[libvirt] [PATCH] Don't use AI_ADDRCONFIG when binding to wildcard addresses

https://bugzilla.redhat.com/show_bug.cgi?id=1098659 With parallel boot, network addresses might not yet be assigned [1], but binding to wildcard addresses should work. For non-wildcard addresses, ADDRCONFIG is still used. Document this in libvirtd.conf. [1] http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ --- daemon/libvirtd.conf | 4 ++++ src/rpc/virnetsocket.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf index aeba11d..e5856d4 100644 --- a/daemon/libvirtd.conf +++ b/daemon/libvirtd.conf @@ -48,6 +48,10 @@ # Override the default configuration which binds to all network # interfaces. This can be a numeric IPv4/6 address, or hostname # +# If the libvirtd service is started in parallel with network +# startup (e.g. with systemd), binding to addresses other than +# the wildcards (0.0.0.0/::) might not be available yet. +# #listen_addr = "192.168.0.1" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index a7e1783..87b39f2 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -226,15 +226,29 @@ int virNetSocketNewListenTCP(const char *nodename, struct addrinfo hints; int fd = -1; size_t i; - int addrInUse = false; + bool addrInUse = false; + bool familyNotSupported = false; + virSocketAddr tmp_addr; *retsocks = NULL; *nretsocks = 0; memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; + /* Don't use ADDRCONFIG for binding to the wildcard address. + * Just catch the error returned by socket() if the system has + * no IPv6 support. + * + * This allows libvirtd to be started in parallel with the network + * startup in most cases. + */ + if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG; + int e = getaddrinfo(nodename, service, &hints, &ai); if (e != 0) { virReportError(VIR_ERR_SYSTEM_ERROR, @@ -251,6 +265,11 @@ int virNetSocketNewListenTCP(const char *nodename, if ((fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol)) < 0) { + if (errno == EAFNOSUPPORT) { + familyNotSupported = true; + runp = runp->ai_next; + continue; + } virReportSystemError(errno, "%s", _("Unable to create socket")); goto error; } @@ -307,6 +326,11 @@ int virNetSocketNewListenTCP(const char *nodename, fd = -1; } + if (nsocks == 0 && familyNotSupported) { + virReportSystemError(EAFNOSUPPORT, "%s", _("Unable to bind to port")); + goto error; + } + if (nsocks == 0 && addrInUse) { virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port")); -- 1.8.3.2

On 05/29/2014 03:32 AM, Ján Tomko wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=1098659
With parallel boot, network addresses might not yet be assigned [1], but binding to wildcard addresses should work.
For non-wildcard addresses, ADDRCONFIG is still used. Document this in libvirtd.conf.
[1] http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ ---
- hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM;
+ /* Don't use ADDRCONFIG for binding to the wildcard address. + * Just catch the error returned by socket() if the system has + * no IPv6 support. + * + * This allows libvirtd to be started in parallel with the network + * startup in most cases. + */ + if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG;
Shouldn't this be |= ? Otherwise, it makes sense to me. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 05/29/2014 04:47 PM, Eric Blake wrote:
On 05/29/2014 03:32 AM, Ján Tomko wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=1098659
With parallel boot, network addresses might not yet be assigned [1], but binding to wildcard addresses should work.
For non-wildcard addresses, ADDRCONFIG is still used. Document this in libvirtd.conf.
[1] http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ ---
- hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM;
+ /* Don't use ADDRCONFIG for binding to the wildcard address. + * Just catch the error returned by socket() if the system has + * no IPv6 support. + * + * This allows libvirtd to be started in parallel with the network + * startup in most cases. + */ + if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG;
Shouldn't this be |= ?
Functionally it's the same, AI_PASSIVE is ignored if nodename is non-NULL. But it should be |= if we were using other flags. Jan

On 05/30/2014 12:21 AM, Ján Tomko wrote:
+ if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG;
Shouldn't this be |= ?
Functionally it's the same, AI_PASSIVE is ignored if nodename is non-NULL.
But it should be |= if we were using other flags.
Okay. ACK to the patch, and safe to include in 1.2.5. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 05/30/2014 09:36 PM, Eric Blake wrote:
On 05/30/2014 12:21 AM, Ján Tomko wrote:
+ if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG;
Shouldn't this be |= ?
Functionally it's the same, AI_PASSIVE is ignored if nodename is non-NULL.
But it should be |= if we were using other flags.
Okay. ACK to the patch, and safe to include in 1.2.5.
Pushed with the |= change, although it's too late for 1.2.5 now. Thanks for the review. Jan

On Fri, May 30, 2014 at 08:21:40AM +0200, Ján Tomko wrote:
On 05/29/2014 04:47 PM, Eric Blake wrote:
On 05/29/2014 03:32 AM, Ján Tomko wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=1098659
With parallel boot, network addresses might not yet be assigned [1], but binding to wildcard addresses should work.
For non-wildcard addresses, ADDRCONFIG is still used. Document this in libvirtd.conf.
[1] http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ ---
- hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM;
+ /* Don't use ADDRCONFIG for binding to the wildcard address. + * Just catch the error returned by socket() if the system has + * no IPv6 support. + * + * This allows libvirtd to be started in parallel with the network + * startup in most cases. + */ + if (nodename && + !(virSocketAddrParse(&tmp_addr, nodename, AF_UNSPEC) > 0 && + virSocketAddrIsWildcard(&tmp_addr))) + hints.ai_flags = AI_ADDRCONFIG;
Shouldn't this be |= ?
Functionally it's the same, AI_PASSIVE is ignored if nodename is non-NULL.
But it should be |= if we were using other flags.
Please make it '|=' regardless. Using '=' is setting a nasty trap-door for a future change which adds some other flags where use of '|=' will be needed. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Ján Tomko