[libvirt] [PATCH 2/2] Support IPv6 in port allocator
Daniel P. Berrange
berrange at redhat.com
Thu Oct 31 17:33:49 UTC 2013
On Thu, Oct 31, 2013 at 04:40:11PM +0100, Ján Tomko wrote:
> Also try to bind on IPv6 to check if the port is occupied.
>
> https://bugzilla.redhat.com/show_bug.cgi?id=1025407
> ---
> src/util/virportallocator.c | 45 ++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 38 insertions(+), 7 deletions(-)
Have you tested this on a system where the IPv6 kernel module is
not present, and on a system with IPv6 kmod is present, but no
interfaces have any IPv6 addresses (not even link-local ones).
I'm concerned this is going to trigger failures on IPv4 only
hosts.
> diff --git a/src/util/virportallocator.c b/src/util/virportallocator.c
> index 1922ea6..24b4bff 100644
> --- a/src/util/virportallocator.c
> +++ b/src/util/virportallocator.c
> @@ -99,21 +99,45 @@ virPortAllocatorPtr virPortAllocatorNew(const char *name,
> }
>
> static int virPortAllocatorBindToPort(bool *used,
> - unsigned short port)
> + unsigned short port,
> + int family)
> {
> - struct sockaddr_in addr = {
> + struct sockaddr_in6 addr6 = {
> + .sin6_family = AF_INET6,
> + .sin6_port = htons(port),
> + .sin6_addr = IN6ADDR_ANY_INIT,
> + };
> + struct sockaddr_in addr4 = {
> .sin_family = AF_INET,
> .sin_port = htons(port),
> .sin_addr.s_addr = htonl(INADDR_ANY)
> };
> + struct sockaddr* addr;
> + size_t addrlen;
> + int v6only = 1;
> int reuse = 1;
> int ret = -1;
> int fd = -1;
> + bool ipv6 = false;
> +
> + if (family == AF_INET6) {
> + addr = (struct sockaddr*)&addr6;
> + addrlen = sizeof(addr6);
> + ipv6 = true;
> + } else if (family == AF_INET) {
> + addr = (struct sockaddr*)&addr4;
> + addrlen = sizeof(addr4);
family can be AF_INET or AF_INET6 here...
> + } else {
> + virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown family %d"), family);
> + return -1;
> + }
>
> *used = false;
>
> fd = socket(PF_INET, SOCK_STREAM, 0);
...but you're hardcoding PF_INET here. I'm not sure it is valid
to use an PF_INET socket with an AF_INET6 address in bind().
> if (fd < 0) {
> + if (errno == EAFNOSUPPORT)
> + return 0;
> virReportSystemError(errno, "%s", _("Unable to open test socket"));
> goto cleanup;
> }
> @@ -125,7 +149,14 @@ static int virPortAllocatorBindToPort(bool *used,
> goto cleanup;
> }
>
> - if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
> + if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only,
> + sizeof(v6only)) < 0) {
> + virReportSystemError(errno, "%s",
> + _("Unable to set IPV6_V6ONLY flag"));
> + goto cleanup;
> + }
> +
> + if (bind(fd, addr, addrlen) < 0) {
> if (errno == EADDRINUSE) {
> *used = true;
> ret = 0;
> @@ -151,7 +182,7 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
> virObjectLock(pa);
>
> for (i = pa->start; i <= pa->end && !*port; i++) {
> - bool used = false;
> + bool used = false, v6used = false;
>
> if (virBitmapGetBit(pa->bitmap,
> i - pa->start, &used) < 0) {
> @@ -163,10 +194,10 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
> if (used)
> continue;
>
> - if (virPortAllocatorBindToPort(&used, i) < 0)
> + if (virPortAllocatorBindToPort(&v6used, i, AF_INET6) < 0 ||
> + virPortAllocatorBindToPort(&used, i, AF_INET) < 0)
> goto cleanup;
> -
> - if (!used) {
> + if (!used && !v6used) {
> /* Add port to bitmap of reserved ports */
> if (virBitmapSetBit(pa->bitmap,
> i - pa->start) < 0) {
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 :|
More information about the libvir-list
mailing list