Add IPv6 support for OpenFlow, OVSDB, NetFlow, and sFlow.
authorArun Sharma <arun.sharma@calsoftinc.com>
Fri, 7 Feb 2014 00:04:05 +0000 (16:04 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 7 Feb 2014 00:08:34 +0000 (16:08 -0800)
Does not add IPv6 support for in-band control.

Co-authored-by: Ben Pfaff <blp@nicira.com>
Signed-off-by: Nandan Nivgune <nandan.nivgune@calsoftinc.com>
Signed-off-by: Abhijit Bhopatkar <abhijit.bhopatkar@calsoftinc.com>
Signed-off-by: Arun Sharma <arun.sharma@calsoftinc.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
26 files changed:
NEWS
include/sparse/netinet/in.h
lib/socket-util.c
lib/socket-util.h
lib/stream-fd.c
lib/stream-fd.h
lib/stream-ssl.c
lib/stream-tcp.c
lib/stream-unix.c
lib/stream.c
lib/stream.h
lib/vconn-active.man
lib/vconn-passive.man
ofproto/connmgr.c
ofproto/ofproto-dpif-sflow.c
ovsdb/remote-active.man
ovsdb/remote-passive.man
python/ovs/socket_util.py
tests/ofproto-dpif.at
tests/ofproto-macros.at
tests/ovsdb-execution.at
tests/ovsdb-idl.at
tests/ovsdb-server.at
tests/test-sflow.c
vswitchd/bridge.c
vswitchd/vswitch.xml

diff --git a/NEWS b/NEWS
index 8689f5c..fe4b8cf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -64,6 +64,7 @@ v2.1.0 - xx xxx xxxx
      hard limit on the number of flows in the datapath.  It defaults to 200,000
      flows.  OVS automatically adjusts this number depending on network
      conditions.
      hard limit on the number of flows in the datapath.  It defaults to 200,000
      flows.  OVS automatically adjusts this number depending on network
      conditions.
+   - Added IPv6 support for active and passive socket communications.
 
 
 v2.0.0 - 15 Oct 2013
 
 
 v2.0.0 - 15 Oct 2013
index 781358b..a220428 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2011, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,15 @@ struct in6_addr {
 
 extern const struct in6_addr in6addr_any;
 
 
 extern const struct in6_addr in6addr_any;
 
+/* Ditto, for IPv6.  */
+struct sockaddr_in6 {
+    sa_family_t sin6_family;
+    in_port_t sin6_port;        /* Transport layer port # */
+    uint32_t sin6_flowinfo;     /* IPv6 flow information */
+    struct in6_addr sin6_addr;  /* IPv6 address */
+    uint32_t sin6_scope_id;     /* IPv6 scope-id */
+};
+
 #define IPPROTO_IP 0
 #define IPPROTO_HOPOPTS 0
 #define IPPROTO_ICMP 1
 #define IPPROTO_IP 0
 #define IPPROTO_HOPOPTS 0
 #define IPPROTO_ICMP 1
@@ -84,6 +93,7 @@ extern const struct in6_addr in6addr_any;
 
 #define INADDR_ANY              0x00000000
 #define INADDR_BROADCAST        0xffffffff
 
 #define INADDR_ANY              0x00000000
 #define INADDR_BROADCAST        0xffffffff
+#define INADDR_LOOPBACK         0x7f000001
 #define INADDR_NONE             0xffffffff
 
 #define INET6_ADDRSTRLEN 46
 #define INADDR_NONE             0xffffffff
 
 #define INET6_ADDRSTRLEN 46
index 24fc6fe..f5d3137 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -612,59 +612,125 @@ guess_netmask(ovs_be32 ip_)
             : htonl(0));                          /* ??? */
 }
 
             : htonl(0));                          /* ??? */
 }
 
-/* Parses 'target', which should be a string in the format "<host>[:<port>]".
- * <host> is required.  If 'default_port' is nonzero then <port> is optional
- * and defaults to 'default_port'.
+/* This is like strsep() except:
  *
  *
- * On success, returns true and stores the parsed remote address into '*sinp'.
- * On failure, logs an error, stores zeros into '*sinp', and returns false. */
-bool
-inet_parse_active(const char *target_, uint16_t default_port,
-                  struct sockaddr_in *sinp)
+ *    - The separator string is ":".
+ *
+ *    - Square brackets [] quote ":" separators and are removed from the
+ *      tokens. */
+static char *
+parse_bracketed_token(char **pp)
 {
 {
-    char *target = xstrdup(target_);
-    char *save_ptr = NULL;
-    const char *host_name;
-    const char *port_string;
-    bool ok = false;
-
-    /* Defaults. */
-    sinp->sin_family = AF_INET;
-    sinp->sin_port = htons(default_port);
-
-    /* Tokenize. */
-    host_name = strtok_r(target, ":", &save_ptr);
-    port_string = strtok_r(NULL, ":", &save_ptr);
-    if (!host_name) {
-        VLOG_ERR("%s: bad peer name format", target_);
-        goto exit;
+    char *p = *pp;
+
+    if (p == NULL) {
+        return NULL;
+    } else if (*p == '\0') {
+        *pp = NULL;
+        return p;
+    } else if (*p == '[') {
+        char *start = p + 1;
+        char *end = start + strcspn(start, "]");
+        *pp = (*end == '\0' ? NULL
+               : end[1] == ':' ? end + 2
+               : end + 1);
+        *end = '\0';
+        return start;
+    } else {
+        char *start = p;
+        char *end = start + strcspn(start, ":");
+        *pp = *end == '\0' ? NULL : end + 1;
+        *end = '\0';
+        return start;
     }
     }
+}
 
 
-    /* Look up IP, port. */
-    if (lookup_ip(host_name, &sinp->sin_addr)) {
-        goto exit;
+static bool
+parse_sockaddr_components(struct sockaddr_storage *ss,
+                          const char *host_s,
+                          const char *port_s, uint16_t default_port,
+                          const char *s)
+{
+    struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *, ss);
+    int port;
+
+    if (port_s && port_s[0]) {
+        if (!str_to_int(port_s, 10, &port) || port < 0 || port > 65535) {
+            VLOG_ERR("%s: bad port number \"%s\"", s, port_s);
+        }
+    } else {
+        port = default_port;
     }
     }
-    if (port_string && atoi(port_string)) {
-        sinp->sin_port = htons(atoi(port_string));
-    } else if (!default_port) {
-        VLOG_ERR("%s: port number must be specified", target_);
-        goto exit;
+
+    memset(ss, 0, sizeof *ss);
+    if (strchr(host_s, ':')) {
+        struct sockaddr_in6 *sin6
+            = ALIGNED_CAST(struct sockaddr_in6 *, ss);
+
+        sin6->sin6_family = AF_INET6;
+        sin6->sin6_port = htons(port);
+        if (!inet_pton(AF_INET6, host_s, sin6->sin6_addr.s6_addr)) {
+            VLOG_ERR("%s: bad IPv6 address \"%s\"", s, host_s);
+            goto exit;
+        }
+    } else {
+        sin->sin_family = AF_INET;
+        sin->sin_port = htons(port);
+        if (!inet_pton(AF_INET, host_s, &sin->sin_addr.s_addr)) {
+            VLOG_ERR("%s: bad IPv4 address \"%s\"", s, host_s);
+            goto exit;
+        }
     }
 
     }
 
-    ok = true;
+    return true;
 
 exit:
 
 exit:
+    memset(ss, 0, sizeof *ss);
+    return false;
+}
+
+/* Parses 'target', which should be a string in the format "<host>[:<port>]".
+ * <host>, which is required, may be an IPv4 address or an IPv6 address
+ * enclosed in square brackets.  If 'default_port' is nonzero then <port> is
+ * optional and defaults to 'default_port'.
+ *
+ * On success, returns true and stores the parsed remote address into '*ss'.
+ * On failure, logs an error, stores zeros into '*ss', and returns false. */
+bool
+inet_parse_active(const char *target_, uint16_t default_port,
+                  struct sockaddr_storage *ss)
+{
+    char *target = xstrdup(target_);
+    const char *port;
+    const char *host;
+    char *p;
+    bool ok;
+
+    p = target;
+    host = parse_bracketed_token(&p);
+    port = parse_bracketed_token(&p);
+    if (!host) {
+        VLOG_ERR("%s: host must be specified", target_);
+        ok = false;
+    } else if (!port && !default_port) {
+        VLOG_ERR("%s: port must be specified", target_);
+        ok = false;
+    } else {
+        ok = parse_sockaddr_components(ss, host, port, default_port, target_);
+    }
     if (!ok) {
     if (!ok) {
-        memset(sinp, 0, sizeof *sinp);
+        memset(ss, 0, sizeof *ss);
     }
     free(target);
     return ok;
 }
 
     }
     free(target);
     return ok;
 }
 
-/* Opens a non-blocking IPv4 socket of the specified 'style' and connects to
- * 'target', which should be a string in the format "<host>[:<port>]".  <host>
- * is required.  If 'default_port' is nonzero then <port> is optional and
- * defaults to 'default_port'.
+
+/* Opens a non-blocking IPv4 or IPv6 socket of the specified 'style' and
+ * connects to 'target', which should be a string in the format
+ * "<host>[:<port>]".  <host>, which is required, may be an IPv4 address or an
+ * IPv6 address enclosed in square brackets.  If 'default_port' is nonzero then
+ * <port> is optional and defaults to 'default_port'.
  *
  * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP).
  *
  *
  * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP).
  *
@@ -673,28 +739,27 @@ exit:
  * into '*fdp'.  On failure, returns a positive errno value other than EAGAIN
  * and stores -1 into '*fdp'.
  *
  * into '*fdp'.  On failure, returns a positive errno value other than EAGAIN
  * and stores -1 into '*fdp'.
  *
- * If 'sinp' is non-null, then on success the target address is stored into
- * '*sinp'.
+ * If 'ss' is non-null, then on success stores the target address into '*ss'.
  *
  * 'dscp' becomes the DSCP bits in the IP headers for the new connection.  It
  * should be in the range [0, 63] and will automatically be shifted to the
  * appropriately place in the IP tos field. */
 int
 inet_open_active(int style, const char *target, uint16_t default_port,
  *
  * 'dscp' becomes the DSCP bits in the IP headers for the new connection.  It
  * should be in the range [0, 63] and will automatically be shifted to the
  * appropriately place in the IP tos field. */
 int
 inet_open_active(int style, const char *target, uint16_t default_port,
-                 struct sockaddr_in *sinp, int *fdp, uint8_t dscp)
+                 struct sockaddr_storage *ssp, int *fdp, uint8_t dscp)
 {
 {
-    struct sockaddr_in sin;
+    struct sockaddr_storage ss;
     int fd = -1;
     int error;
 
     /* Parse. */
     int fd = -1;
     int error;
 
     /* Parse. */
-    if (!inet_parse_active(target, default_port, &sin)) {
+    if (!inet_parse_active(target, default_port, &ss)) {
         error = EAFNOSUPPORT;
         goto exit;
     }
 
     /* Create non-blocking socket. */
         error = EAFNOSUPPORT;
         goto exit;
     }
 
     /* Create non-blocking socket. */
-    fd = socket(AF_INET, style, 0);
+    fd = socket(ss.ss_family, style, 0);
     if (fd < 0) {
         VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
         error = errno;
     if (fd < 0) {
         VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
         error = errno;
@@ -705,8 +770,8 @@ inet_open_active(int style, const char *target, uint16_t default_port,
         goto exit;
     }
 
         goto exit;
     }
 
-    /* The dscp bits must be configured before connect() to ensure that the TOS
-     * field is set during the connection establishment.  If set after
+    /* The dscp bits must be configured before connect() to ensure that the
+     * TOS field is set during the connection establishment.  If set after
      * connect(), the handshake SYN frames will be sent with a TOS of 0. */
     error = set_dscp(fd, dscp);
     if (error) {
      * connect(), the handshake SYN frames will be sent with a TOS of 0. */
     error = set_dscp(fd, dscp);
     if (error) {
@@ -715,25 +780,32 @@ inet_open_active(int style, const char *target, uint16_t default_port,
     }
 
     /* Connect. */
     }
 
     /* Connect. */
-    error = connect(fd, (struct sockaddr *) &sin, sizeof sin) == 0 ? 0 : errno;
+    error = connect(fd, (struct sockaddr *) &ss, ss_length(&ss)) == 0
+                    ? 0
+                    : errno;
     if (error == EINPROGRESS) {
         error = EAGAIN;
     }
 
 exit:
     if (error == EINPROGRESS) {
         error = EAGAIN;
     }
 
 exit:
-    if (!error || error == EAGAIN) {
-        if (sinp) {
-            *sinp = sin;
+    if (error && error != EAGAIN) {
+        if (ssp) {
+            memset(ssp, 0, sizeof *ssp);
+        }
+        if (fd >= 0) {
+            close(fd);
+            fd = -1;
+        }
+    } else {
+        if (ssp) {
+            *ssp = ss;
         }
         }
-    } else if (fd >= 0) {
-        close(fd);
-        fd = -1;
     }
     *fdp = fd;
     return error;
 }
 
     }
     *fdp = fd;
     return error;
 }
 
-/* Parses 'target', which should be a string in the format "[<port>][:<ip>]":
+/* Parses 'target', which should be a string in the format "[<port>][:<host>]":
  *
  *      - If 'default_port' is -1, then <port> is required.  Otherwise, if
  *        <port> is omitted, then 'default_port' is used instead.
  *
  *      - If 'default_port' is -1, then <port> is required.  Otherwise, if
  *        <port> is omitted, then 'default_port' is used instead.
@@ -741,54 +813,41 @@ exit:
  *      - If <port> (or 'default_port', if used) is 0, then no port is bound
  *        and the TCP/IP stack will select a port.
  *
  *      - If <port> (or 'default_port', if used) is 0, then no port is bound
  *        and the TCP/IP stack will select a port.
  *
- *      - If <ip> is omitted then the IP address is wildcarded.
+ *      - <host> is optional.  If supplied, it may be an IPv4 address or an
+ *        IPv6 address enclosed in square brackets.  If omitted, the IP address
+ *        is wildcarded.
  *
  *
- * If successful, stores the address into '*sinp' and returns true; otherwise
- * zeros '*sinp' and returns false. */
+ * If successful, stores the address into '*ss' and returns true; otherwise
+ * zeros '*ss' and returns false. */
 bool
 inet_parse_passive(const char *target_, int default_port,
 bool
 inet_parse_passive(const char *target_, int default_port,
-                   struct sockaddr_in *sinp)
+                   struct sockaddr_storage *ss)
 {
     char *target = xstrdup(target_);
 {
     char *target = xstrdup(target_);
-    char *string_ptr = target;
-    const char *host_name;
-    const char *port_string;
-    bool ok = false;
-    int port;
-
-    /* Address defaults. */
-    memset(sinp, 0, sizeof *sinp);
-    sinp->sin_family = AF_INET;
-    sinp->sin_addr.s_addr = htonl(INADDR_ANY);
-    sinp->sin_port = htons(default_port);
-
-    /* Parse optional port number. */
-    port_string = strsep(&string_ptr, ":");
-    if (port_string && str_to_int(port_string, 10, &port)) {
-        sinp->sin_port = htons(port);
-    } else if (default_port < 0) {
-        VLOG_ERR("%s: port number must be specified", target_);
-        goto exit;
-    }
-
-    /* Parse optional bind IP. */
-    host_name = strsep(&string_ptr, ":");
-    if (host_name && host_name[0] && lookup_ip(host_name, &sinp->sin_addr)) {
-        goto exit;
+    const char *port;
+    const char *host;
+    char *p;
+    bool ok;
+
+    p = target;
+    port = parse_bracketed_token(&p);
+    host = parse_bracketed_token(&p);
+    if (!port && default_port < 0) {
+        VLOG_ERR("%s: port must be specified", target_);
+        ok = false;
+    } else {
+        ok = parse_sockaddr_components(ss, host ? host : "0.0.0.0",
+                                       port, default_port, target_);
     }
     }
-
-    ok = true;
-
-exit:
     if (!ok) {
     if (!ok) {
-        memset(sinp, 0, sizeof *sinp);
+        memset(ss, 0, sizeof *ss);
     }
     free(target);
     return ok;
 }
 
 
     }
     free(target);
     return ok;
 }
 
 
-/* Opens a non-blocking IPv4 socket of the specified 'style', binds to
+/* Opens a non-blocking IPv4 or IPv6 socket of the specified 'style', binds to
  * 'target', and listens for incoming connections.  Parses 'target' in the same
  * way was inet_parse_passive().
  *
  * 'target', and listens for incoming connections.  Parses 'target' in the same
  * way was inet_parse_passive().
  *
@@ -799,27 +858,27 @@ exit:
  * On success, returns a non-negative file descriptor.  On failure, returns a
  * negative errno value.
  *
  * On success, returns a non-negative file descriptor.  On failure, returns a
  * negative errno value.
  *
- * If 'sinp' is non-null, then on success the bound address is stored into
- * '*sinp'.
+ * If 'ss' is non-null, then on success stores the bound address into '*ss'.
  *
  * 'dscp' becomes the DSCP bits in the IP headers for the new connection.  It
  * should be in the range [0, 63] and will automatically be shifted to the
  * appropriately place in the IP tos field. */
 int
 inet_open_passive(int style, const char *target, int default_port,
  *
  * 'dscp' becomes the DSCP bits in the IP headers for the new connection.  It
  * should be in the range [0, 63] and will automatically be shifted to the
  * appropriately place in the IP tos field. */
 int
 inet_open_passive(int style, const char *target, int default_port,
-                  struct sockaddr_in *sinp, uint8_t dscp)
+                  struct sockaddr_storage *ssp, uint8_t dscp)
 {
     bool kernel_chooses_port;
 {
     bool kernel_chooses_port;
-    struct sockaddr_in sin;
+    struct sockaddr_storage ss;
     int fd = 0, error;
     unsigned int yes = 1;
 
     int fd = 0, error;
     unsigned int yes = 1;
 
-    if (!inet_parse_passive(target, default_port, &sin)) {
+    if (!inet_parse_passive(target, default_port, &ss)) {
         return -EAFNOSUPPORT;
     }
         return -EAFNOSUPPORT;
     }
+    kernel_chooses_port = ss_get_port(&ss) == 0;
 
     /* Create non-blocking socket, set SO_REUSEADDR. */
 
     /* Create non-blocking socket, set SO_REUSEADDR. */
-    fd = socket(AF_INET, style, 0);
+    fd = socket(ss.ss_family, style, 0);
     if (fd < 0) {
         error = errno;
         VLOG_ERR("%s: socket: %s", target, ovs_strerror(error));
     if (fd < 0) {
         error = errno;
         VLOG_ERR("%s: socket: %s", target, ovs_strerror(error));
@@ -838,7 +897,7 @@ inet_open_passive(int style, const char *target, int default_port,
     }
 
     /* Bind. */
     }
 
     /* Bind. */
-    if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
+    if (bind(fd, (struct sockaddr *) &ss, ss_length(&ss)) < 0) {
         error = errno;
         VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
         goto error;
         error = errno;
         VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
         goto error;
@@ -860,31 +919,28 @@ inet_open_passive(int style, const char *target, int default_port,
         goto error;
     }
 
         goto error;
     }
 
-    kernel_chooses_port = sin.sin_port == htons(0);
-    if (sinp || kernel_chooses_port) {
-        socklen_t sin_len = sizeof sin;
-        if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
+    if (ssp || kernel_chooses_port) {
+        socklen_t ss_len = sizeof ss;
+        if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) < 0) {
             error = errno;
             VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error));
             goto error;
         }
             error = errno;
             VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error));
             goto error;
         }
-        if (sin.sin_family != AF_INET || sin_len != sizeof sin) {
-            error = EAFNOSUPPORT;
-            VLOG_ERR("%s: getsockname: invalid socket name", target);
-            goto error;
-        }
-        if (sinp) {
-            *sinp = sin;
-        }
         if (kernel_chooses_port) {
             VLOG_INFO("%s: listening on port %"PRIu16,
         if (kernel_chooses_port) {
             VLOG_INFO("%s: listening on port %"PRIu16,
-                      target, ntohs(sin.sin_port));
+                      target, ss_get_port(&ss));
+        }
+        if (ssp) {
+            *ssp = ss;
         }
     }
 
     return fd;
 
 error:
         }
     }
 
     return fd;
 
 error:
+    if (ssp) {
+        memset(ssp, 0, sizeof *ssp);
+    }
     close(fd);
     return -error;
 }
     close(fd);
     return -error;
 }
@@ -1060,12 +1116,12 @@ describe_sockaddr(struct ds *string, int fd,
     socklen_t len = sizeof ss;
 
     if (!getaddr(fd, (struct sockaddr *) &ss, &len)) {
     socklen_t len = sizeof ss;
 
     if (!getaddr(fd, (struct sockaddr *) &ss, &len)) {
-        if (ss.ss_family == AF_INET) {
-            struct sockaddr_in sin;
+        if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
+            char addrbuf[SS_NTOP_BUFSIZE];
 
 
-            memcpy(&sin, &ss, sizeof sin);
-            ds_put_format(string, IP_FMT":%"PRIu16,
-                          IP_ARGS(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+            ds_put_format(string, "%s:%"PRIu16,
+                          ss_format_address(&ss, addrbuf, sizeof addrbuf),
+                          ss_get_port(&ss));
         } else if (ss.ss_family == AF_UNIX) {
             struct sockaddr_un sun;
             const char *null;
         } else if (ss.ss_family == AF_UNIX) {
             struct sockaddr_un sun;
             const char *null;
@@ -1225,4 +1281,66 @@ af_inet_ifreq_ioctl(const char *name, struct ifreq *ifr, unsigned long int cmd,
     }
     return error;
 }
     }
     return error;
 }
+\f
+/* sockaddr_storage helpers. */
 
 
+/* Returns the IPv4 or IPv6 port in 'ss'. */
+uint16_t
+ss_get_port(const struct sockaddr_storage *ss)
+{
+    if (ss->ss_family == AF_INET) {
+        const struct sockaddr_in *sin
+            = ALIGNED_CAST(const struct sockaddr_in *, ss);
+        return ntohs(sin->sin_port);
+    } else if (ss->ss_family == AF_INET6) {
+        const struct sockaddr_in6 *sin6
+            = ALIGNED_CAST(const struct sockaddr_in6 *, ss);
+        return ntohs(sin6->sin6_port);
+    } else {
+        OVS_NOT_REACHED();
+    }
+}
+
+/* Formats the IPv4 or IPv6 address in 'ss' into the 'bufsize' bytes in 'buf'.
+ * If 'ss' is an IPv6 address, puts square brackets around the address.
+ * 'bufsize' should be at least SS_NTOP_BUFSIZE.
+ *
+ * Returns 'buf'. */
+char *
+ss_format_address(const struct sockaddr_storage *ss,
+                  char *buf, size_t bufsize)
+{
+    ovs_assert(bufsize >= SS_NTOP_BUFSIZE);
+    if (ss->ss_family == AF_INET) {
+        const struct sockaddr_in *sin
+            = ALIGNED_CAST(const struct sockaddr_in *, ss);
+
+        snprintf(buf, bufsize, IP_FMT, IP_ARGS(sin->sin_addr.s_addr));
+    } else if (ss->ss_family == AF_INET6) {
+        const struct sockaddr_in6 *sin6
+            = ALIGNED_CAST(const struct sockaddr_in6 *, ss);
+
+        buf[0] = '[';
+        inet_ntop(AF_INET6, sin6->sin6_addr.s6_addr, buf + 1, bufsize - 1);
+        strcpy(strchr(buf, '\0'), "]");
+    } else {
+        OVS_NOT_REACHED();
+    }
+
+    return buf;
+}
+
+size_t
+ss_length(const struct sockaddr_storage *ss)
+{
+    switch (ss->ss_family) {
+    case AF_INET:
+        return sizeof(struct sockaddr_in);
+
+    case AF_INET6:
+        return sizeof(struct sockaddr_in6);
+
+    default:
+        OVS_NOT_REACHED();
+    }
+}
index d5b44b0..b54d1a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,14 +48,14 @@ ovs_be32 guess_netmask(ovs_be32 ip);
 int get_null_fd(void);
 
 bool inet_parse_active(const char *target, uint16_t default_port,
 int get_null_fd(void);
 
 bool inet_parse_active(const char *target, uint16_t default_port,
-                       struct sockaddr_in *sinp);
+                       struct sockaddr_storage *ssp);
 int inet_open_active(int style, const char *target, uint16_t default_port,
 int inet_open_active(int style, const char *target, uint16_t default_port,
-                    struct sockaddr_in *sinp, int *fdp, uint8_t dscp);
+                     struct sockaddr_storage *ssp, int *fdp, uint8_t dscp);
 
 bool inet_parse_passive(const char *target, int default_port,
 
 bool inet_parse_passive(const char *target, int default_port,
-                        struct sockaddr_in *sinp);
+                        struct sockaddr_storage *ssp);
 int inet_open_passive(int style, const char *target, int default_port,
 int inet_open_passive(int style, const char *target, int default_port,
-                      struct sockaddr_in *sinp, uint8_t dscp);
+                      struct sockaddr_storage *ssp, uint8_t dscp);
 
 int read_fully(int fd, void *, size_t, size_t *bytes_read);
 int write_fully(int fd, const void *, size_t, size_t *bytes_written);
 
 int read_fully(int fd, void *, size_t, size_t *bytes_read);
 int write_fully(int fd, const void *, size_t, size_t *bytes_written);
@@ -79,4 +79,12 @@ int af_inet_ioctl(unsigned long int command, const void *arg);
 int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
                         unsigned long int cmd, const char *cmd_name);
 
 int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
                         unsigned long int cmd, const char *cmd_name);
 
+/* Functions for working with sockaddr_storage that might contain an IPv4 or
+ * IPv6 address. */
+uint16_t ss_get_port(const struct sockaddr_storage *);
+#define SS_NTOP_BUFSIZE (1 + INET6_ADDRSTRLEN + 1)
+char *ss_format_address(const struct sockaddr_storage *,
+                        char *buf, size_t bufsize);
+size_t ss_length(const struct sockaddr_storage *);
+
 #endif /* socket-util.h */
 #endif /* socket-util.h */
index 81c5a43..8062d2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -148,7 +148,7 @@ struct fd_pstream
 {
     struct pstream pstream;
     int fd;
 {
     struct pstream pstream;
     int fd;
-    int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len,
+    int (*accept_cb)(int fd, const struct sockaddr_storage *, size_t ss_len,
                      struct stream **);
     int (*set_dscp_cb)(int fd, uint8_t dscp);
     char *unlink_path;
                      struct stream **);
     int (*set_dscp_cb)(int fd, uint8_t dscp);
     char *unlink_path;
@@ -179,8 +179,8 @@ fd_pstream_cast(struct pstream *pstream)
  * implementation never fails.) */
 int
 new_fd_pstream(const char *name, int fd,
  * implementation never fails.) */
 int
 new_fd_pstream(const char *name, int fd,
-               int (*accept_cb)(int fd, const struct sockaddr *sa,
-                                size_t sa_len, struct stream **streamp),
+               int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
+                                size_t ss_len, struct stream **streamp),
                int (*set_dscp_cb)(int fd, uint8_t dscp),
                char *unlink_path, struct pstream **pstreamp)
 {
                int (*set_dscp_cb)(int fd, uint8_t dscp),
                char *unlink_path, struct pstream **pstreamp)
 {
@@ -227,8 +227,7 @@ pfd_accept(struct pstream *pstream, struct stream **new_streamp)
         return retval;
     }
 
         return retval;
     }
 
-    return ps->accept_cb(new_fd, (const struct sockaddr *) &ss, ss_len,
-                         new_streamp);
+    return ps->accept_cb(new_fd, &ss, ss_len, new_streamp);
 }
 
 static void
 }
 
 static void
index 8b8b48f..8f595a9 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 struct stream;
 struct pstream;
 
 struct stream;
 struct pstream;
-struct sockaddr;
+struct sockaddr_storage;
 
 int new_fd_stream(const char *name, int fd, int connect_status,
                   struct stream **streamp);
 int new_fd_pstream(const char *name, int fd,
 
 int new_fd_stream(const char *name, int fd, int connect_status,
                   struct stream **streamp);
 int new_fd_pstream(const char *name, int fd,
-                   int (*accept_cb)(int fd, const struct sockaddr *,
-                                    size_t sa_len, struct stream **),
+                   int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
+                                    size_t ss_len, struct stream **),
                    int (*set_dscp_cb)(int fd, uint8_t dscp),
                    char *unlink_path,
                    struct pstream **pstreamp);
                    int (*set_dscp_cb)(int fd, uint8_t dscp),
                    char *unlink_path,
                    struct pstream **pstreamp);
index 2ed5282..a6f1362 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -206,7 +206,7 @@ static int
 new_ssl_stream(const char *name, int fd, enum session_type type,
                enum ssl_state state, struct stream **streamp)
 {
 new_ssl_stream(const char *name, int fd, enum session_type type,
                enum ssl_state state, struct stream **streamp)
 {
-    struct sockaddr_in local;
+    struct sockaddr_storage local;
     socklen_t local_len = sizeof local;
     struct ssl_stream *sslv;
     SSL *ssl = NULL;
     socklen_t local_len = sizeof local;
     struct ssl_stream *sslv;
     SSL *ssl = NULL;
@@ -780,9 +780,11 @@ static int
 pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
 pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
+    char bound_name[SS_NTOP_BUFSIZE + 16];
+    char addrbuf[SS_NTOP_BUFSIZE];
+    struct sockaddr_storage ss;
     struct pssl_pstream *pssl;
     struct pssl_pstream *pssl;
-    struct sockaddr_in sin;
-    char bound_name[128];
+    uint16_t port;
     int retval;
     int fd;
 
     int retval;
     int fd;
 
@@ -791,16 +793,18 @@ pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
         return retval;
     }
 
         return retval;
     }
 
-    fd = inet_open_passive(SOCK_STREAM, suffix, OFP_OLD_PORT, &sin, dscp);
+    fd = inet_open_passive(SOCK_STREAM, suffix, OFP_OLD_PORT, &ss, dscp);
     if (fd < 0) {
         return -fd;
     }
     if (fd < 0) {
         return -fd;
     }
-    sprintf(bound_name, "pssl:%"PRIu16":"IP_FMT,
-            ntohs(sin.sin_port), IP_ARGS(sin.sin_addr.s_addr));
+
+    port = ss_get_port(&ss);
+    snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
+             port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
 
     pssl = xmalloc(sizeof *pssl);
     pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name);
 
     pssl = xmalloc(sizeof *pssl);
     pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name);
-    pstream_set_bound_port(&pssl->pstream, sin.sin_port);
+    pstream_set_bound_port(&pssl->pstream, htons(port));
     pssl->fd = fd;
     *pstreamp = &pssl->pstream;
     return 0;
     pssl->fd = fd;
     *pstreamp = &pssl->pstream;
     return 0;
@@ -818,13 +822,14 @@ static int
 pssl_accept(struct pstream *pstream, struct stream **new_streamp)
 {
     struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
 pssl_accept(struct pstream *pstream, struct stream **new_streamp)
 {
     struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
-    struct sockaddr_in sin;
-    socklen_t sin_len = sizeof sin;
-    char name[128];
+    char name[SS_NTOP_BUFSIZE + 16];
+    char addrbuf[SS_NTOP_BUFSIZE];
+    struct sockaddr_storage ss;
+    socklen_t ss_len = sizeof ss;
     int new_fd;
     int error;
 
     int new_fd;
     int error;
 
-    new_fd = accept(pssl->fd, (struct sockaddr *) &sin, &sin_len);
+    new_fd = accept(pssl->fd, (struct sockaddr *) &ss, &ss_len);
     if (new_fd < 0) {
         error = errno;
         if (error != EAGAIN) {
     if (new_fd < 0) {
         error = errno;
         if (error != EAGAIN) {
@@ -839,10 +844,9 @@ pssl_accept(struct pstream *pstream, struct stream **new_streamp)
         return error;
     }
 
         return error;
     }
 
-    sprintf(name, "ssl:"IP_FMT, IP_ARGS(sin.sin_addr.s_addr));
-    if (sin.sin_port != htons(OFP_OLD_PORT)) {
-        sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin.sin_port));
-    }
+    snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
+             ss_format_address(&ss, addrbuf, sizeof addrbuf),
+             ss_get_port(&ss));
     return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING,
                           new_streamp);
 }
     return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING,
                           new_streamp);
 }
index b3237d6..55e5818 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#include <netdb.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <unistd.h>
+#include "dynamic-string.h"
 #include "packets.h"
 #include "socket-util.h"
 #include "util.h"
 #include "packets.h"
 #include "socket-util.h"
 #include "util.h"
@@ -40,13 +42,13 @@ static int
 new_tcp_stream(const char *name, int fd, int connect_status,
                struct stream **streamp)
 {
 new_tcp_stream(const char *name, int fd, int connect_status,
                struct stream **streamp)
 {
-    struct sockaddr_in local;
+    struct sockaddr_storage local;
     socklen_t local_len = sizeof local;
     int on = 1;
     int retval;
 
     /* Get the local IP and port information */
     socklen_t local_len = sizeof local;
     int on = 1;
     int retval;
 
     /* Get the local IP and port information */
-    retval = getsockname(fd, (struct sockaddr *)&local, &local_len);
+    retval = getsockname(fd, (struct sockaddr *) &local, &local_len);
     if (retval) {
         memset(&local, 0, sizeof local);
     }
     if (retval) {
         memset(&local, 0, sizeof local);
     }
@@ -90,47 +92,47 @@ const struct stream_class tcp_stream_class = {
 \f
 /* Passive TCP. */
 
 \f
 /* Passive TCP. */
 
-static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
-                       struct stream **streamp);
+static int ptcp_accept(int fd, const struct sockaddr_storage *,
+                       size_t, struct stream **streamp);
 
 static int
 ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
 
 static int
 ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
           uint8_t dscp)
 {
-    struct sockaddr_in sin;
-    char bound_name[128];
+    char bound_name[SS_NTOP_BUFSIZE + 16];
+    char addrbuf[SS_NTOP_BUFSIZE];
+    struct sockaddr_storage ss;
+    uint16_t port;
     int error;
     int fd;
 
     int error;
     int fd;
 
-    fd = inet_open_passive(SOCK_STREAM, suffix, -1, &sin, dscp);
+    fd = inet_open_passive(SOCK_STREAM, suffix, -1, &ss, dscp);
     if (fd < 0) {
         return -fd;
     }
 
     if (fd < 0) {
         return -fd;
     }
 
-    sprintf(bound_name, "ptcp:%"PRIu16":"IP_FMT,
-            ntohs(sin.sin_port), IP_ARGS(sin.sin_addr.s_addr));
+    port = ss_get_port(&ss);
+    snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
+             port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
+
     error = new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL,
                            pstreamp);
     if (!error) {
     error = new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL,
                            pstreamp);
     if (!error) {
-        pstream_set_bound_port(*pstreamp, sin.sin_port);
+        pstream_set_bound_port(*pstreamp, htons(port));
     }
     return error;
 }
 
 static int
     }
     return error;
 }
 
 static int
-ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
-            struct stream **streamp)
+ptcp_accept(int fd, const struct sockaddr_storage *ss,
+            size_t ss_len OVS_UNUSED, struct stream **streamp)
 {
 {
-    const struct sockaddr_in *sin = ALIGNED_CAST(const struct sockaddr_in *,
-                                                 sa);
-    char name[128];
+    char name[SS_NTOP_BUFSIZE + 16];
+    char addrbuf[SS_NTOP_BUFSIZE];
 
 
-    if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) {
-        sprintf(name, "tcp:"IP_FMT, IP_ARGS(sin->sin_addr.s_addr));
-        sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port));
-    } else {
-        strcpy(name, "tcp");
-    }
+    snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
+             ss_format_address(ss, addrbuf, sizeof addrbuf),
+             ss_get_port(ss));
     return new_tcp_stream(name, fd, 0, streamp);
 }
 
     return new_tcp_stream(name, fd, 0, streamp);
 }
 
index e4b7e77..b3d70b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -75,8 +75,8 @@ const struct stream_class unix_stream_class = {
 \f
 /* Passive UNIX socket. */
 
 \f
 /* Passive UNIX socket. */
 
-static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
-                        struct stream **streamp);
+static int punix_accept(int fd, const struct sockaddr_storage *ss,
+                        size_t ss_len, struct stream **streamp);
 
 static int
 punix_open(const char *name OVS_UNUSED, char *suffix,
 
 static int
 punix_open(const char *name OVS_UNUSED, char *suffix,
@@ -105,11 +105,11 @@ punix_open(const char *name OVS_UNUSED, char *suffix,
 }
 
 static int
 }
 
 static int
-punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
+punix_accept(int fd, const struct sockaddr_storage *ss, size_t ss_len,
              struct stream **streamp)
 {
              struct stream **streamp)
 {
-    const struct sockaddr_un *sun = (const struct sockaddr_un *) sa;
-    int name_len = get_unix_name_len(sa_len);
+    const struct sockaddr_un *sun = (const struct sockaddr_un *) ss;
+    int name_len = get_unix_name_len(ss_len);
     char name[128];
 
     if (name_len > 0) {
     char name[128];
 
     if (name_len > 0) {
index 3542455..b69f03c 100644 (file)
@@ -720,18 +720,18 @@ pstream_open_with_default_port(const char *name_,
 /*
  * This function extracts IP address and port from the target string.
  *
 /*
  * This function extracts IP address and port from the target string.
  *
- *     - On success, function returns true and fills *sin structure with port
+ *     - On success, function returns true and fills *ss structure with port
  *       and IP address. If port was absent in target string then it will use
  *       corresponding default port value.
  *       and IP address. If port was absent in target string then it will use
  *       corresponding default port value.
- *     - On error, function returns false and *sin contains garbage.
+ *     - On error, function returns false and *ss contains garbage.
  */
 bool
 stream_parse_target_with_default_port(const char *target,
                                       uint16_t default_port,
  */
 bool
 stream_parse_target_with_default_port(const char *target,
                                       uint16_t default_port,
-                                      struct sockaddr_in *sin)
+                                      struct sockaddr_storage *ss)
 {
     return ((!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4))
 {
     return ((!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4))
-             && inet_parse_active(target + 4, default_port, sin));
+            && inet_parse_active(target + 4, default_port, ss));
 }
 
 /* Attempts to guess the content type of a stream whose first few bytes were
 }
 
 /* Attempts to guess the content type of a stream whose first few bytes were
index d966cde..3780ff9 100644 (file)
@@ -81,7 +81,7 @@ int pstream_open_with_default_port(const char *name,
                                    uint8_t dscp);
 bool stream_parse_target_with_default_port(const char *target,
                                            uint16_t default_port,
                                    uint8_t dscp);
 bool stream_parse_target_with_default_port(const char *target,
                                            uint16_t default_port,
-                                           struct sockaddr_in *sin);
+                                           struct sockaddr_storage *ss);
 int stream_or_pstream_needs_probes(const char *name);
 
 /* Error reporting. */
 int stream_or_pstream_needs_probes(const char *name);
 
 /* Error reporting. */
index bf7aaf7..c1e9281 100644 (file)
@@ -1,9 +1,10 @@
 .IP "\fBssl:\fIip\fR[\fB:\fIport\fR]"
 .IQ "\fBtcp:\fIip\fR[\fB:\fIport\fR]"
 The specified \fIport\fR on the host at the given \fIip\fR, which must
 .IP "\fBssl:\fIip\fR[\fB:\fIport\fR]"
 .IQ "\fBtcp:\fIip\fR[\fB:\fIport\fR]"
 The specified \fIport\fR on the host at the given \fIip\fR, which must
-be expressed as an IP address (not a DNS name).  For \fBssl\fR, the
-\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
-options are mandatory.
+be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
+format.  Wrap IPv6 addresses in square brackets,
+e.g. \fBtcp:[::1]:6633\fR.  For \fBssl\fR, the \fB\-\-private\-key\fR,
+\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory.
 .IP
 If \fIport\fR is not specified, it currently defaults to 6633.  In the
 future, the default will change to 6653, which is the IANA-defined
 .IP
 If \fIport\fR is not specified, it currently defaults to 6633.  In the
 future, the default will change to 6653, which is the IANA-defined
index a9efdb3..0cf8fc1 100644 (file)
@@ -1,14 +1,14 @@
 .IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]"
 .IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
 .IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]"
 .IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
-Listens for OpenFlow connections on \fIport\fR.  By
-default, connections are not bound to a particular local IP address, but
-\fIip\fR may be specified to listen only for connections to the given
-\fIip\fR.  For \fBpssl\fR, the \fB\-\-private\-key\fR,
-\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory.
+Listens for OpenFlow connections on \fIport\fR.  The default
+\fIport\fR is 6633, but a future version of Open vSwitch will change
+the default to the IANA-defined port 6653.  By default, connections
+are allowed from any IPv4 address.  Specify \fIip\fR as an IPv4
+address or a bracketed IPv6 address (e.g. \fBptcp:6633:[::1]\fR).  DNS
+names may not be used.  For \fBpssl\fR, the
+\fB\-\-private\-key\fR,\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
+options are mandatory.
 .IP
 .IP
-If \fIport\fR is not specified, it currently defaults to 6633.  In the
-future, the default will change to 6653, which is the IANA-defined
-value.
 .
 .IP "\fBpunix:\fIfile\fR"
 Listens for OpenFlow connections on the Unix domain server socket
 .
 .IP "\fBpunix:\fIfile\fR"
 Listens for OpenFlow connections on the Unix domain server socket
index b7c16d2..a58e785 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -734,17 +734,13 @@ update_in_band_remotes(struct connmgr *mgr)
 
     /* Add all the remotes. */
     HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) {
 
     /* Add all the remotes. */
     HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) {
-        struct sockaddr_in *sin = &addrs[n_addrs];
         const char *target = rconn_get_target(ofconn->rconn);
         const char *target = rconn_get_target(ofconn->rconn);
+        struct sockaddr_storage ss;
 
 
-        if (ofconn->band == OFPROTO_OUT_OF_BAND) {
-            continue;
-        }
-
-        if (stream_parse_target_with_default_port(target,
-                                                  OFP_OLD_PORT,
-                                                  sin)) {
-            n_addrs++;
+        if (ofconn->band == OFPROTO_IN_BAND
+            && stream_parse_target_with_default_port(target, OFP_OLD_PORT, &ss)
+            && ss.ss_family == AF_INET) {
+            addrs[n_addrs++] = *(struct sockaddr_in *) &ss;
         }
     }
     for (i = 0; i < mgr->n_extra_remotes; i++) {
         }
     }
     for (i = 0; i < mgr->n_extra_remotes; i++) {
index e9ef434..ff07e70 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  * Copyright (c) 2009 InMon Corp.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Copyright (c) 2009 InMon Corp.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -253,13 +253,16 @@ sflow_choose_agent_address(const char *agent_device,
     }
 
     SSET_FOR_EACH (target, targets) {
     }
 
     SSET_FOR_EACH (target, targets) {
-        struct sockaddr_in sin;
+        struct sockaddr_storage ss;
         char name[IFNAMSIZ];
 
         char name[IFNAMSIZ];
 
-        if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &sin)
-            && route_table_get_name(sin.sin_addr.s_addr, name)
-            && !netdev_get_in4_by_name(name, &in4)) {
-            goto success;
+        if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss)
+            && ss.ss_family == AF_INET) {
+            struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
+            if (route_table_get_name(sin->sin_addr.s_addr, name)
+                && !netdev_get_in4_by_name(name, &in4)) {
+                goto success;
+            }
         }
     }
 
         }
     }
 
index a934cf0..419b1c8 100644 (file)
@@ -1,11 +1,15 @@
 .IP "\fBssl:\fIip\fB:\fIport\fR"
 The specified SSL \fIport\fR on the host at the given \fIip\fR, which
 .IP "\fBssl:\fIip\fB:\fIport\fR"
 The specified SSL \fIport\fR on the host at the given \fIip\fR, which
-must be expressed as an IP address (not a DNS name).  The
-\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
+must be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
+format.  If \fIip\fR is an IPv6 address, then wrap \fIip\fR with square
+brackets, e.g.: \fBssl:[::1]:6632\fR.
+The \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
 options are mandatory when this form is used.
 .
 .IP "\fBtcp:\fIip\fB:\fIport\fR"
 options are mandatory when this form is used.
 .
 .IP "\fBtcp:\fIip\fB:\fIport\fR"
-Connect to the given TCP \fIport\fR on \fIip\fR.
+Connect to the given TCP \fIport\fR on \fIip\fR, where \fIip\fR can be IPv4
+or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with
+square brackets, e.g.: \fBtcp:[::1]:6632\fR.
 .
 .IP "\fBunix:\fIfile\fR"
 Connect to the Unix domain server socket named \fIfile\fR.
 .
 .IP "\fBunix:\fIfile\fR"
 Connect to the Unix domain server socket named \fIfile\fR.
index 4cbc007..200651b 100644 (file)
@@ -1,15 +1,22 @@
 .IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]"
 Listen on the given SSL \fIport\fR for a connection.  By default,
 .IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]"
 Listen on the given SSL \fIport\fR for a connection.  By default,
-connections are not bound to a particular local IP address, but
+connections are not bound to a particular local IP address and
+it listens only on IPv4 (but not IPv6) addresses, but
 specifying \fIip\fR limits connections to those from the given
 specifying \fIip\fR limits connections to those from the given
-\fIip\fR.  The \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and
-\fB\-\-ca\-cert\fR options are mandatory when this form is used.
+\fIip\fR, either IPv4 or IPv6 address.  If \fIip\fR is
+an IPv6 address, then wrap \fIip\fR with square brackets, e.g.:
+\fBpssl:6632:[::1]\fR.  The \fB\-\-private\-key\fR,
+\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory
+when this form is used.
 .
 .IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]"
 Listen on the given TCP \fIport\fR for a connection.  By default,
 .
 .IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]"
 Listen on the given TCP \fIport\fR for a connection.  By default,
-connections are not bound to a particular local IP address, but
+connections are not bound to a particular local IP address and
+it listens only on IPv4 (but not IPv6) addresses, but
 \fIip\fR may be specified to listen only for connections to the given
 \fIip\fR may be specified to listen only for connections to the given
-\fIip\fR.
+\fIip\fR, either IPv4 or IPv6 address.  If \fIip\fR is
+an IPv6 address, then wrap \fIip\fR with square brackets, e.g.:
+\fBptcp:6632:[::1]\fR.
 .
 .IP "\fBpunix:\fIfile\fR"
 Listen on the Unix domain server socket named \fIfile\fR for a
 .
 .IP "\fBpunix:\fIfile\fR"
 Listen on the Unix domain server socket named \fIfile\fR for a
index c657047..be9fc95 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010, 2012 Nicira, Inc.
+# Copyright (c) 2010, 2012, 2014 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -177,24 +177,44 @@ def check_connection_completion(sock):
         return errno.EAGAIN
 
 
         return errno.EAGAIN
 
 
+def is_valid_ipv4_address(address):
+    try:
+        socket.inet_pton(socket.AF_INET, address)
+    except AttributeError:
+        try:
+            socket.inet_aton(address)
+        except socket.error:
+            return False
+    except socket.error:
+        return False
+
+    return True
+
+
 def inet_parse_active(target, default_port):
     address = target.split(":")
 def inet_parse_active(target, default_port):
     address = target.split(":")
-    host_name = address[0]
-    if not host_name:
-        raise ValueError("%s: bad peer name format" % target)
     if len(address) >= 2:
     if len(address) >= 2:
-        port = int(address[1])
-    elif default_port:
-        port = default_port
+        host_name = ":".join(address[0:-1]).lstrip('[').rstrip(']')
+        port = int(address[-1])
     else:
     else:
-        raise ValueError("%s: port number must be specified" % target)
+        if default_port:
+            port = default_port
+        else:
+            raise ValueError("%s: port number must be specified" % target)
+        host_name = address[0]
+    if not host_name:
+        raise ValueError("%s: bad peer name format" % target)
     return (host_name, port)
 
 
 def inet_open_active(style, target, default_port, dscp):
     address = inet_parse_active(target, default_port)
     try:
     return (host_name, port)
 
 
 def inet_open_active(style, target, default_port, dscp):
     address = inet_parse_active(target, default_port)
     try:
-        sock = socket.socket(socket.AF_INET, style, 0)
+        is_addr_inet = is_valid_ipv4_address(address[0])
+        if is_addr_inet:
+            sock = socket.socket(socket.AF_INET, style, 0)
+        else:
+            sock = socket.socket(socket.AF_INET6, style, 0)
     except socket.error, e:
         return get_exception_errno(e), None
 
     except socket.error, e:
         return get_exception_errno(e), None
 
index 1c1f029..7a936a2 100644 (file)
@@ -1829,55 +1829,58 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/[[0-9]]\{1,\}$/?/' | sort],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-dnl Test that sFlow samples packets correctly.
-AT_SETUP([ofproto-dpif - sFlow packet sampling])
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-
-ON_EXIT([kill `cat test-sflow.pid`])
-AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([sflow.log])
-SFLOW_PORT=`parse_listening_port < test-sflow.log`
-
-ovs-appctl time/stop
-
-ADD_OF_PORTS([br0], 1, 2)
-ovs-vsctl \
-   set Interface br0 options:ifindex=1002 -- \
-   set Interface p1 options:ifindex=1004 -- \
-   set Interface p2 options:ifindex=1003 -- \
-   set Bridge br0 sflow=@sf -- \
-   --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
-     header=128 sampling=1 polling=1
-
-dnl open with ARP packets to seed the bridge-learning.  The output
-dnl ifIndex numbers should be reported predictably after that.
-dnl Since we set sampling=1 we should see all of these packets
-dnl reported. Sorting the output by data-source and seqNo makes
-dnl it deterministic. Ensuring that we send at least two packets
-dnl into each port means we get to check the seq nos are
-dnl incrementing correctly.
-
-dnl because packets from different ports can be handled by separate
-dnl threads, put some sleeps
-
-ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)'
-sleep 1
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)'
-sleep 1
-ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
-sleep 1
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
-
-dnl sleep long enough to get more than one counter sample
-dnl from each datasource so we can check sequence numbers
-for i in `seq 1 30`; do
-    ovs-appctl time/warp 100
-done
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-sflow exit
+# CHECK_SFLOW_SAMPLING_PACKET(LOOPBACK_ADDR, ADDR_WITHOUT_BRACKETS)
+#
+# Test that sFlow samples packets correctly using IPv4/IPv6 sFlow collector
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_SFLOW_SAMPLING_PACKET],
+  [AT_SETUP([ofproto-dpif - sFlow packet sampling - $2 collector])
+  OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+
+  ON_EXIT([kill `cat test-sflow.pid`])
+  AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
+  AT_CAPTURE_FILE([sflow.log])
+  SFLOW_PORT=`parse_listening_port < test-sflow.log`
+  ovs-appctl time/stop
+
+  ADD_OF_PORTS([br0], 1, 2)
+  ovs-vsctl \
+     set Interface br0 options:ifindex=1002 -- \
+     set Interface p1 options:ifindex=1004 -- \
+     set Interface p2 options:ifindex=1003 -- \
+     set Bridge br0 sflow=@sf -- \
+     --id=@sf create sflow targets=\"$1:$SFLOW_PORT\" \
+       header=128 sampling=1 polling=1 agent=lo
+
+  dnl open with ARP packets to seed the bridge-learning.  The output
+  dnl ifIndex numbers should be reported predictably after that.
+  dnl Since we set sampling=1 we should see all of these packets
+  dnl reported. Sorting the output by data-source and seqNo makes
+  dnl it deterministic. Ensuring that we send at least two packets
+  dnl into each port means we get to check the seq nos are
+  dnl incrementing correctly.
+  dnl because packets from different ports can be handled by separate
+  dnl threads, put some sleeps
+
+  ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)'
+  sleep 1
+  ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)'
+  sleep 1
+  ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+  sleep 1
+  ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+  ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
+
+  dnl sleep long enough to get more than one counter sample
+  dnl from each datasource so we can check sequence numbers
+  for i in `seq 1 30`; do
+      ovs-appctl time/warp 100
+  done
+  OVS_VSWITCHD_STOP
+  ovs-appctl -t test-sflow exit
 
 
-AT_CHECK([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
+  AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
        /g']], [0], [dnl
 HEADER
        dgramSeqNo=1
        /g']], [0], [dnl
 HEADER
        dgramSeqNo=1
@@ -1981,7 +1984,7 @@ HEADER
        hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
 ])
 
        hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
 ])
 
-AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
+  AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
        /g']], [0], [dnl
 IFCOUNTERS
        dgramSeqNo=2
        /g']], [0], [dnl
 IFCOUNTERS
        dgramSeqNo=2
@@ -2122,128 +2125,144 @@ IFCOUNTERS
        out_errors=0
        promiscuous=0
 ])
        out_errors=0
        promiscuous=0
 ])
-AT_CLEANUP
-
-
-
-dnl Test that basic NetFlow reports flow statistics correctly:
-dnl - The initial packet of a flow are correctly accounted.
-dnl - Later packets within a flow are correctly accounted.
-dnl - Flow actions changing (in this case, due to MAC learning)
-dnl   cause a record to be sent.
-AT_SETUP([ofproto-dpif - NetFlow flow expiration])
-
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-ADD_OF_PORTS([br0], 1, 2)
+  AT_CLEANUP])
 
 
-ovs-appctl time/stop
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
-
-ovs-vsctl \
-   set Bridge br0 netflow=@nf -- \
-   --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
-     engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
-
-for delay in 1000 30000; do
-    ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
-    ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+CHECK_SFLOW_SAMPLING_PACKET([127.0.0.1], [IPv4])
+CHECK_SFLOW_SAMPLING_PACKET([[[::1]]], [IPv6])
 
 
-    ovs-appctl time/warp $delay
-done
-
-ovs-appctl time/warp 6000
-sleep 1
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-netflow exit
+# CHECK_NETFLOW_EXPIRATION(LOOPBACK_ADDR, IP_VERSION_TYPE)
+#
+# Test that basic NetFlow reports flow statistics correctly:
+# The initial packet of a flow are correctly accounted.
+# Later packets within a flow are correctly accounted.
+# Flow actions changing (in this case, due to MAC learning)
+# cause a record to be sent.
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_NETFLOW_EXPIRATION],
+  [AT_SETUP([ofproto-dpif - NetFlow flow expiration - $2 collector])
+  OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+  ADD_OF_PORTS([br0], 1, 2)
+
+  ovs-appctl time/stop
+  ON_EXIT([kill `cat test-netflow.pid`])
+  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CAPTURE_FILE([netflow.log])
+  NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+
+  ovs-vsctl \
+     set Bridge br0 netflow=@nf -- \
+     --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+       engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
+
+  for delay in 1000 30000; do
+      ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+      ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+
+      ovs-appctl time/warp $delay
+  done
 
 
-AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
+  ovs-appctl time/warp 6000
+  sleep 1
+  OVS_VSWITCHD_STOP
+  ovs-appctl -t test-netflow exit
 
 
-AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
+  AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
 
 
-combined=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0" netflow.log | wc -l`
-separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l`
-AT_CHECK([test $separate = 2 || test $combined = 1], [0])
+  AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
 
 
-AT_CLEANUP
+  combined=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0" netflow.log | wc -l`
+  separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l`
+  AT_CHECK([test $separate = 2 || test $combined = 1], [0])
 
 
-dnl Test that basic NetFlow reports active expirations correctly.
-AT_SETUP([ofproto-dpif - NetFlow active expiration])
+  AT_CLEANUP])
 
 
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-ADD_OF_PORTS([br0], 1, 2)
+CHECK_NETFLOW_EXPIRATION([127.0.0.1], [IPv4])
+CHECK_NETFLOW_EXPIRATION([[[::1]]], [IPv6])
 
 
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+# CHECK_NETFLOW_ACTIVE_EXPIRATION(LOOPBACK_ADDR, IP_VERSION_TYPE)
+#
+# Test that basic NetFlow reports active expirations correctly.
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_NETFLOW_ACTIVE_EXPIRATION],
+  [AT_SETUP([ofproto-dpif - NetFlow active expiration - $2 collector])
 
 
-ovs-vsctl \
-   set Bridge br0 netflow=@nf -- \
-   --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
-     engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
+  OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+  ADD_OF_PORTS([br0], 1, 2)
 
 
-AT_CHECK([ovs-appctl time/stop])
-n=1
-while test $n -le 60; do
-    n=`expr $n + 1`
+  ON_EXIT([kill `cat test-netflow.pid`])
+  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CAPTURE_FILE([netflow.log])
+  NETFLOW_PORT=`parse_listening_port < test-netflow.log`
 
 
-    ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=1234,dst=80)'
-    ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=1234)'
+  ovs-vsctl \
+     set Bridge br0 netflow=@nf -- \
+     --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+       engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
 
 
-    ovs-appctl time/warp 1000
-done
+  AT_CHECK([ovs-appctl time/stop])
+  n=1
+  while test $n -le 60; do
+      n=`expr $n + 1`
 
 
-ovs-appctl time/warp 10000
+      ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=1234,dst=80)'
+      ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=1234)'
 
 
-sleep 1
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-netflow exit
-
-# Count the number of reported packets:
-# - From source to destination before MAC learning kicks in (just one).
-# - From source to destination after that.
-# - From destination to source.
-n_learn=0
-n_in=0
-n_out=0
-n_other=0
-n_recs=0
-none=0
-while read line; do
-    pkts=`echo "$line" | sed 's/.*, \([[0-9]]*\) pkts,.*/\1/'`
-    case $pkts in
-         [[0-9]]*) ;;
-        *) continue ;;
-    esac
-
-    case $line in
-        "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
-            counter=n_learn
-           ;;
-       "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
-           counter=n_in
-           ;;
-       "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
-           counter=n_out
-           ;;
-       *)
-           counter=n_other
-           ;;
-    esac
-    eval $counter=\`expr \$$counter + \$pkts\`
-    n_recs=`expr $n_recs + 1`
-done < netflow.log
-
-# There should be exactly 1 MAC learning packet,
-# exactly 59 other packets in that direction,
-# and exactly 60 packets in the other direction.
-AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
-])
+      ovs-appctl time/warp 1000
+  done
 
 
-AT_CLEANUP
+  ovs-appctl time/warp 10000
+
+  sleep 1
+  OVS_VSWITCHD_STOP
+  ovs-appctl -t test-netflow exit
+
+  # Count the number of reported packets:
+  # - From source to destination before MAC learning kicks in (just one).
+  # - From source to destination after that.
+  # - From destination to source.
+  n_learn=0
+  n_in=0
+  n_out=0
+  n_other=0
+  n_recs=0
+  none=0
+  while read line; do
+      pkts=`echo "$line" | sed 's/.*, \([[0-9]]*\) pkts,.*/\1/'`
+      case $pkts in
+           [[0-9]]*) ;;
+       *) continue ;;
+      esac
+
+      case $line in
+          "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+              counter=n_learn
+          ;;
+      "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+          counter=n_in
+          ;;
+      "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
+          counter=n_out
+          ;;
+      *)
+          counter=n_other
+          ;;
+      esac
+      eval $counter=\`expr \$$counter + \$pkts\`
+      n_recs=`expr $n_recs + 1`
+  done < netflow.log
+
+  # There should be exactly 1 MAC learning packet,
+  # exactly 59 other packets in that direction,
+  # and exactly 60 packets in the other direction.
+  AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
+])
+
+  AT_CLEANUP])
+
+CHECK_NETFLOW_ACTIVE_EXPIRATION([127.0.0.1], [IPv4])
+CHECK_NETFLOW_ACTIVE_EXPIRATION([[[::1]]], [IPv6])
 
 AT_SETUP([idle_age and hard_age increase over time])
 OVS_VSWITCHD_START
 
 AT_SETUP([idle_age and hard_age increase over time])
 OVS_VSWITCHD_START
@@ -2700,30 +2719,37 @@ skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-AT_SETUP([ofproto-dpif megaflow - netflow])
-OVS_VSWITCHD_START
-ADD_OF_PORTS([br0], [1], [2])
-
-dnl NetFlow configuration disables wildcarding relevant fields
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
-ovs-vsctl \
-   set Bridge br0 netflow=@nf -- \
-   --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
-     engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
-
-AT_CHECK([ovs-ofctl add-flow br0 action=normal])
-AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
+# CHECK_MEGAFLOW_NETFLOW(LOOPBACK_ADDR, IP_VERSION_TYPE)
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_MEGAFLOW_NETFLOW],
+  [AT_SETUP([ofproto-dpif megaflow - netflow - $2 collector])
+  OVS_VSWITCHD_START
+  ADD_OF_PORTS([br0], [1], [2])
+
+  dnl NetFlow configuration disables wildcarding relevant fields
+  ON_EXIT([kill `cat test-netflow.pid`])
+  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CAPTURE_FILE([netflow.log])
+  NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+  ovs-vsctl \
+     set Bridge br0 netflow=@nf -- \
+     --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+       engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
+
+  AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+  AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+  AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+  sleep 1
+  AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
 skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
 skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
 ])
 skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
 skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
 ])
-OVS_VSWITCHD_STOP
-AT_CLEANUP
+  OVS_VSWITCHD_STOP
+  AT_CLEANUP])
+
+CHECK_MEGAFLOW_NETFLOW([127.0.0.1], [IPv4])
+CHECK_MEGAFLOW_NETFLOW([[[::1]]], [IPv6])
 
 AT_SETUP([ofproto-dpif megaflow - normal, active-backup bonding])
 OVS_VSWITCHD_START(
 
 AT_SETUP([ofproto-dpif megaflow - normal, active-backup bonding])
 OVS_VSWITCHD_START(
index 3bcffc2..a82a9b1 100644 (file)
@@ -21,7 +21,7 @@ s/ hard_age=[0-9]*,//
 # log, given that the server was told to listen on a kernel-chosen
 # port, file provided on stdin, and prints the port number on stdout.
 # You should specify the listening remote as ptcp:0:127.0.0.1 or
 # log, given that the server was told to listen on a kernel-chosen
 # port, file provided on stdin, and prints the port number on stdout.
 # You should specify the listening remote as ptcp:0:127.0.0.1 or
-# pssl:0:127.0.0.1.
+# pssl:0:127.0.0.1, or the equivalent with [::1] instead of 127.0.0.1.
 #
 # Here's an example of how to use this with ovsdb-server:
 #
 #
 # Here's an example of how to use this with ovsdb-server:
 #
@@ -29,7 +29,7 @@ s/ hard_age=[0-9]*,//
 #    ovsdb-server --log-file --remote=ptcp:0:127.0.0.1 ...
 #    TCP_PORT=`parse_listening_port < ovsdb-server.log`
 parse_listening_port () {
 #    ovsdb-server --log-file --remote=ptcp:0:127.0.0.1 ...
 #    TCP_PORT=`parse_listening_port < ovsdb-server.log`
 parse_listening_port () {
-    sed -n 's/.*0:127\.0\.0\.1: listening on port \([0-9]*\)$/\1/p'
+    sed -n 's/.*0:.*: listening on port \([0-9]*\)$/\1/p'
 }]
 m4_divert_pop([PREPARE_TESTS])
 
 }]
 m4_divert_pop([PREPARE_TESTS])
 
index d014804..949ed59 100644 (file)
@@ -177,7 +177,7 @@ OVSDB_CHECK_EXECUTION([duplicate uuid-name not allowed],
   [[[{"uuid":["uuid","<0>"]},{"details":"This \"uuid-name\" appeared on an earlier \"insert\" operation.","error":"duplicate uuid-name","syntax":"\"x\""}]
 ]])
 
   [[[{"uuid":["uuid","<0>"]},{"details":"This \"uuid-name\" appeared on an earlier \"insert\" operation.","error":"duplicate uuid-name","syntax":"\"x\""}]
 ]])
 
-m4_define([EXECUTION_EXAMPLES], [
+m4_define([ONE_EXECUTION_EXAMPLE], [dnl
 dnl At one point the "commit" code ignored new rows with all-default values,
 dnl so this checks for that problem.
 OVSDB_CHECK_EXECUTION([insert default row, query table],
 dnl At one point the "commit" code ignored new rows with all-default values,
 dnl so this checks for that problem.
 OVSDB_CHECK_EXECUTION([insert default row, query table],
@@ -193,7 +193,10 @@ OVSDB_CHECK_EXECUTION([insert default row, query table],
   [[[{"uuid":["uuid","<0>"]}]
 [{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"","number":0}]}]
 ]])
   [[[{"uuid":["uuid","<0>"]}]
 [{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"","number":0}]}]
 ]])
+])
 
 
+m4_define([EXECUTION_EXAMPLES], [
+ONE_EXECUTION_EXAMPLE
 OVSDB_CHECK_EXECUTION([insert row, query table],
   [ordinal_schema],
   [[[["ordinals",
 OVSDB_CHECK_EXECUTION([insert row, query table],
   [ordinal_schema],
   [[[["ordinals",
index 9ff7b1b..0c6d7df 100644 (file)
@@ -72,10 +72,33 @@ m4_define([OVSDB_CHECK_IDL_TCP_PY],
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
+# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp6
+m4_define([OVSDB_CHECK_IDL_TCP6_PY],
+  [AT_SETUP([$1 - Python tcp6])
+   AT_SKIP_IF([test $HAVE_PYTHON = no])
+   AT_KEYWORDS([ovsdb server idl positive Python with tcp6 socket $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+   OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+   AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
+                  [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+   TCP_PORT=`parse_listening_port < ovsdb-server.log`
+   echo "TCP_PORT=$TCP_PORT"
+
+   m4_if([$2], [], [],
+     [AT_CHECK([ovsdb-client transact "tcp:[[::1]]:$TCP_PORT" $2], [0], [ignore], [ignore], [kill `cat pid`])])
+   AT_CHECK([strace $PYTHON $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema tcp:[[::1]]:$TCP_PORT $3],
+            [0], [stdout], [ignore], [kill `cat pid`])
+   AT_CHECK([sort stdout | ${PERL} $srcdir/uuidfilt.pl]m4_if([$6],,, [[| $6]]),
+            [0], [$4], [], [kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
 m4_define([OVSDB_CHECK_IDL],
   [OVSDB_CHECK_IDL_C($@)
    OVSDB_CHECK_IDL_PY($@)
 m4_define([OVSDB_CHECK_IDL],
   [OVSDB_CHECK_IDL_C($@)
    OVSDB_CHECK_IDL_PY($@)
-   OVSDB_CHECK_IDL_TCP_PY($@)])
+   OVSDB_CHECK_IDL_TCP_PY($@)
+   OVSDB_CHECK_IDL_TCP6_PY($@)])
 
 OVSDB_CHECK_IDL([simple idl, initially empty, no ops],
   [],
 
 OVSDB_CHECK_IDL([simple idl, initially empty, no ops],
   [],
index a2c53f3..b01743d 100644 (file)
@@ -748,7 +748,7 @@ for i in `seq 1 100`; do
 done
 AT_CLEANUP
 \f
 done
 AT_CLEANUP
 \f
-AT_BANNER([OVSDB -- ovsdb-server transactions (SSL sockets)])
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv4 sockets)])
 
 # OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
 #
 
 # OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
 #
@@ -787,7 +787,46 @@ cat stdout >> output
 
 EXECUTION_EXAMPLES
 
 
 EXECUTION_EXAMPLES
 
-AT_BANNER([OVSDB -- ovsdb-server transactions (TCP sockets)])
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv6 sockets)])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive ssl6 $5])
+   AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+   OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --private-key=$PKIDIR/testpki-privkey2.pem --certificate=$PKIDIR/testpki-cert2.pem --ca-cert=$PKIDIR/testpki-cacert.pem --remote=pssl:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+   SSL_PORT=`parse_listening_port < ovsdb-server.log`
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client --private-key=$PKIDIR/testpki-privkey.pem --certificate=$PKIDIR/testpki-cert.pem --ca-cert=$PKIDIR/testpki-cacert.pem transact ssl:[[::1]]:$SSL_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (TCP IPv4 sockets)])
 
 AT_SETUP([ovsdb-client get-schema-version - tcp socket])
 AT_KEYWORDS([ovsdb server positive tcp])
 
 AT_SETUP([ovsdb-client get-schema-version - tcp socket])
 AT_KEYWORDS([ovsdb server positive tcp])
@@ -836,6 +875,42 @@ cat stdout >> output
    AT_CLEANUP])
 
 EXECUTION_EXAMPLES
    AT_CLEANUP])
 
 EXECUTION_EXAMPLES
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive tcp6 $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+   OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+   $2 > schema
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+   TCP_PORT=`parse_listening_port < ovsdb-server.log`
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client transact tcp:[[::1]]:$TCP_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
 \f
 AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 
 \f
 AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 
index cba01b9..deebd82 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  * Copyright (c) 2013 InMon Corp.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Copyright (c) 2013 InMon Corp.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,7 +44,6 @@ static unixctl_cb_func test_sflow_exit;
 /* Datagram. */
 #define SFLOW_VERSION_5 5
 #define SFLOW_MIN_LEN 36
 /* Datagram. */
 #define SFLOW_VERSION_5 5
 #define SFLOW_MIN_LEN 36
-#define SFLOW_MAX_AGENTIP_STRLEN 64
 
 /* Sample tag numbers. */
 #define SFLOW_FLOW_SAMPLE 1
 
 /* Sample tag numbers. */
 #define SFLOW_FLOW_SAMPLE 1
@@ -82,7 +81,7 @@ struct sflow_xdr {
 
     /* Agent. */
     struct sflow_addr agentAddr;
 
     /* Agent. */
     struct sflow_addr agentAddr;
-    char agentIPStr[SFLOW_MAX_AGENTIP_STRLEN];
+    char agentIPStr[INET6_ADDRSTRLEN + 2];
     uint32_t subAgentId;
     uint32_t uptime_mS;
 
     uint32_t subAgentId;
     uint32_t uptime_mS;
 
@@ -325,14 +324,12 @@ process_datagram(struct sflow_xdr *x)
 
     /* Store the agent address as a string. */
     if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
 
     /* Store the agent address as a string. */
     if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
-        snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
-                 "%04x:%04x:%04x:%04x",
-                 x->agentAddr.a.ip6[0],
-                 x->agentAddr.a.ip6[1],
-                 x->agentAddr.a.ip6[2],
-                 x->agentAddr.a.ip6[3]);
+        char ipstr[INET6_ADDRSTRLEN];
+        inet_ntop(AF_INET6, (const void *) &x->agentAddr.a.ip6,
+                  ipstr, INET6_ADDRSTRLEN);
+        snprintf(x->agentIPStr, sizeof x->agentIPStr, "[%s]", ipstr);
     } else {
     } else {
-        snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
+        snprintf(x->agentIPStr, sizeof x->agentIPStr,
                  IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
     }
 
                  IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
     }
 
index 5b1aec3..cde4bd0 100644 (file)
@@ -466,12 +466,12 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg,
 
         managers = xmalloc(sset_count(&targets) * sizeof *managers);
         SSET_FOR_EACH (target, &targets) {
 
         managers = xmalloc(sset_count(&targets) * sizeof *managers);
         SSET_FOR_EACH (target, &targets) {
-            struct sockaddr_in *sin = &managers[n_managers];
+            struct sockaddr_storage ss;
 
 
-            if (stream_parse_target_with_default_port(target,
-                                                      OVSDB_OLD_PORT,
-                                                      sin)) {
-                n_managers++;
+            if (stream_parse_target_with_default_port(target, OVSDB_OLD_PORT,
+                                                      &ss)
+                && ss.ss_family == AF_INET) {
+                managers[n_managers++] = *(struct sockaddr_in *) &ss;
             }
         }
     }
             }
         }
     }
index 797f330..e915caf 100644 (file)
           </dd>
           <dt><code>tcp:<var>ip</var></code>[<code>:<var>port</var></code>]</dt>
           <dd>
           </dd>
           <dt><code>tcp:<var>ip</var></code>[<code>:<var>port</var></code>]</dt>
           <dd>
-            <p>The specified TCP <var>port</var> on the host at the
-            given <var>ip</var>, which must be expressed as an IP
-            address (not a DNS name).</p>
-            <p>If <var>port</var> is not specified, it currently
-            defaults to 6633.  In the future, the default will change to
-            6653, which is the IANA-defined value.</p>
+            <p>
+              The specified TCP <var>port</var> on the host at the given
+              <var>ip</var>, which must be expressed as an IP address (not a
+              DNS name), where <var>ip</var> can be IPv4 or IPv6 address.  If
+              <var>ip</var> is an IPv6 address, wrap it in square brackets,
+              e.g. <code>tcp:[::1]:6632</code>.
+            </p>
+            <p>
+              If <var>port</var> is not specified, it currently defaults to
+              6633.  In the future, the default will change to 6653, which is
+              the IANA-defined value.
+            </p>
           </dd>
         </dl>
         <p>
           </dd>
         </dl>
         <p>
         <dl>
           <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
         <dl>
           <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
-            <p> Listens for SSL connections on the specified TCP
-            <var>port</var>.  If <var>ip</var>, which must be expressed
-            as an IP address (not a DNS name), is specified, then
-            connections are restricted to the specified local IP
-            address.  The <ref table="Open_vSwitch" column="ssl"/>
-            column in the <ref table="Open_vSwitch"/> table must point
-            to a valid SSL configuration when this form is used.</p>
-            <p>If <var>port</var> is not specified, it currently
-            defaults to 6633.  In the future, the default will change to
-            6653, which is the IANA-defined value.</p>
-            <p>SSL support is an optional feature that is not always built as
-            part of Open vSwitch.</p>
+            <p>
+              Listens for SSL connections on the specified TCP <var>port</var>.
+              If <var>ip</var>, which must be expressed as an IP address (not a
+              DNS name), is specified, then connections are restricted to the
+              specified local IP address (either IPv4 or IPv6).  If
+              <var>ip</var> is an IPv6 address, wrap it in square brackets,
+              e.g. <code>pssl:6632:[::1]</code>.
+            </p>
+            <p>
+              If <var>port</var> is not specified, it currently defaults to
+              6633.  If <var>ip</var> is not specified then it listens only on
+              IPv4 (but not IPv6) addresses.  The
+              <ref table="Open_vSwitch" column="ssl"/>
+              column in the <ref table="Open_vSwitch"/> table must point to a
+              valid SSL configuration when this form is used.
+            </p>
+            <p>
+              If <var>port</var> is not specified, it currently defaults to
+              6633.  In the future, the default will change to 6653, which is
+              the IANA-defined value.
+            </p>
+            <p>
+              SSL support is an optional feature that is not always built as
+              part of Open vSwitch.
+            </p>
           </dd>
           <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
           </dd>
           <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
-            <p>Listens for connections on the specified TCP
-            <var>port</var>.  If <var>ip</var>, which must be expressed
-            as an IP address (not a DNS name), is specified, then
-            connections are restricted to the specified local IP
-            address.</p>
-            <p>If <var>port</var> is not specified, it currently
-            defaults to 6633.  In the future, the default will change to
-            6653, which is the IANA-defined value.</p>
+            <p>
+              Listens for connections on the specified TCP <var>port</var>.  If
+              <var>ip</var>, which must be expressed as an IP address (not a
+              DNS name), is specified, then connections are restricted to the
+              specified local IP address (either IPv4 or IPv6).  If
+              <var>ip</var> is an IPv6 address, wrap it in square brackets,
+              e.g. <code>ptcp:6632:[::1]</code>. If <var>ip</var> is not
+              specified then it listens only on IPv4 addresses.
+            </p>
+            <p>
+              If <var>port</var> is not specified, it currently defaults to
+              6633.  In the future, the default will change to 6653, which is
+              the IANA-defined value.
+            </p>
           </dd>
         </dl>
         <p>When multiple controllers are configured for a single bridge, the
           </dd>
         </dl>
         <p>When multiple controllers are configured for a single bridge, the
           <dd>
             <p>
               The specified TCP <var>port</var> on the host at the given
           <dd>
             <p>
               The specified TCP <var>port</var> on the host at the given
-              <var>ip</var>, which must be expressed as an IP address
-              (not a DNS name).
+              <var>ip</var>, which must be expressed as an IP address (not a
+              DNS name), where <var>ip</var> can be IPv4 or IPv6 address.  If
+              <var>ip</var> is an IPv6 address, wrap it in square brackets,
+              e.g. <code>tcp:[::1]:6632</code>.
             </p>
             <p>
               If <var>port</var> is not specified, it currently defaults
             </p>
             <p>
               If <var>port</var> is not specified, it currently defaults
           <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
             <p>
           <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
             <p>
-              Listens for SSL connections on the specified TCP
-              <var>port</var>.  Specify 0 for <var>port</var> to have
-              the kernel automatically choose an available port.  If
-              <var>ip</var>, which must be expressed as an IP address
-              (not a DNS name), is specified, then connections are
-              restricted to the specified local IP address.  The <ref
-              table="Open_vSwitch" column="ssl"/> column in the <ref
+              Listens for SSL connections on the specified TCP <var>port</var>.
+              Specify 0 for <var>port</var> to have the kernel automatically
+              choose an available port.  If <var>ip</var>, which must be
+              expressed as an IP address (not a DNS name), is specified, then
+              connections are restricted to the specified local IP address
+              (either IPv4 or IPv6 address).  If <var>ip</var> is an IPv6
+              address, wrap in square brackets,
+              e.g. <code>pssl:6632:[::1]</code>.  If <var>ip</var> is not
+              specified then it listens only on IPv4 (but not IPv6) addresses.
+              The <ref table="Open_vSwitch" column="ssl"/> column in the <ref
               table="Open_vSwitch"/> table must point to a valid SSL
               configuration when this form is used.
             </p>
               table="Open_vSwitch"/> table must point to a valid SSL
               configuration when this form is used.
             </p>
           <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
             <p>
           <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
           <dd>
             <p>
-              Listens for connections on the specified TCP
-              <var>port</var>.  Specify 0 for <var>port</var> to have
-              the kernel automatically choose an available port.  If
-              <var>ip</var>, which must be expressed as an IP address
-              (not a DNS name), is specified, then connections are
-              restricted to the specified local IP address.
+              Listens for connections on the specified TCP <var>port</var>.
+              Specify 0 for <var>port</var> to have the kernel automatically
+              choose an available port.  If <var>ip</var>, which must be
+              expressed as an IP address (not a DNS name), is specified, then
+              connections are restricted to the specified local IP address
+              (either IPv4 or IPv6 address).  If <var>ip</var> is an IPv6
+              address, wrap it in square brackets,
+              e.g. <code>ptcp:6632:[::1]</code>.  If <var>ip</var> is not
+              specified then it listens only on IPv4 addresses.
             </p>
             <p>
               If <var>port</var> is not specified, it currently defaults
             </p>
             <p>
               If <var>port</var> is not specified, it currently defaults