[libvirt] [PATCH 3/3] util: introduce virSocketAddrParseQuiet

Jim Fehlig posted 3 patches 7 years, 3 months ago
[libvirt] [PATCH 3/3] util: introduce virSocketAddrParseQuiet
Posted by Jim Fehlig 7 years, 3 months ago
When preparing for migration, the libxl driver creates a new TCP listen
socket for the incoming migration by calling virNetSocketNewListenTCP,
passing the destination host name. virNetSocketNewListenTCP calls
virSocketAddrParse to check if the host name is a wildcard address, in
which case it avoids adding the AI_ADDRCONFIG flag to the hints passed to
getaddrinfo. If the host name is not an IP address, virSocketAddrParse
reports an error

error : virSocketAddrParseInternal:121 : Cannot parse socket address
'myhost.example.com': Name or service not known

But virNetSocketNewListenTCP succeeds regardless and the overall migration
operation succeeds.

Introduce virSocketAddrParseQuiet and use it when simply testing if a host
name/addr is parsable.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
---

A brute-force hack that also works is to remove AI_NUMERICHOST flag from
hints in virSocketAddrParseInternal, but I'm not sure what sort of havoc
that would wreak

Perhaps I should ask the obvious question first: Is virSocketAddrParse
expected to work with a host name? I suspec there are other callers that
could pass a name as well as a numeric IP addr, depending on URI provided
by user.

 src/libvirt_private.syms |  1 +
 src/rpc/virnetsocket.c   |  2 +-
 src/util/virsocketaddr.c | 60 +++++++++++++++++++++++++++++++++++-------------
 src/util/virsocketaddr.h |  4 ++++
 4 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index c3e4fd23d..acacbaeb1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2726,6 +2726,7 @@ virSocketAddrNumericFamily;
 virSocketAddrParse;
 virSocketAddrParseIPv4;
 virSocketAddrParseIPv6;
+virSocketAddrParseQuiet;
 virSocketAddrPrefixToNetmask;
 virSocketAddrPTRDomain;
 virSocketAddrSetIPv4Addr;
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index 2d41a716b..07166ecc9 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -333,7 +333,7 @@ int virNetSocketNewListenTCP(const char *nodename,
      * startup in most cases.
      */
     if (nodename &&
-        !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 &&
+        !(virSocketAddrParseQuiet(&tmp_addr, nodename, AF_UNSPEC) > 0 &&
           virSocketAddrIsWildcard(&tmp_addr)))
         hints.ai_flags |= AI_ADDRCONFIG;
 
diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c
index 95b527436..711c634e8 100644
--- a/src/util/virsocketaddr.c
+++ b/src/util/virsocketaddr.c
@@ -126,29 +126,24 @@ virSocketAddrParseInternal(struct addrinfo **res,
     return 0;
 }
 
-/**
- * virSocketAddrParse:
- * @val: a numeric network address IPv4 or IPv6
- * @addr: where to store the return value, optional.
- * @family: address family to pass down to getaddrinfo
- *
- * Mostly a wrapper for getaddrinfo() extracting the address storage
- * from the numeric string like 1.2.3.4 or 2001:db8:85a3:0:0:8a2e:370:7334
- *
- * Returns the length of the network address or -1 in case of error.
- */
-int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
+static int
+virSockAddrParseVerbose(virSocketAddrPtr addr,
+                        const char *val,
+                        int family,
+                        bool verbose)
 {
     int len;
     struct addrinfo *res;
 
-    if (virSocketAddrParseInternal(&res, val, family, true) < 0)
+    if (virSocketAddrParseInternal(&res, val, family, verbose) < 0)
         return -1;
 
     if (res == NULL) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("No socket addresses found for '%s'"),
-                       val);
+        if (verbose) {
+            virReportError(VIR_ERR_SYSTEM_ERROR,
+                           _("No socket addresses found for '%s'"),
+                           val);
+        }
         return -1;
     }
 
@@ -162,6 +157,39 @@ int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
     return len;
 }
 
+
+/**
+ * virSocketAddrParse:
+ * @val: a numeric network address IPv4 or IPv6
+ * @addr: where to store the return value, optional.
+ * @family: address family to pass down to getaddrinfo
+ *
+ * Mostly a wrapper for getaddrinfo() extracting the address storage
+ * from the numeric string like 1.2.3.4 or 2001:db8:85a3:0:0:8a2e:370:7334
+ *
+ * Returns the length of the network address or -1 in case of error.
+ */
+int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
+{
+    return virSockAddrParseVerbose(addr, val, family, true);
+}
+
+/**
+ * virSocketAddrParseQuiet:
+ * @val: a numeric network address IPv4 or IPv6
+ * @addr: where to store the return value, optional.
+ * @family: address family to pass down to getaddrinfo
+ *
+ * A quiet version of virSocketAddrParse. No errors are reported in
+ * error paths.
+ *
+ * Returns the length of the network address or -1 in case of error.
+ */
+int virSocketAddrParseQuiet(virSocketAddrPtr addr, const char *val, int family)
+{
+    return virSockAddrParseVerbose(addr, val, family, false);
+}
+
 /*
  * virSocketAddrParseIPv4:
  * @val: an IPv4 numeric address
diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h
index 80e792618..99bb7a949 100644
--- a/src/util/virsocketaddr.h
+++ b/src/util/virsocketaddr.h
@@ -92,6 +92,10 @@ int virSocketAddrParse(virSocketAddrPtr addr,
                        const char *val,
                        int family);
 
+int virSocketAddrParseQuiet(virSocketAddrPtr addr,
+                            const char *val,
+                            int family);
+
 int virSocketAddrParseIPv4(virSocketAddrPtr addr,
                            const char *val);
 
-- 
2.16.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 3/3] util: introduce virSocketAddrParseQuiet
Posted by John Ferlan 7 years, 3 months ago

On 03/19/2018 07:28 PM, Jim Fehlig wrote:
> When preparing for migration, the libxl driver creates a new TCP listen
> socket for the incoming migration by calling virNetSocketNewListenTCP,
> passing the destination host name. virNetSocketNewListenTCP calls
> virSocketAddrParse to check if the host name is a wildcard address, in
> which case it avoids adding the AI_ADDRCONFIG flag to the hints passed to
> getaddrinfo. If the host name is not an IP address, virSocketAddrParse
> reports an error
> 
> error : virSocketAddrParseInternal:121 : Cannot parse socket address
> 'myhost.example.com': Name or service not known
> 
> But virNetSocketNewListenTCP succeeds regardless and the overall migration
> operation succeeds.
> 
> Introduce virSocketAddrParseQuiet and use it when simply testing if a host
> name/addr is parsable.
> 
> Signed-off-by: Jim Fehlig <jfehlig@suse.com>
> ---
> 
> A brute-force hack that also works is to remove AI_NUMERICHOST flag from
> hints in virSocketAddrParseInternal, but I'm not sure what sort of havoc
> that would wreak

Perhaps rather than quiet/verbose flag - maybe ParseInternal should add
a new parameter "ai_flags"?  Then add virSocketAddrParseName which would
pass 0 instead of AI_NUMERICHOST and expect to parse the name. FWIW, I
have a faint recollection of some issue with getaddrinfo and dns delays
on lookups when looking up by name. Been a while since I've had to think
about that though, so I could be wrong as the memory fades/ages.

You could also search on some other direct callers of getaddrinfo in
libvirt sources - there's some interesting uses..

I also note (ironically) that if @addr == NULL, then error is splatted
in ParseInternal regardless of @reportError value.

> 
> Perhaps I should ask the obvious question first: Is virSocketAddrParse
> expected to work with a host name? I suspec there are other callers that
> could pass a name as well as a numeric IP addr, depending on URI provided
> by user.

Seems to me some comments [1] answer your question.

There's a virSocketAddrNumericFamily - maybe that'll help you in
deciding how to formulate things... Seems to be used by a few places
already to determine whether one has a name or number (including the
qemu migration path).

FWIW: I also note callers to virSocketAddrNumericFamily don't
necessarily handle the possible -1 return possibly...  Looks like you're
jumping into one of rabbit holes Laine usually falls into ;-)

> 
>  src/libvirt_private.syms |  1 +
>  src/rpc/virnetsocket.c   |  2 +-
>  src/util/virsocketaddr.c | 60 +++++++++++++++++++++++++++++++++++-------------
>  src/util/virsocketaddr.h |  4 ++++
>  4 files changed, 50 insertions(+), 17 deletions(-)
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index c3e4fd23d..acacbaeb1 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2726,6 +2726,7 @@ virSocketAddrNumericFamily;
>  virSocketAddrParse;
>  virSocketAddrParseIPv4;
>  virSocketAddrParseIPv6;
> +virSocketAddrParseQuiet;
>  virSocketAddrPrefixToNetmask;
>  virSocketAddrPTRDomain;
>  virSocketAddrSetIPv4Addr;
> diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
> index 2d41a716b..07166ecc9 100644
> --- a/src/rpc/virnetsocket.c
> +++ b/src/rpc/virnetsocket.c
> @@ -333,7 +333,7 @@ int virNetSocketNewListenTCP(const char *nodename,
>       * startup in most cases.
>       */
>      if (nodename &&
> -        !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 &&
> +        !(virSocketAddrParseQuiet(&tmp_addr, nodename, AF_UNSPEC) > 0 &&
>            virSocketAddrIsWildcard(&tmp_addr)))
>          hints.ai_flags |= AI_ADDRCONFIG;
>  
> diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c
> index 95b527436..711c634e8 100644
> --- a/src/util/virsocketaddr.c
> +++ b/src/util/virsocketaddr.c
> @@ -126,29 +126,24 @@ virSocketAddrParseInternal(struct addrinfo **res,
>      return 0;
>  }
>  
> -/**
> - * virSocketAddrParse:
> - * @val: a numeric network address IPv4 or IPv6
> - * @addr: where to store the return value, optional.
> - * @family: address family to pass down to getaddrinfo
> - *
> - * Mostly a wrapper for getaddrinfo() extracting the address storage
> - * from the numeric string like 1.2.3.4 or 2001:db8:85a3:0:0:8a2e:370:7334
> - *

[1]

> - * Returns the length of the network address or -1 in case of error.
> - */
> -int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
> +static int
> +virSockAddrParseVerbose(virSocketAddrPtr addr,
> +                        const char *val,
> +                        int family,
> +                        bool verbose)

Could have gone with reportError like ParseInternal.

John

>  {
>      int len;
>      struct addrinfo *res;
>  
> -    if (virSocketAddrParseInternal(&res, val, family, true) < 0)
> +    if (virSocketAddrParseInternal(&res, val, family, verbose) < 0)
>          return -1;
>  
>      if (res == NULL) {
> -        virReportError(VIR_ERR_SYSTEM_ERROR,
> -                       _("No socket addresses found for '%s'"),
> -                       val);
> +        if (verbose) {
> +            virReportError(VIR_ERR_SYSTEM_ERROR,
> +                           _("No socket addresses found for '%s'"),
> +                           val);
> +        }
>          return -1;
>      }
>  
> @@ -162,6 +157,39 @@ int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
>      return len;
>  }
>  
> +
> +/**
> + * virSocketAddrParse:
> + * @val: a numeric network address IPv4 or IPv6
> + * @addr: where to store the return value, optional.
> + * @family: address family to pass down to getaddrinfo
> + *
> + * Mostly a wrapper for getaddrinfo() extracting the address storage
> + * from the numeric string like 1.2.3.4 or 2001:db8:85a3:0:0:8a2e:370:7334
> + *
> + * Returns the length of the network address or -1 in case of error.
> + */
> +int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family)
> +{
> +    return virSockAddrParseVerbose(addr, val, family, true);
> +}
> +
> +/**
> + * virSocketAddrParseQuiet:
> + * @val: a numeric network address IPv4 or IPv6
> + * @addr: where to store the return value, optional.
> + * @family: address family to pass down to getaddrinfo
> + *
> + * A quiet version of virSocketAddrParse. No errors are reported in
> + * error paths.
> + *
> + * Returns the length of the network address or -1 in case of error.
> + */
> +int virSocketAddrParseQuiet(virSocketAddrPtr addr, const char *val, int family)
> +{
> +    return virSockAddrParseVerbose(addr, val, family, false);
> +}
> +
>  /*
>   * virSocketAddrParseIPv4:
>   * @val: an IPv4 numeric address
> diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h
> index 80e792618..99bb7a949 100644
> --- a/src/util/virsocketaddr.h
> +++ b/src/util/virsocketaddr.h
> @@ -92,6 +92,10 @@ int virSocketAddrParse(virSocketAddrPtr addr,
>                         const char *val,
>                         int family);
>  
> +int virSocketAddrParseQuiet(virSocketAddrPtr addr,
> +                            const char *val,
> +                            int family);
> +
>  int virSocketAddrParseIPv4(virSocketAddrPtr addr,
>                             const char *val);
>  
> 

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list