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.nivg...@calsoftinc.com> Signed-off-by: Abhijit Bhopatkar <abhijit.bhopat...@calsoftinc.com> Signed-off-by: Arun Sharma <arun.sha...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev