[libvirt] [PATCH 2/2] Support IPv6 in port allocator

Ján Tomko jtomko at redhat.com
Thu Oct 31 15:40:11 UTC 2013


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(-)

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);
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown family %d"), family);
+        return -1;
+    }
 
     *used = false;
 
     fd = socket(PF_INET, SOCK_STREAM, 0);
     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) {
-- 
1.8.1.5




More information about the libvir-list mailing list