[ovs-dev] [PATCH 1/3] lib: Add ipv6 support for active and passive socket connections
Arun Sharma
arun.sharma at calsoftinc.com
Mon Dec 9 12:21:21 UTC 2013
Allows all socket operations to use ipv6 network addresses,
except in-band control which is not supported for ipv6
Signed-off-by: Nandan Nivgune <nandan.nivgune at calsoftinc.com>
Signed-off-by: Abhijit Bhopatkar <abhijit.bhopatkar at calsoftinc.com>
Signed-off-by: Arun Sharma <arun.sharma at calsoftinc.com>
---
lib/packets.h | 12 +++
lib/rconn.c | 39 ++++++-
lib/rconn.h | 3 +
lib/socket-util.c | 235 ++++++++++++++++++++++++++++--------------
lib/socket-util.h | 9 +-
lib/stream-provider.h | 4 +
lib/stream-ssl.c | 85 +++++++++++----
lib/stream-tcp.c | 66 +++++++++---
lib/stream.c | 20 +++-
lib/stream.h | 2 +-
lib/vconn-provider.h | 6 +-
lib/vconn.c | 26 +++++
lib/vconn.h | 3 +
ofproto/connmgr.c | 9 +-
ofproto/ofproto-dpif-sflow.c | 26 +++--
python/ovs/socket_util.py | 36 +++++--
tests/test-sflow.c | 8 +-
vswitchd/bridge.c | 8 +-
18 files changed, 449 insertions(+), 148 deletions(-)
diff --git a/lib/packets.h b/lib/packets.h
index d291c14..4823806 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -367,6 +367,18 @@ mpls_lse_to_bos(ovs_be32 mpls_lse)
return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0;
}
+#define IP6_FMT "%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16":%"PRIx16 \
+ ":%"PRIx16":%"PRIx16":%"PRIx16
+#define IP6_ARGS(ip6) \
+ ntohs(ip6[0]), \
+ ntohs(ip6[1]), \
+ ntohs(ip6[2]), \
+ ntohs(ip6[3]), \
+ ntohs(ip6[4]), \
+ ntohs(ip6[5]), \
+ ntohs(ip6[6]), \
+ ntohs(ip6[7])
+
#define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32
#define IP_ARGS(ip) \
ntohl(ip) >> 24, \
diff --git a/lib/rconn.c b/lib/rconn.c
index f7f90f7..65a8d66 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -21,12 +21,14 @@
#include <stdlib.h>
#include <string.h>
#include "coverage.h"
+#include "jsonrpc.h"
#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "poll-loop.h"
#include "sat-math.h"
+#include "socket-util.h"
#include "timeval.h"
#include "util.h"
#include "vconn.h"
@@ -125,6 +127,7 @@ struct rconn {
* We don't cache the local port, because that changes from one connection
* attempt to the next. */
ovs_be32 local_ip, remote_ip;
+ struct in6_addr local_ip6, remote_ip6;
ovs_be16 remote_port;
uint8_t dscp;
@@ -448,22 +451,40 @@ reconnect(struct rconn *rc)
OVS_REQUIRES(rc->mutex)
{
int retval;
+ struct sockaddr_storage ss;
if (rconn_logging_connection_attempts__(rc)) {
VLOG_INFO("%s: connecting...", rc->name);
}
rc->n_attempted_connections++;
+ if (!strncmp(rc->target, "tcp:", 4) || (!strncmp(rc->target, "ssl:", 4))) {
+ if (!inet_parse_active(rc->target + 4, OVSDB_PORT, &ss)) {
+ VLOG_WARN("%s:failed to get address family", rc->name);
+ retval = -1;
+ goto exit;
+ }
+ }
+
retval = vconn_open(rc->target, rc->allowed_versions, rc->dscp,
&rc->vconn);
if (!retval) {
- rc->remote_ip = vconn_get_remote_ip(rc->vconn);
- rc->local_ip = vconn_get_local_ip(rc->vconn);
+ if (ss.ss_family == AF_INET) {
+ rc->remote_ip = vconn_get_remote_ip(rc->vconn);
+ rc->local_ip = vconn_get_local_ip(rc->vconn);
+ } else {
+ vconn_get_remote_ip6(rc->vconn, &rc->remote_ip6);
+ vconn_get_local_ip6(rc->vconn, &rc->local_ip6);
+ }
rc->remote_port = vconn_get_remote_port(rc->vconn);
rc->backoff_deadline = time_now() + rc->backoff;
state_transition(rc, S_CONNECTING);
} else {
VLOG_WARN("%s: connection failed (%s)",
rc->name, ovs_strerror(retval));
+ }
+
+exit:
+ if (retval) {
rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
disconnect(rc, retval);
}
@@ -958,6 +979,20 @@ rconn_get_version__(const struct rconn *rconn)
return rconn->vconn ? vconn_get_version(rconn->vconn) : -1;
}
+/* Copies the IP address used to connect to the peer into 'ip'. */
+void
+rconn_get_remote_ip6(struct rconn *rconn, struct in6_addr *ip)
+{
+ memcpy(ip, &rconn->remote_ip6, sizeof rconn->remote_ip6);
+}
+
+/* Copies the IP address used to connect to the peer into 'ip'. */
+void
+rconn_get_local_ip6(struct rconn *rconn, struct in6_addr *ip)
+{
+ memcpy(ip, &rconn->local_ip6, sizeof rconn->local_ip6);
+}
+
/* Returns the OpenFlow version negotiated with the peer, or -1 if there is
* currently no connection or if version negotiation is not yet complete. */
int
diff --git a/lib/rconn.h b/lib/rconn.h
index 408cec9..5e64c14 100644
--- a/lib/rconn.h
+++ b/lib/rconn.h
@@ -17,6 +17,7 @@
#ifndef RCONN_H
#define RCONN_H 1
+#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
@@ -87,6 +88,8 @@ ovs_be32 rconn_get_remote_ip(const struct rconn *);
ovs_be16 rconn_get_remote_port(const struct rconn *);
ovs_be32 rconn_get_local_ip(const struct rconn *);
ovs_be16 rconn_get_local_port(const struct rconn *);
+void rconn_get_remote_ip6(struct rconn *, struct in6_addr *remote_ip);
+void rconn_get_local_ip6(struct rconn *, struct in6_addr *local_ip);
int rconn_get_version(const struct rconn *);
const char *rconn_get_state(const struct rconn *);
diff --git a/lib/socket-util.c b/lib/socket-util.c
index bb48ade..1d8a8e3 100644
--- a/lib/socket-util.c
+++ b/lib/socket-util.c
@@ -67,6 +67,11 @@ VLOG_DEFINE_THIS_MODULE(socket_util);
static int getsockopt_int(int fd, int level, int option, const char *optname,
int *valuep);
+static int do_getaddrinfo(const char *host, const char *port,
+ struct sockaddr_storage *ssp);
+
+static void parse_active(char *target, const char **host, const char **port);
+
/* Sets 'fd' to non-blocking mode. Returns 0 if successful, otherwise a
* positive errno value. */
int
@@ -616,38 +621,34 @@ guess_netmask(ovs_be32 ip_)
* <host> is required. 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 '*sinp'.
- * On failure, logs an error, stores zeros into '*sinp', and returns false. */
+ * On success, returns true and stores the parsed remote address into '*ssp'.
+ * On failure, logs an error, stores zeros into '*ssp', and returns false. */
bool
inet_parse_active(const char *target_, uint16_t default_port,
- struct sockaddr_in *sinp)
+ struct sockaddr_storage *ssp)
{
char *target = xstrdup(target_);
- char *save_ptr = NULL;
+ char *save_ptr = target;
const char *host_name;
const char *port_string;
+ char default_port_str[6] = {'\0'};
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);
+ /* Parse IP address and port. */
+ parse_active(target, &host_name, &port_string);
if (!host_name) {
- VLOG_ERR("%s: bad peer name format", target_);
- goto exit;
+ VLOG_ERR("%s: bad peer name format", target_);
+ goto exit;
}
-
- /* Look up IP, port. */
- if (lookup_ip(host_name, &sinp->sin_addr)) {
- goto exit;
+ if (port_string == NULL) {
+ if (!default_port) {
+ VLOG_ERR("%s: port number must be specified", target_);
+ goto exit;
+ }
+ sprintf(default_port_str, "%d", default_port);
+ port_string = default_port_str;
}
- 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_);
+ if (do_getaddrinfo(host_name, port_string, ssp) == -1) {
goto exit;
}
@@ -655,16 +656,16 @@ inet_parse_active(const char *target_, uint16_t default_port,
exit:
if (!ok) {
- memset(sinp, 0, sizeof *sinp);
+ memset(ssp, 0, sizeof *ssp);
}
- free(target);
+ free(save_ptr);
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> is required. 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).
*
@@ -673,28 +674,29 @@ exit:
* 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 'ssp' is non-null, then on success the target address is stored into
+ * '*ssp'.
*
* '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 sstorage;
int fd = -1;
int error;
+ socklen_t addrlen;
/* Parse. */
- if (!inet_parse_active(target, default_port, &sin)) {
+ if (!inet_parse_active(target, default_port, &sstorage)) {
error = EAFNOSUPPORT;
goto exit;
}
/* Create non-blocking socket. */
- fd = socket(AF_INET, style, 0);
+ fd = socket(sstorage.ss_family, style, 0);
if (fd < 0) {
VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
error = errno;
@@ -714,16 +716,24 @@ inet_open_active(int style, const char *target, uint16_t default_port,
goto exit;
}
+ if (sstorage.ss_family == AF_INET) {
+ addrlen = sizeof (struct sockaddr_in);
+ } else {
+ addrlen = sizeof (struct sockaddr_in6);
+ }
+
/* Connect. */
- error = connect(fd, (struct sockaddr *) &sin, sizeof sin) == 0 ? 0 : errno;
+ error = connect(fd, (struct sockaddr *) &sstorage, addrlen) == 0
+ ? 0
+ : errno;
if (error == EINPROGRESS) {
error = EAGAIN;
}
exit:
if (!error || error == EAGAIN) {
- if (sinp) {
- *sinp = sin;
+ if (ssp) {
+ *ssp = sstorage;
}
} else if (fd >= 0) {
close(fd);
@@ -743,37 +753,33 @@ exit:
*
* - If <ip> is omitted then 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 '*ssp' and returns true; otherwise
+ * zeros '*ssp' and returns false. */
bool
inet_parse_passive(const char *target_, int default_port,
- struct sockaddr_in *sinp)
+ struct sockaddr_storage *ssp)
{
char *target = xstrdup(target_);
char *string_ptr = target;
const char *host_name;
const char *port_string;
+ char default_port_str[8] = {'\0'};
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);
+ memset(ssp, 0, sizeof *ssp);
- /* 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;
+ host_name = string_ptr;
+ if (port_string == NULL) {
+ if (default_port == -1) {
+ VLOG_ERR("%s: port number must be specified", target_);
+ goto exit;
+ }
+ sprintf(default_port_str, "%d", default_port);
+ port_string = default_port_str;
}
- /* Parse optional bind IP. */
- host_name = strsep(&string_ptr, ":");
- if (host_name && host_name[0] && lookup_ip(host_name, &sinp->sin_addr)) {
+ if (do_getaddrinfo(host_name, port_string, ssp) == -1) {
goto exit;
}
@@ -781,14 +787,14 @@ inet_parse_passive(const char *target_, int default_port,
exit:
if (!ok) {
- memset(sinp, 0, sizeof *sinp);
+ memset(ssp, 0, sizeof *ssp);
}
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().
*
@@ -799,27 +805,31 @@ exit:
* 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 'ssp' is non-null, then on success the bound address is stored into
+ * '*ssp'.
*
* '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;
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sin_p;
+ struct sockaddr_in6 *sin6_p;
+ in_port_t port;
int fd = 0, error;
unsigned int yes = 1;
+ socklen_t addrlen;
- if (!inet_parse_passive(target, default_port, &sin)) {
+ if (!inet_parse_passive(target, default_port, &ss)) {
return -EAFNOSUPPORT;
}
/* 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));
@@ -837,8 +847,19 @@ inet_open_passive(int style, const char *target, int default_port,
goto error;
}
+ if (ss.ss_family == AF_INET) {
+ sin_p = (struct sockaddr_in *) &ss;
+ addrlen = sizeof (struct sockaddr_in);
+ port = sin_p->sin_port;
+ } else {
+ sin6_p = (struct sockaddr_in6 *) &ss;
+ addrlen = sizeof (struct sockaddr_in6);
+ port = sin6_p->sin6_port;
+ }
+
+ kernel_chooses_port = port == htons(0);
/* Bind. */
- if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
+ if (bind(fd, (struct sockaddr *) &ss, addrlen) < 0) {
error = errno;
VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
goto error;
@@ -860,25 +881,20 @@ inet_open_passive(int style, const char *target, int default_port,
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 sin_len = addrlen;
+ if (getsockname(fd, (struct sockaddr *) &ss, &sin_len) < 0) {
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 (ssp) {
+ *ssp = ss;
}
+ sin_p = (struct sockaddr_in *) &ss;
if (kernel_chooses_port) {
VLOG_INFO("%s: listening on port %"PRIu16,
- target, ntohs(sin.sin_port));
+ target, ntohs(sin_p->sin_port));
}
}
@@ -1060,6 +1076,68 @@ getsockopt_int(int fd, int level, int option, const char *optname, int *valuep)
return error;
}
+/* Wrapper for getaddrinfo(). On success, 0 is returnd else -1 is returned for
+ * in error. If 'res' is not NULL, output address list is paased to caller. */
+static int
+do_getaddrinfo(const char *host, const char *port,
+ struct sockaddr_storage *ssp)
+{
+ struct addrinfo hint;
+ struct addrinfo *info;
+ struct addrinfo *addr;
+ int ret;
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_flags = AI_PASSIVE;
+ hint.ai_canonname = NULL;
+ hint.ai_addr = NULL;
+ hint.ai_next = NULL;
+
+ ret = getaddrinfo(host, port, &hint, &info);
+ if (ret) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_ERR_RL(&rl, "\"%s\" is not a valid IP address", host);
+ return -1;
+ }
+
+ for (addr = info; addr != NULL; addr = addr->ai_next) {
+ memcpy(ssp, addr->ai_addr, addr->ai_addrlen);
+ break;
+ }
+ if (addr == NULL) {
+ ret = -1;
+ }
+ if (info) {
+ freeaddrinfo(info);
+ }
+
+ return ret;
+}
+
+/* Parse IP address and port from string 'itarget'.
+ * If 'host' and 'port' are not NULL, parsed string values are stored in
+ * them. */
+static void
+parse_active(char *itarget, const char **host, const char **port)
+{
+ char *ptr = NULL;
+ char *start_ptr = itarget;
+
+ while (*itarget != '\0') {
+ if (*itarget == ':') {
+ ptr = itarget;
+ }
+ itarget++;
+ }
+ if (host && port) {
+ *port = ++ptr;
+ *(--ptr) = '\0';
+ *host = start_ptr;
+ }
+}
+
static void
describe_sockaddr(struct ds *string, int fd,
int (*getaddr)(int, struct sockaddr *, socklen_t *))
@@ -1074,6 +1152,13 @@ describe_sockaddr(struct ds *string, int fd,
memcpy(&sin, &ss, sizeof sin);
ds_put_format(string, IP_FMT":%"PRIu16,
IP_ARGS(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+ } else if (ss.ss_family == AF_INET6) {
+ struct sockaddr_in6 sin6;
+
+ memcpy(&sin6, &ss, sizeof sin6);
+ ds_put_format(string, IP6_FMT":%"PRIu16,
+ IP6_ARGS(sin6.sin6_addr.s6_addr16),
+ ntohs(sin6.sin6_port));
} else if (ss.ss_family == AF_UNIX) {
struct sockaddr_un sun;
const char *null;
diff --git a/lib/socket-util.h b/lib/socket-util.h
index 670eeb3..13e66fd 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -25,6 +25,7 @@
#include "openvswitch/types.h"
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+#include <netdb.h>
int set_nonblocking(int fd);
void xset_nonblocking(int fd);
@@ -48,14 +49,14 @@ ovs_be32 guess_netmask(ovs_be32 ip);
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,
- 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,
- struct sockaddr_in *sinp);
+ struct sockaddr_storage *ssp);
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);
diff --git a/lib/stream-provider.h b/lib/stream-provider.h
index 43c63e8..7e7092d 100644
--- a/lib/stream-provider.h
+++ b/lib/stream-provider.h
@@ -33,14 +33,18 @@ struct stream {
ovs_be16 remote_port;
ovs_be32 local_ip;
ovs_be16 local_port;
+ struct in6_addr remote_ip6;
+ struct in6_addr local_ip6;
char *name;
};
void stream_init(struct stream *, const struct stream_class *,
int connect_status, const char *name);
void stream_set_remote_ip(struct stream *, ovs_be32 remote_ip);
+void stream_set_remote_ip6(struct stream *, struct in6_addr ip);
void stream_set_remote_port(struct stream *, ovs_be16 remote_port);
void stream_set_local_ip(struct stream *, ovs_be32 local_ip);
+void stream_set_local_ip6(struct stream *, struct in6_addr ip);
void stream_set_local_port(struct stream *, ovs_be16 local_port);
static inline void stream_assert_class(const struct stream *stream,
const struct stream_class *class)
diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c
index f2bd513..78034e3 100644
--- a/lib/stream-ssl.c
+++ b/lib/stream-ssl.c
@@ -204,10 +204,12 @@ want_to_poll_events(int want)
static int
new_ssl_stream(const char *name, int fd, enum session_type type,
- enum ssl_state state, const struct sockaddr_in *remote,
+ enum ssl_state state, const struct sockaddr_storage *remote,
struct stream **streamp)
{
- struct sockaddr_in local;
+ struct sockaddr_storage local;
+ struct sockaddr_in *local_in;
+ struct sockaddr_in6 *local_in6;
socklen_t local_len = sizeof local;
struct ssl_stream *sslv;
SSL *ssl = NULL;
@@ -270,10 +272,25 @@ new_ssl_stream(const char *name, int fd, enum session_type type,
/* Create and return the ssl_stream. */
sslv = xmalloc(sizeof *sslv);
stream_init(&sslv->stream, &ssl_stream_class, EAGAIN, name);
- stream_set_remote_ip(&sslv->stream, remote->sin_addr.s_addr);
- stream_set_remote_port(&sslv->stream, remote->sin_port);
- stream_set_local_ip(&sslv->stream, local.sin_addr.s_addr);
- stream_set_local_port(&sslv->stream, local.sin_port);
+
+ if (remote->ss_family == AF_INET) {
+ struct sockaddr_in *remote_in = (struct sockaddr_in *) remote;
+ stream_set_remote_ip(&sslv->stream, remote_in->sin_addr.s_addr);
+ stream_set_remote_port(&sslv->stream, remote_in->sin_port);
+ } else {
+ struct sockaddr_in6 *remote_in6 = (struct sockaddr_in6 *) remote;
+ stream_set_remote_ip6(&sslv->stream, remote_in6->sin6_addr);
+ stream_set_remote_port(&sslv->stream, remote_in6->sin6_port);
+ }
+ if (local.ss_family == AF_INET) {
+ local_in = (struct sockaddr_in *) &local;
+ stream_set_local_ip(&sslv->stream, local_in->sin_addr.s_addr);
+ stream_set_local_port(&sslv->stream, local_in->sin_port);
+ } else {
+ local_in6 = (struct sockaddr_in6 *) &local;
+ stream_set_local_ip6(&sslv->stream, local_in6->sin6_addr);
+ stream_set_local_port(&sslv->stream, local_in6->sin6_port);
+ }
sslv->state = state;
sslv->type = type;
sslv->fd = fd;
@@ -309,7 +326,7 @@ ssl_stream_cast(struct stream *stream)
static int
ssl_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
{
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
int error, fd;
error = ssl_init();
@@ -317,11 +334,11 @@ ssl_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
return error;
}
- error = inet_open_active(SOCK_STREAM, suffix, OFP_OLD_PORT, &sin, &fd,
+ error = inet_open_active(SOCK_STREAM, suffix, OFP_OLD_PORT, &ss, &fd,
dscp);
if (fd >= 0) {
int state = error ? STATE_TCP_CONNECTING : STATE_SSL_CONNECTING;
- return new_ssl_stream(name, fd, CLIENT, state, &sin, streamp);
+ return new_ssl_stream(name, fd, CLIENT, state, &ss, streamp);
} else {
VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
return error;
@@ -787,7 +804,8 @@ pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp)
{
struct pssl_pstream *pssl;
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ in_port_t port;
char bound_name[128];
int retval;
int fd;
@@ -797,16 +815,29 @@ pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
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;
}
- sprintf(bound_name, "pssl:%"PRIu16":"IP_FMT,
- ntohs(sin.sin_port), IP_ARGS(sin.sin_addr.s_addr));
+
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin_addr = (struct sockaddr_in *) &ss;
+
+ port = sin_addr->sin_port;
+ sprintf(bound_name, "pssl:%"PRIu16":"IP_FMT,
+ ntohs(port), IP_ARGS(sin_addr->sin_addr.s_addr));
+ } else {
+ struct sockaddr_in6 *sin_addr6 = (struct sockaddr_in6 *) &ss;
+
+ port = sin_addr6->sin6_port;
+ sprintf(bound_name, "pssl:%"PRIu16":"IP6_FMT,
+ ntohs(port),
+ IP6_ARGS(sin_addr6->sin6_addr.s6_addr16));
+ }
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, port);
pssl->fd = fd;
*pstreamp = &pssl->pstream;
return 0;
@@ -824,13 +855,13 @@ static int
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;
+ struct sockaddr_storage ss;
+ socklen_t sin_len = sizeof ss;
char name[128];
int new_fd;
int error;
- new_fd = accept(pssl->fd, (struct sockaddr *) &sin, &sin_len);
+ new_fd = accept(pssl->fd, (struct sockaddr *) &ss, &sin_len);
if (new_fd < 0) {
error = errno;
if (error != EAGAIN) {
@@ -845,11 +876,23 @@ pssl_accept(struct pstream *pstream, struct stream **new_streamp)
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));
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin_addr = (struct sockaddr_in *) &ss;
+
+ sprintf(name, "ssl:"IP_FMT, IP_ARGS(sin_addr->sin_addr.s_addr));
+ if (sin_addr->sin_port != htons(OFP_OLD_PORT)) {
+ sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin_addr->sin_port));
+ }
+ } else {
+ struct sockaddr_in6 *sin_addr6 = (struct sockaddr_in6 *) &ss;
+
+ sprintf(name, "ssl:"IP6_FMT, IP6_ARGS(sin_addr6->sin6_addr.s6_addr16));
+ if (sin_addr6->sin6_port != htons(OFP_OLD_PORT)) {
+ sprintf(strchr(name, '\0'), ":%"PRIu16,
+ ntohs(sin_addr6->sin6_port));
+ }
}
- return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING, &sin,
+ return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING, &ss,
new_streamp);
}
diff --git a/lib/stream-tcp.c b/lib/stream-tcp.c
index a4cdf45..6445625 100644
--- a/lib/stream-tcp.c
+++ b/lib/stream-tcp.c
@@ -21,6 +21,7 @@
#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>
@@ -38,9 +39,11 @@ VLOG_DEFINE_THIS_MODULE(stream_tcp);
static int
new_tcp_stream(const char *name, int fd, int connect_status,
- const struct sockaddr_in *remote, struct stream **streamp)
+ const struct sockaddr_storage *remote, struct stream **streamp)
{
- struct sockaddr_in local;
+ struct sockaddr_storage local;
+ struct sockaddr_in *addr_in;
+ struct sockaddr_in6 *addr_in6;
socklen_t local_len = sizeof local;
int on = 1;
int retval;
@@ -61,10 +64,25 @@ new_tcp_stream(const char *name, int fd, int connect_status,
retval = new_fd_stream(name, fd, connect_status, streamp);
if (!retval) {
struct stream *stream = *streamp;
- stream_set_remote_ip(stream, remote->sin_addr.s_addr);
- stream_set_remote_port(stream, remote->sin_port);
- stream_set_local_ip(stream, local.sin_addr.s_addr);
- stream_set_local_port(stream, local.sin_port);
+
+ if (remote->ss_family == AF_INET) {
+ addr_in = (struct sockaddr_in *) remote;
+ stream_set_remote_ip(stream, addr_in->sin_addr.s_addr);
+ stream_set_remote_port(stream, addr_in->sin_port);
+ } else {
+ addr_in6 = (struct sockaddr_in6 *) remote;
+ stream_set_remote_ip6(stream, addr_in6->sin6_addr);
+ stream_set_remote_port(stream, addr_in6->sin6_port);
+ }
+ if (local.ss_family == AF_INET) {
+ addr_in = (struct sockaddr_in *) &local;
+ stream_set_local_ip(stream, addr_in->sin_addr.s_addr);
+ stream_set_local_port(stream, addr_in->sin_port);
+ } else {
+ addr_in6 = (struct sockaddr_in6 *) &local;
+ stream_set_local_ip6(stream, addr_in6->sin6_addr);
+ stream_set_local_port(stream, addr_in6->sin6_port);
+ }
}
return retval;
}
@@ -72,12 +90,12 @@ new_tcp_stream(const char *name, int fd, int connect_status,
static int
tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
{
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
int fd, error;
- error = inet_open_active(SOCK_STREAM, suffix, 0, &sin, &fd, dscp);
+ error = inet_open_active(SOCK_STREAM, suffix, 0, &ss, &fd, dscp);
if (fd >= 0) {
- return new_tcp_stream(name, fd, error, &sin, streamp);
+ return new_tcp_stream(name, fd, error, &ss, streamp);
} else {
VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
return error;
@@ -106,22 +124,33 @@ static int
ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp)
{
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ in_port_t port;
char bound_name[128];
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;
}
- sprintf(bound_name, "ptcp:%"PRIu16":"IP_FMT,
- ntohs(sin.sin_port), IP_ARGS(sin.sin_addr.s_addr));
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin_addr = (struct sockaddr_in *) &ss;
+ port = sin_addr->sin_port;
+ sprintf(bound_name, "ptcp:%"PRIu16":"IP_FMT,
+ ntohs(sin_addr->sin_port), IP_ARGS(sin_addr->sin_addr.s_addr));
+ } else {
+ struct sockaddr_in6 *sin_addr6 = (struct sockaddr_in6 *) &ss;
+ port = sin_addr6->sin6_port;
+ sprintf(bound_name, "ptcp:%"PRIu16":"IP6_FMT,
+ ntohs(sin_addr6->sin6_port),
+ IP6_ARGS(sin_addr6->sin6_addr.s6_addr16));
+ }
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, port);
}
return error;
}
@@ -137,10 +166,13 @@ ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
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");
+ } else if (sa_len == sizeof(struct sockaddr_in6)) {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) sa;
+ sprintf(name, "tcp:"IP6_FMT, IP6_ARGS(sin6->sin6_addr.s6_addr16));
+ sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port));
}
- return new_tcp_stream(name, fd, 0, sin, streamp);
+ return new_tcp_stream(name, fd, 0, (struct sockaddr_storage *) sa,
+ streamp);
}
const struct pstream_class ptcp_pstream_class = {
diff --git a/lib/stream.c b/lib/stream.c
index 0442d84..227cd0d 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -687,6 +687,18 @@ stream_set_local_port(struct stream *stream, ovs_be16 port)
}
void
+stream_set_remote_ip6(struct stream *stream, struct in6_addr ip)
+{
+ memcpy(&stream->remote_ip6, &ip, sizeof ip);
+}
+
+void
+stream_set_local_ip6(struct stream *stream, struct in6_addr ip)
+{
+ memcpy(&stream->local_ip6, &ip, sizeof ip);
+}
+
+void
pstream_init(struct pstream *pstream, const struct pstream_class *class,
const char *name)
{
@@ -776,18 +788,18 @@ pstream_open_with_default_port(const char *name_,
/*
* 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.
- * - 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,
- struct sockaddr_in *sin)
+ struct sockaddr_storage *ss)
{
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
diff --git a/lib/stream.h b/lib/stream.h
index d966cde..3780ff9 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -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,
- struct sockaddr_in *sin);
+ struct sockaddr_storage *ss);
int stream_or_pstream_needs_probes(const char *name);
/* Error reporting. */
diff --git a/lib/vconn-provider.h b/lib/vconn-provider.h
index 640c5b6..1e628ae 100644
--- a/lib/vconn-provider.h
+++ b/lib/vconn-provider.h
@@ -19,7 +19,7 @@
/* Provider interface to vconns, which provide a virtual connection to an
* OpenFlow device. */
-
+#include <netdb.h>
#include "vconn.h"
#include "util.h"
#include "openflow/openflow-common.h"
@@ -44,6 +44,8 @@ struct vconn {
ovs_be16 remote_port;
ovs_be32 local_ip;
ovs_be16 local_port;
+ struct in6_addr remote_ip6;
+ struct in6_addr local_ip6;
char *name;
};
@@ -52,8 +54,10 @@ void vconn_init(struct vconn *, const struct vconn_class *, int connect_status,
const char *name, uint32_t allowed_versions);
void vconn_free_data(struct vconn *vconn);
void vconn_set_remote_ip(struct vconn *, ovs_be32 remote_ip);
+void vconn_set_remote_ip6(struct vconn *, struct in6_addr remote_ip);
void vconn_set_remote_port(struct vconn *, ovs_be16 remote_port);
void vconn_set_local_ip(struct vconn *, ovs_be32 local_ip);
+void vconn_set_local_ip6(struct vconn *, struct in6_addr local_ip);
void vconn_set_local_port(struct vconn *, ovs_be16 local_port);
static inline void vconn_assert_class(const struct vconn *vconn,
const struct vconn_class *class)
diff --git a/lib/vconn.c b/lib/vconn.c
index 5708987..7a363d1 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -375,6 +375,20 @@ vconn_get_local_ip(const struct vconn *vconn)
return vconn->local_ip;
}
+/* Copies the IP address used to connect to the peer into 'ip'. */
+void
+vconn_get_remote_ip6(struct vconn *vconn, struct in6_addr *ip)
+{
+ memcpy(ip, &vconn->remote_ip6, sizeof vconn->remote_ip6);
+}
+
+/* Copies the IP address used to connect to the peer into 'ip'. */
+void
+vconn_get_local_ip6(struct vconn *vconn, struct in6_addr *ip)
+{
+ memcpy(ip, &vconn->local_ip6, sizeof vconn->local_ip6);
+}
+
/* Returns the transport port used to connect to the peer, or 0 if the
* connection does not contain a port or if the port is not yet known. */
ovs_be16
@@ -1148,6 +1162,18 @@ vconn_set_local_port(struct vconn *vconn, ovs_be16 port)
}
void
+vconn_set_local_ip6(struct vconn *vconn, struct in6_addr ip)
+{
+ memcpy(&vconn->local_ip6, &ip, sizeof ip);
+}
+
+void
+vconn_set_remote_ip6(struct vconn *vconn, struct in6_addr ip)
+{
+ memcpy(&vconn->remote_ip6, &ip, sizeof ip);
+}
+
+void
pvconn_init(struct pvconn *pvconn, const struct pvconn_class *class,
const char *name, uint32_t allowed_versions)
{
diff --git a/lib/vconn.h b/lib/vconn.h
index b15388c..8c8afe4 100644
--- a/lib/vconn.h
+++ b/lib/vconn.h
@@ -17,6 +17,7 @@
#ifndef VCONN_H
#define VCONN_H 1
+#include <netdb.h>
#include <stdbool.h>
#include "openvswitch/types.h"
#include "openflow/openflow.h"
@@ -49,6 +50,8 @@ ovs_be32 vconn_get_remote_ip(const struct vconn *);
ovs_be16 vconn_get_remote_port(const struct vconn *);
ovs_be32 vconn_get_local_ip(const struct vconn *);
ovs_be16 vconn_get_local_port(const struct vconn *);
+void vconn_get_remote_ip6(struct vconn *vconn, struct in6_addr *ip);
+void vconn_get_local_ip6(struct vconn *vconn, struct in6_addr *ip);
int vconn_connect(struct vconn *);
int vconn_recv(struct vconn *, struct ofpbuf **);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index da25930..b632222 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -734,6 +734,7 @@ update_in_band_remotes(struct connmgr *mgr)
/* Add all the remotes. */
HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) {
struct sockaddr_in *sin = &addrs[n_addrs];
+ struct sockaddr_storage sstorage;
const char *target = rconn_get_target(ofconn->rconn);
if (ofconn->band == OFPROTO_OUT_OF_BAND) {
@@ -742,8 +743,12 @@ update_in_band_remotes(struct connmgr *mgr)
if (stream_parse_target_with_default_port(target,
OFP_OLD_PORT,
- sin)) {
- n_addrs++;
+ &sstorage)) {
+ if (sstorage.ss_family == AF_INET) {
+ /* Allow only IPv4 Address for in-band. */
+ n_addrs++;
+ memcpy(sin, &sstorage, sizeof *sin);
+ }
}
}
for (i = 0; i < mgr->n_extra_remotes; i++) {
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 158887f..1028ca4 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -242,6 +242,7 @@ sflow_choose_agent_address(const char *agent_device,
{
const char *target;
struct in_addr in4;
+ struct sockaddr_storage ss;
memset(agent_addr, 0, sizeof *agent_addr);
agent_addr->type = SFLADDRESSTYPE_IP_V4;
@@ -253,13 +254,18 @@ sflow_choose_agent_address(const char *agent_device,
}
SSET_FOR_EACH (target, targets) {
- struct sockaddr_in sin;
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)) {
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *tsin = (struct sockaddr_in *) &ss;
+ if (route_table_get_name(tsin->sin_addr.s_addr, name)
+ && !netdev_get_in4_by_name(name, &in4)) {
+ goto success;
+ }
+ } else if (ss.ss_family == AF_INET6) {
+ goto success;
+ }
}
}
@@ -271,7 +277,15 @@ sflow_choose_agent_address(const char *agent_device,
return false;
success:
- agent_addr->address.ip_v4.addr = (OVS_FORCE uint32_t) in4.s_addr;
+ if (ss.ss_family == AF_INET) {
+ agent_addr->address.ip_v4.addr = (OVS_FORCE uint32_t) in4.s_addr;
+ } else if (ss.ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
+
+ memcpy(agent_addr->address.ip_v6.addr, sin6->sin6_addr.s6_addr16,
+ sizeof sin6->sin6_addr);
+ agent_addr->type = SFLADDRESSTYPE_IP_V6;
+ }
return true;
}
diff --git a/python/ovs/socket_util.py b/python/ovs/socket_util.py
index c657047..ff2a79c 100644
--- a/python/ovs/socket_util.py
+++ b/python/ovs/socket_util.py
@@ -177,24 +177,44 @@ def check_connection_completion(sock):
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(":")
- host_name = address[0]
- if not host_name:
- raise ValueError("%s: bad peer name format" % target)
if len(address) >= 2:
- port = int(address[1])
- elif default_port:
- port = default_port
+ host_name = ":".join(address[0:-1])
+ port = int(address[-1])
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:
- 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
diff --git a/tests/test-sflow.c b/tests/test-sflow.c
index cba01b9..2d830d8 100644
--- a/tests/test-sflow.c
+++ b/tests/test-sflow.c
@@ -325,12 +325,10 @@ process_datagram(struct sflow_xdr *x)
/* Store the agent address as a string. */
if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
+ ovs_be16 *addr=(ovs_be16 *) &x->agentAddr.a.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]);
+ IP6_FMT, IP6_ARGS(addr));
} else {
snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index c2307be..578df5d 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -473,11 +473,15 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg,
managers = xmalloc(sset_count(&targets) * sizeof *managers);
SSET_FOR_EACH (target, &targets) {
struct sockaddr_in *sin = &managers[n_managers];
+ struct sockaddr_storage sstorage;
if (stream_parse_target_with_default_port(target,
OVSDB_OLD_PORT,
- sin)) {
- n_managers++;
+ &sstorage)) {
+ if (sstorage.ss_family == AF_INET) {
+ n_managers++;
+ memcpy(sin, &sstorage, sizeof *sin);
+ }
}
}
}
--
1.7.10.4
More information about the dev
mailing list