diff mbox

[ovs-dev] Change TCP connections to support DNS names

Message ID 1457983533-13440-1-git-send-email-rmoats@us.ibm.com
State Changes Requested
Headers show

Commit Message

Ryan Moats March 14, 2016, 7:25 p.m. UTC
From: RYAN D. MOATS <rmoats@us.ibm.com>

Allow TCP connection strings to also use DNS names in
addition to IPv4 and IPv6 addresses. Updated test case
"ovsdb-client get-schema-version - tcp socket" to
verify.

Signed-off-by: RYAN D. MOATS <rmoats@us.ibm.com>
---
 lib/stream-tcp.c      |   66 +++++++++++++++++++++++++++++++++++++++++++++---
 tests/ovsdb-server.at |    2 +
 2 files changed, 63 insertions(+), 5 deletions(-)

Comments

Ben Pfaff March 23, 2016, 1:05 a.m. UTC | #1
On Mon, Mar 14, 2016 at 02:25:33PM -0500, Ryan Moats wrote:
> From: RYAN D. MOATS <rmoats@us.ibm.com>
> 
> Allow TCP connection strings to also use DNS names in
> addition to IPv4 and IPv6 addresses. Updated test case
> "ovsdb-client get-schema-version - tcp socket" to
> verify.
> 
> Signed-off-by: RYAN D. MOATS <rmoats@us.ibm.com>

This would be nice but it can't be this simple.

The first reason is because OVS consists of daemons that run in a
polling loop.  Resolving DNS names can take seconds.  We can't afford to
pause everything in the main loop for that long.  This could be fixed by
either spawning a thread for name resolution or by using an asynchronous
name resolution library.

Second, we've historically not even bothered with name resolution for
ovs-vswitchd because of in-band control issues.  Basically, that means
that ovs-vswitchd needs to connect to the OpenFlow controller before it
knows much about the network structure, including about how to reach the
name server, and there's a sort of chicken-and-egg problem.  This only
applies to ovs-vswitchd and specifically when in-band control is in use
though.

So, basically, I support this, but it needs to be more sophisticated.

Thanks,

Ben.
diff mbox

Patch

diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c
index fc5a606..483ff77 100644
--- a/lib/stream-tcp.c
+++ b/lib/stream-tcp.c
@@ -15,6 +15,7 @@ 
  */
 
 #include <config.h>
+#include <ctype.h>
 #include "stream.h"
 #include <errno.h>
 #include <inttypes.h>
@@ -48,17 +49,72 @@  new_tcp_stream(const char *name, int fd, int connect_status,
     return new_fd_stream(name, fd, connect_status, AF_INET, streamp);
 }
 
+static bool
+is_name_dns(char *suffix)
+{
+    char *c = suffix;
+    if (*c == '[') {
+        return false;
+    }
+    while (*c && *c != ':') {
+        if (isalpha(*c) || *c == '-') {
+            return true;
+        }
+        c++;
+    }
+    return false;
+}
+
 static int
 tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
 {
     int fd, error;
 
-    error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp);
-    if (fd >= 0) {
-        return new_tcp_stream(name, fd, error, streamp);
-    } else {
-        VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
+    /* if suffix begins with a domain name, rather than either an IPv4
+     * or IPv6 address, then make a call to getaddrinfo to get the IP
+     * addresses for this call.  we'll loop through trying to connect
+     * to each one and fail if we get through all of them without a
+     * successful connection. */
+    if (is_name_dns(suffix)) {
+        char *c = strchr(suffix, ':');
+        *c = 0;
+        struct addrinfo hints;
+        struct addrinfo *servinfo, *p;
+        memset(&hints, 0, sizeof hints);
+        hints.ai_family = AF_INET; //TODO: make this work with IPv6
+        hints.ai_socktype = SOCK_STREAM;
+        int status = getaddrinfo(suffix, c+1, &hints, &servinfo);
+        *c = ':';
+        if (status != 0) {
+            VLOG_ERR("%s: getaddrinfo: %s", name, ovs_strerror(status));
+            return status;
+        }
+        for (p = servinfo; p != NULL; p = p->ai_next) {
+            char ipv4str[15];
+            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
+            void *addr = &(ipv4->sin_addr);
+            inet_ntop(p->ai_family, addr, ipv4str, sizeof ipv4str);
+            char *new_suffix = xasprintf("%s:%s", ipv4str, c+1);
+            error = inet_open_active(SOCK_STREAM, new_suffix, 0, NULL, &fd,
+                                     dscp);
+            free(new_suffix);
+            if (fd >= 0) {
+                freeaddrinfo(servinfo);
+                return new_tcp_stream(name, fd, error, streamp);
+            }
+        }
+        freeaddrinfo(servinfo);
+        VLOG_ERR("%s: can not connect, last error: %s", name,
+                 ovs_strerror(error));
         return error;
+    } else {
+        error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp);
+        if (fd >= 0) {
+            return new_tcp_stream(name, fd, error, streamp);
+        } else {
+            VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
+            return error;
+        }
     }
 }
 
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index c869d6f..44c93b8 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -854,6 +854,8 @@  AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --un
 PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
 AT_CHECK([ovsdb-client get-schema-version tcp:127.0.0.1:$TCP_PORT ordinals], [0], [5.1.3
 ])
+AT_CHECK([ovsdb-client get-schema-version tcp:localhost:$TCP_PORT ordinals], [0], [5.1.3
+])
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP])