2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-01 23:05:29 +00:00

Add IPv6 support for OpenFlow, OVSDB, NetFlow, and sFlow.

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>
This commit is contained in:
Arun Sharma
2014-02-06 16:04:05 -08:00
committed by Ben Pfaff
parent 978188b242
commit e731d71bf4
26 changed files with 773 additions and 443 deletions

1
NEWS
View File

@@ -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 hard limit on the number of flows in the datapath. It defaults to 200,000
flows. OVS automatically adjusts this number depending on network flows. OVS automatically adjusts this number depending on network
conditions. conditions.
- Added IPv6 support for active and passive socket communications.
v2.0.0 - 15 Oct 2013 v2.0.0 - 15 Oct 2013

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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_IP 0
#define IPPROTO_HOPOPTS 0 #define IPPROTO_HOPOPTS 0
#define IPPROTO_ICMP 1 #define IPPROTO_ICMP 1
@@ -84,6 +93,7 @@ extern const struct in6_addr in6addr_any;
#define INADDR_ANY 0x00000000 #define INADDR_ANY 0x00000000
#define INADDR_BROADCAST 0xffffffff #define INADDR_BROADCAST 0xffffffff
#define INADDR_LOOPBACK 0x7f000001
#define INADDR_NONE 0xffffffff #define INADDR_NONE 0xffffffff
#define INET6_ADDRSTRLEN 46 #define INET6_ADDRSTRLEN 46

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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>]". /* This is like strsep() except:
* <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'. * - The separator string is ":".
* On failure, logs an error, stores zeros into '*sinp', and returns false. */ *
bool * - Square brackets [] quote ":" separators and are removed from the
inet_parse_active(const char *target_, uint16_t default_port, * tokens. */
struct sockaddr_in *sinp) static char *
parse_bracketed_token(char **pp)
{ {
char *target = xstrdup(target_); char *p = *pp;
char *save_ptr = NULL;
const char *host_name;
const char *port_string;
bool ok = false;
/* Defaults. */ if (p == NULL) {
sinp->sin_family = AF_INET; return NULL;
sinp->sin_port = htons(default_port); } 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;
}
}
/* Tokenize. */ static bool
host_name = strtok_r(target, ":", &save_ptr); parse_sockaddr_components(struct sockaddr_storage *ss,
port_string = strtok_r(NULL, ":", &save_ptr); const char *host_s,
if (!host_name) { const char *port_s, uint16_t default_port,
VLOG_ERR("%s: bad peer name format", target_); const char *s)
goto exit; {
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;
} }
/* Look up IP, port. */ memset(ss, 0, sizeof *ss);
if (lookup_ip(host_name, &sinp->sin_addr)) { if (strchr(host_s, ':')) {
goto exit; struct sockaddr_in6 *sin6
} = ALIGNED_CAST(struct sockaddr_in6 *, ss);
if (port_string && atoi(port_string)) {
sinp->sin_port = htons(atoi(port_string)); sin6->sin6_family = AF_INET6;
} else if (!default_port) { sin6->sin6_port = htons(port);
VLOG_ERR("%s: port number must be specified", target_); if (!inet_pton(AF_INET6, host_s, sin6->sin6_addr.s6_addr)) {
goto exit; 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); free(target);
return ok; 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> /* Opens a non-blocking IPv4 or IPv6 socket of the specified 'style' and
* is required. If 'default_port' is nonzero then <port> is optional and * connects to 'target', which should be a string in the format
* defaults to 'default_port'. * "<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 * into '*fdp'. On failure, returns a positive errno value other than EAGAIN
* and stores -1 into '*fdp'. * and stores -1 into '*fdp'.
* *
* If 'sinp' is non-null, then on success the target address is stored into * If 'ss' is non-null, then on success stores the target address into '*ss'.
* '*sinp'.
* *
* 'dscp' becomes the DSCP bits in the IP headers for the new connection. It * '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 * should be in the range [0, 63] and will automatically be shifted to the
* appropriately place in the IP tos field. */ * appropriately place in the IP tos field. */
int int
inet_open_active(int style, const char *target, uint16_t default_port, 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 fd = -1;
int error; int error;
/* Parse. */ /* Parse. */
if (!inet_parse_active(target, default_port, &sin)) { if (!inet_parse_active(target, default_port, &ss)) {
error = EAFNOSUPPORT; error = EAFNOSUPPORT;
goto exit; goto exit;
} }
/* Create non-blocking socket. */ /* Create non-blocking socket. */
fd = socket(AF_INET, style, 0); fd = socket(ss.ss_family, style, 0);
if (fd < 0) { if (fd < 0) {
VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno)); VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
error = 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 /* The dscp bits must be configured before connect() to ensure that the
* field is set during the connection establishment. If set after * TOS field is set during the connection establishment. If set after
* connect(), the handshake SYN frames will be sent with a TOS of 0. */ * connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp); error = set_dscp(fd, dscp);
if (error) { 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) { if (error == EINPROGRESS) {
error = EAGAIN; error = EAGAIN;
} }
exit: exit:
if (!error || error == EAGAIN) { if (error && error != EAGAIN) {
if (sinp) { if (ssp) {
*sinp = sin; 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; *fdp = fd;
return error; 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 * - If 'default_port' is -1, then <port> is required. Otherwise, if
* <port> is omitted, then 'default_port' is used instead. * <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 * - If <port> (or 'default_port', if used) is 0, then no port is bound
* and the TCP/IP stack will select a port. * 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 * If successful, stores the address into '*ss' and returns true; otherwise
* zeros '*sinp' and returns false. */ * zeros '*ss' and returns false. */
bool bool
inet_parse_passive(const char *target_, int default_port, 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 *port;
const char *host_name; const char *host;
const char *port_string; char *p;
bool ok = false; bool ok;
int port;
/* Address defaults. */ p = target;
memset(sinp, 0, sizeof *sinp); port = parse_bracketed_token(&p);
sinp->sin_family = AF_INET; host = parse_bracketed_token(&p);
sinp->sin_addr.s_addr = htonl(INADDR_ANY); if (!port && default_port < 0) {
sinp->sin_port = htons(default_port); VLOG_ERR("%s: port must be specified", target_);
ok = false;
/* Parse optional port number. */ } else {
port_string = strsep(&string_ptr, ":"); ok = parse_sockaddr_components(ss, host ? host : "0.0.0.0",
if (port_string && str_to_int(port_string, 10, &port)) { port, default_port, target_);
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;
}
ok = true;
exit:
if (!ok) { if (!ok) {
memset(sinp, 0, sizeof *sinp); memset(ss, 0, sizeof *ss);
} }
free(target); free(target);
return ok; 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 * 'target', and listens for incoming connections. Parses 'target' in the same
* way was inet_parse_passive(). * way was inet_parse_passive().
* *
@@ -799,27 +858,27 @@ exit:
* On success, returns a non-negative file descriptor. On failure, returns a * On success, returns a non-negative file descriptor. On failure, returns a
* negative errno value. * negative errno value.
* *
* If 'sinp' is non-null, then on success the bound address is stored into * If 'ss' is non-null, then on success stores the bound address into '*ss'.
* '*sinp'.
* *
* 'dscp' becomes the DSCP bits in the IP headers for the new connection. It * '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 * should be in the range [0, 63] and will automatically be shifted to the
* appropriately place in the IP tos field. */ * appropriately place in the IP tos field. */
int int
inet_open_passive(int style, const char *target, int default_port, 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; int fd = 0, error;
unsigned int yes = 1; 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) { if (fd < 0) {
error = errno; error = errno;
VLOG_ERR("%s: socket: %s", target, ovs_strerror(error)); 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; error = errno;
VLOG_ERR("%s: bind: %s", target, ovs_strerror(error)); VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
goto 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 (ssp || kernel_chooses_port) {
if (sinp || kernel_chooses_port) { socklen_t ss_len = sizeof ss;
socklen_t sin_len = sizeof sin; if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) < 0) {
if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
error = errno; error = errno;
VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error)); VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error));
goto 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) { if (kernel_chooses_port) {
VLOG_INFO("%s: listening on port %"PRIu16, VLOG_INFO("%s: listening on port %"PRIu16,
target, ntohs(sin.sin_port)); target, ss_get_port(&ss));
}
if (ssp) {
*ssp = ss;
} }
} }
return fd; return fd;
error: error:
if (ssp) {
memset(ssp, 0, sizeof *ssp);
}
close(fd); close(fd);
return -error; return -error;
} }
@@ -1060,12 +1116,12 @@ describe_sockaddr(struct ds *string, int fd,
socklen_t len = sizeof ss; socklen_t len = sizeof ss;
if (!getaddr(fd, (struct sockaddr *) &ss, &len)) { if (!getaddr(fd, (struct sockaddr *) &ss, &len)) {
if (ss.ss_family == AF_INET) { if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
struct sockaddr_in sin; char addrbuf[SS_NTOP_BUFSIZE];
memcpy(&sin, &ss, sizeof sin); ds_put_format(string, "%s:%"PRIu16,
ds_put_format(string, IP_FMT":%"PRIu16, ss_format_address(&ss, addrbuf, sizeof addrbuf),
IP_ARGS(sin.sin_addr.s_addr), ntohs(sin.sin_port)); ss_get_port(&ss));
} else if (ss.ss_family == AF_UNIX) { } else if (ss.ss_family == AF_UNIX) {
struct sockaddr_un sun; struct sockaddr_un sun;
const char *null; 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;
} }
/* 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();
}
}

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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); int get_null_fd(void);
bool inet_parse_active(const char *target, uint16_t default_port, 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 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 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 *, int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
unsigned long int cmd, const char *cmd_name); 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 */

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -148,7 +148,7 @@ struct fd_pstream
{ {
struct pstream pstream; struct pstream pstream;
int fd; 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 **); struct stream **);
int (*set_dscp_cb)(int fd, uint8_t dscp); int (*set_dscp_cb)(int fd, uint8_t dscp);
char *unlink_path; char *unlink_path;
@@ -179,8 +179,8 @@ fd_pstream_cast(struct pstream *pstream)
* implementation never fails.) */ * implementation never fails.) */
int int
new_fd_pstream(const char *name, int fd, new_fd_pstream(const char *name, int fd,
int (*accept_cb)(int fd, const struct sockaddr *sa, int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
size_t sa_len, struct stream **streamp), size_t ss_len, struct stream **streamp),
int (*set_dscp_cb)(int fd, uint8_t dscp), int (*set_dscp_cb)(int fd, uint8_t dscp),
char *unlink_path, struct pstream **pstreamp) 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, return ps->accept_cb(new_fd, &ss, ss_len, new_streamp);
new_streamp);
} }
static void static void

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,13 +23,13 @@
struct stream; struct stream;
struct pstream; struct pstream;
struct sockaddr; struct sockaddr_storage;
int new_fd_stream(const char *name, int fd, int connect_status, int new_fd_stream(const char *name, int fd, int connect_status,
struct stream **streamp); struct stream **streamp);
int new_fd_pstream(const char *name, int fd, int new_fd_pstream(const char *name, int fd,
int (*accept_cb)(int fd, const struct sockaddr *, int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
size_t sa_len, struct stream **), size_t ss_len, struct stream **),
int (*set_dscp_cb)(int fd, uint8_t dscp), int (*set_dscp_cb)(int fd, uint8_t dscp),
char *unlink_path, char *unlink_path,
struct pstream **pstreamp); struct pstream **pstreamp);

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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, new_ssl_stream(const char *name, int fd, enum session_type type,
enum ssl_state state, struct stream **streamp) enum ssl_state state, struct stream **streamp)
{ {
struct sockaddr_in local; struct sockaddr_storage local;
socklen_t local_len = sizeof local; socklen_t local_len = sizeof local;
struct ssl_stream *sslv; struct ssl_stream *sslv;
SSL *ssl = NULL; SSL *ssl = NULL;
@@ -780,9 +780,11 @@ static int
pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp, pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp) 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; uint16_t port;
char bound_name[128];
int retval; int retval;
int fd; 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) { if (fd < 0) {
return -fd; 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); pssl = xmalloc(sizeof *pssl);
pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name); 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; pssl->fd = fd;
*pstreamp = &pssl->pstream; *pstreamp = &pssl->pstream;
return 0; return 0;
@@ -818,13 +822,14 @@ static int
pssl_accept(struct pstream *pstream, struct stream **new_streamp) pssl_accept(struct pstream *pstream, struct stream **new_streamp)
{ {
struct pssl_pstream *pssl = pssl_pstream_cast(pstream); struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
struct sockaddr_in sin; char name[SS_NTOP_BUFSIZE + 16];
socklen_t sin_len = sizeof sin; char addrbuf[SS_NTOP_BUFSIZE];
char name[128]; struct sockaddr_storage ss;
socklen_t ss_len = sizeof ss;
int new_fd; int new_fd;
int error; 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) { if (new_fd < 0) {
error = errno; error = errno;
if (error != EAGAIN) { 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)); snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
if (sin.sin_port != htons(OFP_OLD_PORT)) { ss_format_address(&ss, addrbuf, sizeof addrbuf),
sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin.sin_port)); ss_get_port(&ss));
}
return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING, return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING,
new_streamp); new_streamp);
} }

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,10 +21,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netdb.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "dynamic-string.h"
#include "packets.h" #include "packets.h"
#include "socket-util.h" #include "socket-util.h"
#include "util.h" #include "util.h"
@@ -40,13 +42,13 @@ static int
new_tcp_stream(const char *name, int fd, int connect_status, new_tcp_stream(const char *name, int fd, int connect_status,
struct stream **streamp) struct stream **streamp)
{ {
struct sockaddr_in local; struct sockaddr_storage local;
socklen_t local_len = sizeof local; socklen_t local_len = sizeof local;
int on = 1; int on = 1;
int retval; int retval;
/* Get the local IP and port information */ /* 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) { if (retval) {
memset(&local, 0, sizeof local); memset(&local, 0, sizeof local);
} }
@@ -90,47 +92,47 @@ const struct stream_class tcp_stream_class = {
/* Passive TCP. */ /* Passive TCP. */
static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, static int ptcp_accept(int fd, const struct sockaddr_storage *,
struct stream **streamp); size_t, struct stream **streamp);
static int static int
ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp, ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp) uint8_t dscp)
{ {
struct sockaddr_in sin; char bound_name[SS_NTOP_BUFSIZE + 16];
char bound_name[128]; char addrbuf[SS_NTOP_BUFSIZE];
struct sockaddr_storage ss;
uint16_t port;
int error; int error;
int fd; 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) { if (fd < 0) {
return -fd; return -fd;
} }
sprintf(bound_name, "ptcp:%"PRIu16":"IP_FMT, port = ss_get_port(&ss);
ntohs(sin.sin_port), IP_ARGS(sin.sin_addr.s_addr)); 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, error = new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL,
pstreamp); pstreamp);
if (!error) { if (!error) {
pstream_set_bound_port(*pstreamp, sin.sin_port); pstream_set_bound_port(*pstreamp, htons(port));
} }
return error; return error;
} }
static int static int
ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, ptcp_accept(int fd, const struct sockaddr_storage *ss,
struct stream **streamp) size_t ss_len OVS_UNUSED, struct stream **streamp)
{ {
const struct sockaddr_in *sin = ALIGNED_CAST(const struct sockaddr_in *, char name[SS_NTOP_BUFSIZE + 16];
sa); char addrbuf[SS_NTOP_BUFSIZE];
char name[128];
if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) { snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
sprintf(name, "tcp:"IP_FMT, IP_ARGS(sin->sin_addr.s_addr)); ss_format_address(ss, addrbuf, sizeof addrbuf),
sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port)); ss_get_port(ss));
} else {
strcpy(name, "tcp");
}
return new_tcp_stream(name, fd, 0, streamp); return new_tcp_stream(name, fd, 0, streamp);
} }

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 = {
/* Passive UNIX socket. */ /* Passive UNIX socket. */
static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len, static int punix_accept(int fd, const struct sockaddr_storage *ss,
struct stream **streamp); size_t ss_len, struct stream **streamp);
static int static int
punix_open(const char *name OVS_UNUSED, char *suffix, 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; const struct sockaddr_un *sun = (const struct sockaddr_un *) ss;
int name_len = get_unix_name_len(sa_len); int name_len = get_unix_name_len(ss_len);
char name[128]; char name[128];
if (name_len > 0) { if (name_len > 0) {

View 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 * and IP address. If port was absent in target string then it will use
* corresponding default port value. * corresponding default port value.
* - On error, function returns false and *sin contains garbage. * - On error, function returns false and *ss contains garbage.
*/ */
bool bool
stream_parse_target_with_default_port(const char *target, stream_parse_target_with_default_port(const char *target,
uint16_t default_port, 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

View File

@@ -81,7 +81,7 @@ int pstream_open_with_default_port(const char *name,
uint8_t dscp); uint8_t dscp);
bool stream_parse_target_with_default_port(const char *target, bool stream_parse_target_with_default_port(const char *target,
uint16_t default_port, uint16_t default_port,
struct sockaddr_in *sin); struct sockaddr_storage *ss);
int stream_or_pstream_needs_probes(const char *name); int stream_or_pstream_needs_probes(const char *name);
/* Error reporting. */ /* Error reporting. */

View File

@@ -1,9 +1,10 @@
.IP "\fBssl:\fIip\fR[\fB:\fIport\fR]" .IP "\fBssl:\fIip\fR[\fB:\fIport\fR]"
.IQ "\fBtcp:\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 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 be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR format. Wrap IPv6 addresses in square brackets,
options are mandatory. 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 .IP
If \fIport\fR is not specified, it currently defaults to 6633. In the 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 future, the default will change to 6653, which is the IANA-defined

View File

@@ -1,14 +1,14 @@
.IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]" .IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]"
.IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]" .IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
Listens for OpenFlow connections on \fIport\fR. By Listens for OpenFlow connections on \fIport\fR. The default
default, connections are not bound to a particular local IP address, but \fIport\fR is 6633, but a future version of Open vSwitch will change
\fIip\fR may be specified to listen only for connections to the given the default to the IANA-defined port 6653. By default, connections
\fIip\fR. For \fBpssl\fR, the \fB\-\-private\-key\fR, are allowed from any IPv4 address. Specify \fIip\fR as an IPv4
\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory. 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" .IP "\fBpunix:\fIfile\fR"
Listens for OpenFlow connections on the Unix domain server socket Listens for OpenFlow connections on the Unix domain server socket

View 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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. */ /* Add all the remotes. */
HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) { 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) { if (ofconn->band == OFPROTO_IN_BAND
continue; && stream_parse_target_with_default_port(target, OFP_OLD_PORT, &ss)
} && ss.ss_family == AF_INET) {
addrs[n_addrs++] = *(struct sockaddr_in *) &ss;
if (stream_parse_target_with_default_port(target,
OFP_OLD_PORT,
sin)) {
n_addrs++;
} }
} }
for (i = 0; i < mgr->n_extra_remotes; i++) { for (i = 0; i < mgr->n_extra_remotes; i++) {

View 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. * Copyright (c) 2009 InMon Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * 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) if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss)
&& route_table_get_name(sin.sin_addr.s_addr, name) && ss.ss_family == AF_INET) {
&& !netdev_get_in4_by_name(name, &in4)) { struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
goto success; if (route_table_get_name(sin->sin_addr.s_addr, name)
&& !netdev_get_in4_by_name(name, &in4)) {
goto success;
}
} }
} }

View File

@@ -1,11 +1,15 @@
.IP "\fBssl:\fIip\fB:\fIport\fR" .IP "\fBssl:\fIip\fB:\fIport\fR"
The specified SSL \fIport\fR on the host at the given \fIip\fR, which 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 must be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR 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. options are mandatory when this form is used.
. .
.IP "\fBtcp:\fIip\fB:\fIport\fR" .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" .IP "\fBunix:\fIfile\fR"
Connect to the Unix domain server socket named \fIfile\fR. Connect to the Unix domain server socket named \fIfile\fR.

View File

@@ -1,15 +1,22 @@
.IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]" .IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]"
Listen on the given SSL \fIport\fR for a connection. By default, 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 \fIip\fR, either IPv4 or IPv6 address. If \fIip\fR is
\fB\-\-ca\-cert\fR options are mandatory when this form is used. 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]" .IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]"
Listen on the given TCP \fIport\fR for a connection. By default, 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" .IP "\fBpunix:\fIfile\fR"
Listen on the Unix domain server socket named \fIfile\fR for a Listen on the Unix domain server socket named \fIfile\fR for a

View 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"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with 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): def inet_parse_active(target, default_port):
address = target.split(":") address = target.split(":")
host_name = address[0] if len(address) >= 2:
host_name = ":".join(address[0:-1]).lstrip('[').rstrip(']')
port = int(address[-1])
else:
if default_port:
port = default_port
else:
raise ValueError("%s: port number must be specified" % target)
host_name = address[0]
if not host_name: if not host_name:
raise ValueError("%s: bad peer name format" % target) raise ValueError("%s: bad peer name format" % target)
if len(address) >= 2:
port = int(address[1])
elif default_port:
port = default_port
else:
raise ValueError("%s: port number must be specified" % target)
return (host_name, port) return (host_name, port)
def inet_open_active(style, target, default_port, dscp): def inet_open_active(style, target, default_port, dscp):
address = inet_parse_active(target, default_port) address = inet_parse_active(target, default_port)
try: 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: except socket.error, e:
return get_exception_errno(e), None return get_exception_errno(e), None

View File

@@ -1829,55 +1829,58 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/[[0-9]]\{1,\}$/?/' | sort],
OVS_VSWITCHD_STOP OVS_VSWITCHD_STOP
AT_CLEANUP AT_CLEANUP
dnl Test that sFlow samples packets correctly. # CHECK_SFLOW_SAMPLING_PACKET(LOOPBACK_ADDR, ADDR_WITHOUT_BRACKETS)
AT_SETUP([ofproto-dpif - sFlow packet sampling]) #
OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) # 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`]) 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_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
AT_CAPTURE_FILE([sflow.log]) AT_CAPTURE_FILE([sflow.log])
SFLOW_PORT=`parse_listening_port < test-sflow.log` SFLOW_PORT=`parse_listening_port < test-sflow.log`
ovs-appctl time/stop
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
ADD_OF_PORTS([br0], 1, 2) dnl open with ARP packets to seed the bridge-learning. The output
ovs-vsctl \ dnl ifIndex numbers should be reported predictably after that.
set Interface br0 options:ifindex=1002 -- \ dnl Since we set sampling=1 we should see all of these packets
set Interface p1 options:ifindex=1004 -- \ dnl reported. Sorting the output by data-source and seqNo makes
set Interface p2 options:ifindex=1003 -- \ dnl it deterministic. Ensuring that we send at least two packets
set Bridge br0 sflow=@sf -- \ dnl into each port means we get to check the seq nos are
--id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \ dnl incrementing correctly.
header=128 sampling=1 polling=1 dnl because packets from different ports can be handled by separate
dnl threads, put some sleeps
dnl open with ARP packets to seed the bridge-learning. The output 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)'
dnl ifIndex numbers should be reported predictably after that. sleep 1
dnl Since we set sampling=1 we should see all of these packets 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)'
dnl reported. Sorting the output by data-source and seqNo makes sleep 1
dnl it deterministic. Ensuring that we send at least two packets 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)'
dnl into each port means we get to check the seq nos are sleep 1
dnl incrementing correctly. 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 because packets from different ports can be handled by separate dnl sleep long enough to get more than one counter sample
dnl threads, put some sleeps 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
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)' AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
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/ /\
/g']], [0], [dnl /g']], [0], [dnl
HEADER HEADER
dgramSeqNo=1 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 /g']], [0], [dnl
IFCOUNTERS IFCOUNTERS
dgramSeqNo=2 dgramSeqNo=2
@@ -2122,128 +2125,144 @@ IFCOUNTERS
out_errors=0 out_errors=0
promiscuous=0 promiscuous=0
]) ])
AT_CLEANUP AT_CLEANUP])
CHECK_SFLOW_SAMPLING_PACKET([127.0.0.1], [IPv4])
CHECK_SFLOW_SAMPLING_PACKET([[[::1]]], [IPv6])
# 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)
dnl Test that basic NetFlow reports flow statistics correctly: ovs-appctl time/stop
dnl - The initial packet of a flow are correctly accounted. ON_EXIT([kill `cat test-netflow.pid`])
dnl - Later packets within a flow are correctly accounted. AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
dnl - Flow actions changing (in this case, due to MAC learning) AT_CAPTURE_FILE([netflow.log])
dnl cause a record to be sent. NETFLOW_PORT=`parse_listening_port < test-netflow.log`
AT_SETUP([ofproto-dpif - NetFlow flow expiration])
OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) ovs-vsctl \
ADD_OF_PORTS([br0], 1, 2) 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
ovs-appctl time/stop for delay in 1000 30000; do
ON_EXIT([kill `cat test-netflow.pid`]) 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)'
AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore]) 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)'
AT_CAPTURE_FILE([netflow.log])
NETFLOW_PORT=`parse_listening_port < test-netflow.log`
ovs-vsctl \ ovs-appctl time/warp $delay
set Bridge br0 netflow=@nf -- \ done
--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 time/warp 6000
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_VSWITCHD_STOP
ovs-appctl -t test-netflow exit
ovs-appctl time/warp $delay 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])
done
ovs-appctl time/warp 6000 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])
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 > 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` CHECK_NETFLOW_EXPIRATION([127.0.0.1], [IPv4])
separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l` CHECK_NETFLOW_EXPIRATION([[[::1]]], [IPv6])
AT_CHECK([test $separate = 2 || test $combined = 1], [0])
AT_CLEANUP # 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])
dnl Test that basic NetFlow reports active expirations correctly. OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
AT_SETUP([ofproto-dpif - NetFlow active expiration]) ADD_OF_PORTS([br0], 1, 2)
OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) ON_EXIT([kill `cat test-netflow.pid`])
ADD_OF_PORTS([br0], 1, 2) 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`
ON_EXIT([kill `cat test-netflow.pid`]) ovs-vsctl \
AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore]) set Bridge br0 netflow=@nf -- \
AT_CAPTURE_FILE([netflow.log]) --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
NETFLOW_PORT=`parse_listening_port < test-netflow.log` engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
ovs-vsctl \ AT_CHECK([ovs-appctl time/stop])
set Bridge br0 netflow=@nf -- \ n=1
--id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \ while test $n -le 60; do
engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false n=`expr $n + 1`
AT_CHECK([ovs-appctl time/stop]) 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)'
n=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=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=1234)'
while test $n -le 60; do
n=`expr $n + 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=6,tos=0,ttl=64,frag=no),tcp(src=1234,dst=80)' ovs-appctl time/warp 1000
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)' done
ovs-appctl time/warp 1000 ovs-appctl time/warp 10000
done
ovs-appctl time/warp 10000 sleep 1
OVS_VSWITCHD_STOP
ovs-appctl -t test-netflow exit
sleep 1 # Count the number of reported packets:
OVS_VSWITCHD_STOP # - From source to destination before MAC learning kicks in (just one).
ovs-appctl -t test-netflow exit # - 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
# Count the number of reported packets: case $line in
# - From source to destination before MAC learning kicks in (just one). "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
# - From source to destination after that. counter=n_learn
# - From destination to source. ;;
n_learn=0 "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
n_in=0 counter=n_in
n_out=0 ;;
n_other=0 "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
n_recs=0 counter=n_out
none=0 ;;
while read line; do *)
pkts=`echo "$line" | sed 's/.*, \([[0-9]]*\) pkts,.*/\1/'` counter=n_other
case $pkts in ;;
[[0-9]]*) ;; esac
*) continue ;; eval $counter=\`expr \$$counter + \$pkts\`
esac n_recs=`expr $n_recs + 1`
done < netflow.log
case $line in # There should be exactly 1 MAC learning packet,
"seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*) # exactly 59 other packets in that direction,
counter=n_learn # and exactly 60 packets in the other direction.
;; AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
"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 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]) AT_SETUP([idle_age and hard_age increase over time])
OVS_VSWITCHD_START 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 OVS_VSWITCHD_STOP
AT_CLEANUP AT_CLEANUP
AT_SETUP([ofproto-dpif megaflow - netflow]) # CHECK_MEGAFLOW_NETFLOW(LOOPBACK_ADDR, IP_VERSION_TYPE)
OVS_VSWITCHD_START #
ADD_OF_PORTS([br0], [1], [2]) # 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 dnl NetFlow configuration disables wildcarding relevant fields
ON_EXIT([kill `cat test-netflow.pid`]) 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_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
AT_CAPTURE_FILE([netflow.log]) AT_CAPTURE_FILE([netflow.log])
NETFLOW_PORT=`parse_listening_port < test-netflow.log` NETFLOW_PORT=`parse_listening_port < test-netflow.log`
ovs-vsctl \ ovs-vsctl \
set Bridge br0 netflow=@nf -- \ set Bridge br0 netflow=@nf -- \
--id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \ --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false 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-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: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)']) 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 sleep 1
AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl 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: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: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 OVS_VSWITCHD_STOP
AT_CLEANUP AT_CLEANUP])
CHECK_MEGAFLOW_NETFLOW([127.0.0.1], [IPv4])
CHECK_MEGAFLOW_NETFLOW([[[::1]]], [IPv6])
AT_SETUP([ofproto-dpif megaflow - normal, active-backup bonding]) AT_SETUP([ofproto-dpif megaflow - normal, active-backup bonding])
OVS_VSWITCHD_START( OVS_VSWITCHD_START(

View File

@@ -21,7 +21,7 @@ s/ hard_age=[0-9]*,//
# log, given that the server was told to listen on a kernel-chosen # 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. # 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 # 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 ... # ovsdb-server --log-file --remote=ptcp:0:127.0.0.1 ...
# TCP_PORT=`parse_listening_port < ovsdb-server.log` # TCP_PORT=`parse_listening_port < ovsdb-server.log`
parse_listening_port () { 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])

View 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 At one point the "commit" code ignored new rows with all-default values,
dnl so this checks for that problem. dnl so this checks for that problem.
OVSDB_CHECK_EXECUTION([insert default row, query table], OVSDB_CHECK_EXECUTION([insert default row, query table],
@@ -193,7 +193,10 @@ OVSDB_CHECK_EXECUTION([insert default row, query table],
[[[{"uuid":["uuid","<0>"]}] [[[{"uuid":["uuid","<0>"]}]
[{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"","number":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], OVSDB_CHECK_EXECUTION([insert row, query table],
[ordinal_schema], [ordinal_schema],
[[[["ordinals", [[[["ordinals",

View File

@@ -72,10 +72,33 @@ m4_define([OVSDB_CHECK_IDL_TCP_PY],
OVSDB_SERVER_SHUTDOWN OVSDB_SERVER_SHUTDOWN
AT_CLEANUP]) 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], m4_define([OVSDB_CHECK_IDL],
[OVSDB_CHECK_IDL_C($@) [OVSDB_CHECK_IDL_C($@)
OVSDB_CHECK_IDL_PY($@) 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],
[], [],

View File

@@ -748,7 +748,7 @@ for i in `seq 1 100`; do
done done
AT_CLEANUP AT_CLEANUP
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_SETUP([ovsdb-client get-schema-version - tcp socket])
AT_KEYWORDS([ovsdb server positive tcp]) AT_KEYWORDS([ovsdb server positive tcp])
@@ -836,6 +875,42 @@ cat stdout >> output
AT_CLEANUP]) AT_CLEANUP])
EXECUTION_EXAMPLES 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
AT_BANNER([OVSDB -- transactions on transient ovsdb-server]) AT_BANNER([OVSDB -- transactions on transient ovsdb-server])

View 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. * Copyright (c) 2013 InMon Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,7 +44,6 @@ static unixctl_cb_func test_sflow_exit;
/* Datagram. */ /* Datagram. */
#define SFLOW_VERSION_5 5 #define SFLOW_VERSION_5 5
#define SFLOW_MIN_LEN 36 #define SFLOW_MIN_LEN 36
#define SFLOW_MAX_AGENTIP_STRLEN 64
/* Sample tag numbers. */ /* Sample tag numbers. */
#define SFLOW_FLOW_SAMPLE 1 #define SFLOW_FLOW_SAMPLE 1
@@ -82,7 +81,7 @@ struct sflow_xdr {
/* Agent. */ /* Agent. */
struct sflow_addr agentAddr; struct sflow_addr agentAddr;
char agentIPStr[SFLOW_MAX_AGENTIP_STRLEN]; char agentIPStr[INET6_ADDRSTRLEN + 2];
uint32_t subAgentId; uint32_t subAgentId;
uint32_t uptime_mS; uint32_t uptime_mS;
@@ -325,14 +324,12 @@ process_datagram(struct sflow_xdr *x)
/* Store the agent address as a string. */ /* Store the agent address as a string. */
if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) { if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN, char ipstr[INET6_ADDRSTRLEN];
"%04x:%04x:%04x:%04x", inet_ntop(AF_INET6, (const void *) &x->agentAddr.a.ip6,
x->agentAddr.a.ip6[0], ipstr, INET6_ADDRSTRLEN);
x->agentAddr.a.ip6[1], snprintf(x->agentIPStr, sizeof x->agentIPStr, "[%s]", ipstr);
x->agentAddr.a.ip6[2],
x->agentAddr.a.ip6[3]);
} 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));
} }

View File

@@ -466,12 +466,12 @@ collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg,
managers = xmalloc(sset_count(&targets) * sizeof *managers); managers = xmalloc(sset_count(&targets) * sizeof *managers);
SSET_FOR_EACH (target, &targets) { SSET_FOR_EACH (target, &targets) {
struct sockaddr_in *sin = &managers[n_managers]; struct sockaddr_storage ss;
if (stream_parse_target_with_default_port(target, if (stream_parse_target_with_default_port(target, OVSDB_OLD_PORT,
OVSDB_OLD_PORT, &ss)
sin)) { && ss.ss_family == AF_INET) {
n_managers++; managers[n_managers++] = *(struct sockaddr_in *) &ss;
} }
} }
} }

View File

@@ -3000,12 +3000,18 @@
</dd> </dd>
<dt><code>tcp:<var>ip</var></code>[<code>:<var>port</var></code>]</dt> <dt><code>tcp:<var>ip</var></code>[<code>:<var>port</var></code>]</dt>
<dd> <dd>
<p>The specified TCP <var>port</var> on the host at the <p>
given <var>ip</var>, which must be expressed as an IP The specified TCP <var>port</var> on the host at the given
address (not a DNS name).</p> <var>ip</var>, which must be expressed as an IP address (not a
<p>If <var>port</var> is not specified, it currently DNS name), where <var>ip</var> can be IPv4 or IPv6 address. If
defaults to 6633. In the future, the default will change to <var>ip</var> is an IPv6 address, wrap it in square brackets,
6653, which is the IANA-defined value.</p> 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> </dd>
</dl> </dl>
<p> <p>
@@ -3015,29 +3021,48 @@
<dl> <dl>
<dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt> <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd> <dd>
<p> Listens for SSL connections on the specified TCP <p>
<var>port</var>. If <var>ip</var>, which must be expressed Listens for SSL connections on the specified TCP <var>port</var>.
as an IP address (not a DNS name), is specified, then If <var>ip</var>, which must be expressed as an IP address (not a
connections are restricted to the specified local IP DNS name), is specified, then connections are restricted to the
address. The <ref table="Open_vSwitch" column="ssl"/> specified local IP address (either IPv4 or IPv6). If
column in the <ref table="Open_vSwitch"/> table must point <var>ip</var> is an IPv6 address, wrap it in square brackets,
to a valid SSL configuration when this form is used.</p> e.g. <code>pssl:6632:[::1]</code>.
<p>If <var>port</var> is not specified, it currently </p>
defaults to 6633. In the future, the default will change to <p>
6653, which is the IANA-defined value.</p> If <var>port</var> is not specified, it currently defaults to
<p>SSL support is an optional feature that is not always built as 6633. If <var>ip</var> is not specified then it listens only on
part of Open vSwitch.</p> 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> </dd>
<dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt> <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd> <dd>
<p>Listens for connections on the specified TCP <p>
<var>port</var>. If <var>ip</var>, which must be expressed Listens for connections on the specified TCP <var>port</var>. If
as an IP address (not a DNS name), is specified, then <var>ip</var>, which must be expressed as an IP address (not a
connections are restricted to the specified local IP DNS name), is specified, then connections are restricted to the
address.</p> specified local IP address (either IPv4 or IPv6). If
<p>If <var>port</var> is not specified, it currently <var>ip</var> is an IPv6 address, wrap it in square brackets,
defaults to 6633. In the future, the default will change to e.g. <code>ptcp:6632:[::1]</code>. If <var>ip</var> is not
6653, which is the IANA-defined value.</p> 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> </dd>
</dl> </dl>
<p>When multiple controllers are configured for a single bridge, the <p>When multiple controllers are configured for a single bridge, the
@@ -3331,8 +3356,10 @@
<dd> <dd>
<p> <p>
The specified TCP <var>port</var> on the host at the given The specified TCP <var>port</var> on the host at the given
<var>ip</var>, which must be expressed as an IP address <var>ip</var>, which must be expressed as an IP address (not a
(not a DNS name). 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>
<p> <p>
If <var>port</var> is not specified, it currently defaults If <var>port</var> is not specified, it currently defaults
@@ -3343,13 +3370,16 @@
<dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt> <dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd> <dd>
<p> <p>
Listens for SSL connections on the specified TCP Listens for SSL connections on the specified TCP <var>port</var>.
<var>port</var>. Specify 0 for <var>port</var> to have Specify 0 for <var>port</var> to have the kernel automatically
the kernel automatically choose an available port. If choose an available port. If <var>ip</var>, which must be
<var>ip</var>, which must be expressed as an IP address expressed as an IP address (not a DNS name), is specified, then
(not a DNS name), is specified, then connections are connections are restricted to the specified local IP address
restricted to the specified local IP address. The <ref (either IPv4 or IPv6 address). If <var>ip</var> is an IPv6
table="Open_vSwitch" column="ssl"/> column in the <ref 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 table="Open_vSwitch"/> table must point to a valid SSL
configuration when this form is used. configuration when this form is used.
</p> </p>
@@ -3366,12 +3396,15 @@
<dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt> <dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd> <dd>
<p> <p>
Listens for connections on the specified TCP Listens for connections on the specified TCP <var>port</var>.
<var>port</var>. Specify 0 for <var>port</var> to have Specify 0 for <var>port</var> to have the kernel automatically
the kernel automatically choose an available port. If choose an available port. If <var>ip</var>, which must be
<var>ip</var>, which must be expressed as an IP address expressed as an IP address (not a DNS name), is specified, then
(not a DNS name), is specified, then connections are connections are restricted to the specified local IP address
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>
<p> <p>
If <var>port</var> is not specified, it currently defaults If <var>port</var> is not specified, it currently defaults