Niklas Andersson nandersson@nicira.com
Padmanabhan Krishnan kprad1@yahoo.com
Pankaj Thakkar thakkar@nicira.com
+Pasi Kärkkäinen pasik@iki.fi
Paulo Cravero pcravero@as2594.net
Pawan Shukla shuklap@vmware.com
Peter Balland peter@nicira.com
When support for a given OpenFlow version is solidly implemented,
Open vSwitch will enable that version by default.
+Q: Does Open vSwitch support MPLS?
+
+A: Before version 1.11, Open vSwitch did not support MPLS. That is,
+ these versions can match on MPLS Ethernet types, but they cannot
+ match, push, or pop MPLS labels, nor can they look past MPLS labels
+ into the encapsulated packet.
+
+ Open vSwitch versions 1.11, 2.0, and 2.1 have very minimal support
+ for MPLS. With the userspace datapath only, these versions can
+ match, push, or pop a single MPLS label, but they still cannot look
+ past MPLS labels (even after popping them) into the encapsulated
+ packet. Kernel datapath support is unchanged from earlier
+ versions.
+
+ Open vSwitch version 2.2 will be able to match, push, or pop up to
+ 3 MPLS labels. Looking past MPLS labels into the encapsulated
+ packet will still be unsupported. Both userspace and kernel
+ datapaths will be supported, but MPLS processing always happens in
+ userspace either way, so kernel datapath performance will be
+ disappointing.
+
Q: I'm getting "error type 45250 code 0". What's that?
A: This is a Open vSwitch extension to OpenFlow error codes. Open
hard limit on the number of flows in the datapath. It defaults to 200,000
flows. OVS automatically adjusts this number depending on network
conditions.
+ - Added IPv6 support for active and passive socket communications.
v2.0.0 - 15 Oct 2013
#endif
.snd_portid = upcall_info->portid,
};
- size_t len, plen;
+ size_t len;
unsigned int hlen;
int err, dp_ifindex;
skb_zerocopy(user_skb, skb, skb->len, hlen);
/* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
- if (!(dp->user_features & OVS_DP_F_UNALIGNED) &&
- (plen = (ALIGN(user_skb->len, NLA_ALIGNTO) - user_skb->len)) > 0)
- memset(skb_put(user_skb, plen), 0, plen);
+ if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
+ size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len;
+
+ if (plen > 0)
+ memset(skb_put(user_skb, plen), 0, plen);
+ }
((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
struct sw_flow_mask *mask = flow->mask;
/* ovs-lock is required to protect mask-refcount and
- * mask list. */
+ * mask list.
+ */
ASSERT_OVSL();
BUG_ON(!mask->ref_count);
mask->ref_count--;
/*
- * Copyright (c) 2007-2013 Nicira, Inc.
+ * Copyright (c) 2007-2014 Nicira, Inc.
*
* This file is offered under your choice of two licenses: Apache 2.0 or GNU
* GPL 2.0 or later. The permission statements for each of these licenses is
* single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
* value.
* @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the
- * top of the packets MPLS label stack. Set the ethertype of the
+ * top of the packets MPLS label stack. Set the ethertype of the
* encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to
* indicate the new packet contents.
* @OVS_ACTION_ATTR_POP_MPLS: Pop an MPLS label stack entry off of the
* packet's MPLS label stack. Set the encapsulating frame's ethertype to
- * indicate the new packet contents This could potentially still be
- * %ETH_P_MPLS_* if the resulting MPLS label stack is not empty. If there
+ * indicate the new packet contents. This could potentially still be
+ * %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
* is no MPLS label stack, as determined by ethertype, no action is taken.
*
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
/*
- * Copyright (c) 2011, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
extern const struct in6_addr in6addr_any;
+/* Ditto, for IPv6. */
+struct sockaddr_in6 {
+ sa_family_t sin6_family;
+ in_port_t sin6_port; /* Transport layer port # */
+ uint32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ uint32_t sin6_scope_id; /* IPv6 scope-id */
+};
+
#define IPPROTO_IP 0
#define IPPROTO_HOPOPTS 0
#define IPPROTO_ICMP 1
#define INADDR_ANY 0x00000000
#define INADDR_BROADCAST 0xffffffff
+#define INADDR_LOOPBACK 0x7f000001
#define INADDR_NONE 0xffffffff
#define INET6_ADDRSTRLEN 46
}
static void
-convert_stats(struct netdev_stats *stats, const struct if_data *ifd)
+convert_stats_system(struct netdev_stats *stats, const struct if_data *ifd)
{
/*
* note: UINT64_MAX means unsupported
stats->tx_window_errors = UINT64_MAX;
}
+static void
+convert_stats_tap(struct netdev_stats *stats, const struct if_data *ifd)
+{
+ /*
+ * Similar to convert_stats_system but swapping rx and tx
+ * because 'ifd' is stats for the network interface side of the
+ * tap device and what the caller wants is one for the character
+ * device side.
+ *
+ * note: UINT64_MAX means unsupported
+ */
+ stats->rx_packets = ifd->ifi_opackets;
+ stats->tx_packets = ifd->ifi_ipackets;
+ stats->rx_bytes = ifd->ifi_ibytes;
+ stats->tx_bytes = ifd->ifi_obytes;
+ stats->rx_errors = ifd->ifi_oerrors;
+ stats->tx_errors = ifd->ifi_ierrors;
+ stats->rx_dropped = UINT64_MAX;
+ stats->tx_dropped = ifd->ifi_iqdrops;
+ stats->multicast = ifd->ifi_omcasts;
+ stats->collisions = UINT64_MAX;
+ stats->rx_length_errors = UINT64_MAX;
+ stats->rx_over_errors = UINT64_MAX;
+ stats->rx_crc_errors = UINT64_MAX;
+ stats->rx_frame_errors = UINT64_MAX;
+ stats->rx_fifo_errors = UINT64_MAX;
+ stats->rx_missed_errors = UINT64_MAX;
+ stats->tx_aborted_errors = UINT64_MAX;
+ stats->tx_carrier_errors = UINT64_MAX;
+ stats->tx_fifo_errors = UINT64_MAX;
+ stats->tx_heartbeat_errors = UINT64_MAX;
+ stats->tx_window_errors = UINT64_MAX;
+}
+
+static void
+convert_stats(const struct netdev *netdev, struct netdev_stats *stats,
+ const struct if_data *ifd)
+{
+ if (netdev_bsd_cast(netdev)->tap_fd == -1) {
+ convert_stats_system(stats, ifd);
+ } else {
+ convert_stats_tap(stats, ifd);
+ }
+}
+
/* Retrieves current device stats for 'netdev'. */
static int
netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
netdev_get_name(netdev_), ovs_strerror(errno));
return errno;
} else if (!strcmp(ifmd.ifmd_name, netdev_get_name(netdev_))) {
- convert_stats(stats, &ifmd.ifmd_data);
+ convert_stats(netdev, stats, &ifdr.ifdr_data);
break;
}
}
sizeof(ifdr.ifdr_name));
error = af_link_ioctl(SIOCGIFDATA, &ifdr);
if (!error) {
- convert_stats(stats, &ifdr.ifdr_data);
+ convert_stats(netdev_, stats, &ifdr.ifdr_data);
}
return error;
#else
reconnect_set_passive(reconnect, false, time_msec());
reconnect_enable(reconnect, time_msec());
reconnect_set_backoff(reconnect, 1000, INT_MAX);
+ reconnect_set_probe_interval(reconnect, 0);
conn->u.rconn.reconnect = reconnect;
error = stream_open(stream, &active_stream, DSCP_DEFAULT);
while (base_n < flow_n) {
struct ovs_action_push_mpls *mpls;
- /* If there's a VLAN tag, pop it off so that our new MPLS label doesn't
- * end up outside it. */
- pop_vlan(base, odp_actions, wc);
-
mpls = nl_msg_put_unspec_zero(odp_actions,
OVS_ACTION_ATTR_PUSH_MPLS,
sizeof *mpls);
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
static enum ofperr
-push_mpls_from_openflow(ovs_be16 ethertype, enum ofpact_mpls_position position,
- struct ofpbuf *out)
+push_mpls_from_openflow(ovs_be16 ethertype, struct ofpbuf *out)
{
struct ofpact_push_mpls *oam;
}
oam = ofpact_put_PUSH_MPLS(out);
oam->ethertype = ethertype;
- oam->position = position;
return 0;
}
break;
case OFPUTIL_NXAST_PUSH_MPLS:
- error = push_mpls_from_openflow(a->push_mpls.ethertype,
- OFPACT_MPLS_AFTER_VLAN, out);
+ error = push_mpls_from_openflow(a->push_mpls.ethertype, out);
break;
case OFPUTIL_NXAST_SET_MPLS_LABEL:
break;
case OFPUTIL_OFPAT11_PUSH_MPLS:
- /* OpenFlow 1.3 has different semantics. */
- error = push_mpls_from_openflow(a->push.ethertype,
- version >= OFP13_VERSION ?
- OFPACT_MPLS_BEFORE_VLAN :
- OFPACT_MPLS_AFTER_VLAN, out);
+ error = push_mpls_from_openflow(a->push.ethertype, out);
break;
case OFPUTIL_OFPAT11_POP_MPLS:
/*
- * Copyright (c) 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
union mf_subvalue subvalue; /* Least-significant bits are used. */
};
-/* The position in the packet at which to insert an MPLS header.
- *
- * Used NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */
-enum ofpact_mpls_position {
- /* Add the MPLS LSE after the Ethernet header but before any VLAN tags.
- * OpenFlow 1.3+ requires this behavior. */
- OFPACT_MPLS_BEFORE_VLAN,
-
- /* Add the MPLS LSE after the Ethernet header and any VLAN tags.
- * OpenFlow 1.1 and 1.2 require this behavior. */
- OFPACT_MPLS_AFTER_VLAN
-};
-
/* OFPACT_SET_FIELD.
*
* Used for OFPAT12_SET_FIELD. */
struct ofpact_push_mpls {
struct ofpact ofpact;
ovs_be16 ethertype;
- enum ofpact_mpls_position position;
};
/* OFPACT_POP_MPLS
* (by recompiling). Thus, one may more freely use this form of
* thread-specific data.
*
- * Compared to pthread_key_t, ovsthread_key_t has the follow limitations:
+ * ovsthread_key_t also differs from pthread_key_t in the following ways:
*
* - Destructors must not access thread-specific data (via ovsthread_key).
+ *
+ * - The pthread_key_t API allows concurrently exiting threads to start
+ * executing the destructor after pthread_key_delete() returns. The
+ * ovsthread_key_t API guarantees that, when ovsthread_key_delete()
+ * returns, all destructors have returned and no new ones will start
+ * execution.
*/
typedef struct ovsthread_key *ovsthread_key_t;
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
: htonl(0)); /* ??? */
}
-/* Parses 'target', which should be a string in the format "<host>[:<port>]".
- * <host> is required. If 'default_port' is nonzero then <port> is optional
- * and defaults to 'default_port'.
+/* This is like strsep() except:
*
- * On success, returns true and stores the parsed remote address into '*sinp'.
- * On failure, logs an error, stores zeros into '*sinp', and returns false. */
-bool
-inet_parse_active(const char *target_, uint16_t default_port,
- struct sockaddr_in *sinp)
+ * - The separator string is ":".
+ *
+ * - Square brackets [] quote ":" separators and are removed from the
+ * tokens. */
+static char *
+parse_bracketed_token(char **pp)
{
- char *target = xstrdup(target_);
- char *save_ptr = NULL;
- const char *host_name;
- const char *port_string;
- bool ok = false;
-
- /* Defaults. */
- sinp->sin_family = AF_INET;
- sinp->sin_port = htons(default_port);
-
- /* Tokenize. */
- host_name = strtok_r(target, ":", &save_ptr);
- port_string = strtok_r(NULL, ":", &save_ptr);
- if (!host_name) {
- VLOG_ERR("%s: bad peer name format", target_);
- goto exit;
+ char *p = *pp;
+
+ if (p == NULL) {
+ return NULL;
+ } else if (*p == '\0') {
+ *pp = NULL;
+ return p;
+ } else if (*p == '[') {
+ char *start = p + 1;
+ char *end = start + strcspn(start, "]");
+ *pp = (*end == '\0' ? NULL
+ : end[1] == ':' ? end + 2
+ : end + 1);
+ *end = '\0';
+ return start;
+ } else {
+ char *start = p;
+ char *end = start + strcspn(start, ":");
+ *pp = *end == '\0' ? NULL : end + 1;
+ *end = '\0';
+ return start;
}
+}
- /* Look up IP, port. */
- if (lookup_ip(host_name, &sinp->sin_addr)) {
- goto exit;
+static bool
+parse_sockaddr_components(struct sockaddr_storage *ss,
+ const char *host_s,
+ const char *port_s, uint16_t default_port,
+ const char *s)
+{
+ struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *, ss);
+ int port;
+
+ if (port_s && port_s[0]) {
+ if (!str_to_int(port_s, 10, &port) || port < 0 || port > 65535) {
+ VLOG_ERR("%s: bad port number \"%s\"", s, port_s);
+ }
+ } else {
+ port = default_port;
}
- if (port_string && atoi(port_string)) {
- sinp->sin_port = htons(atoi(port_string));
- } else if (!default_port) {
- VLOG_ERR("%s: port number must be specified", target_);
- goto exit;
+
+ memset(ss, 0, sizeof *ss);
+ if (strchr(host_s, ':')) {
+ struct sockaddr_in6 *sin6
+ = ALIGNED_CAST(struct sockaddr_in6 *, ss);
+
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ if (!inet_pton(AF_INET6, host_s, sin6->sin6_addr.s6_addr)) {
+ VLOG_ERR("%s: bad IPv6 address \"%s\"", s, host_s);
+ goto exit;
+ }
+ } else {
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ if (!inet_pton(AF_INET, host_s, &sin->sin_addr.s_addr)) {
+ VLOG_ERR("%s: bad IPv4 address \"%s\"", s, host_s);
+ goto exit;
+ }
}
- ok = true;
+ return true;
exit:
+ 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) {
- memset(sinp, 0, sizeof *sinp);
+ memset(ss, 0, sizeof *ss);
}
free(target);
return ok;
}
-/* Opens a non-blocking IPv4 socket of the specified 'style' and connects to
- * 'target', which should be a string in the format "<host>[:<port>]". <host>
- * is required. If 'default_port' is nonzero then <port> is optional and
- * defaults to 'default_port'.
+
+/* Opens a non-blocking IPv4 or IPv6 socket of the specified 'style' and
+ * connects to 'target', which should be a string in the format
+ * "<host>[:<port>]". <host>, which is required, may be an IPv4 address or an
+ * IPv6 address enclosed in square brackets. If 'default_port' is nonzero then
+ * <port> is optional and defaults to 'default_port'.
*
* 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP).
*
* into '*fdp'. On failure, returns a positive errno value other than EAGAIN
* and stores -1 into '*fdp'.
*
- * If 'sinp' is non-null, then on success the target address is stored into
- * '*sinp'.
+ * If 'ss' is non-null, then on success stores the target address into '*ss'.
*
* 'dscp' becomes the DSCP bits in the IP headers for the new connection. It
* should be in the range [0, 63] and will automatically be shifted to the
* appropriately place in the IP tos field. */
int
inet_open_active(int style, const char *target, uint16_t default_port,
- struct sockaddr_in *sinp, int *fdp, uint8_t dscp)
+ struct sockaddr_storage *ssp, int *fdp, uint8_t dscp)
{
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
int fd = -1;
int error;
/* Parse. */
- if (!inet_parse_active(target, default_port, &sin)) {
+ if (!inet_parse_active(target, default_port, &ss)) {
error = EAFNOSUPPORT;
goto exit;
}
/* Create non-blocking socket. */
- fd = socket(AF_INET, style, 0);
+ fd = socket(ss.ss_family, style, 0);
if (fd < 0) {
VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
error = errno;
goto exit;
}
- /* The dscp bits must be configured before connect() to ensure that the TOS
- * field is set during the connection establishment. If set after
+ /* The dscp bits must be configured before connect() to ensure that the
+ * TOS field is set during the connection establishment. If set after
* connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp);
if (error) {
}
/* Connect. */
- error = connect(fd, (struct sockaddr *) &sin, sizeof sin) == 0 ? 0 : errno;
+ error = connect(fd, (struct sockaddr *) &ss, ss_length(&ss)) == 0
+ ? 0
+ : errno;
if (error == EINPROGRESS) {
error = EAGAIN;
}
exit:
- if (!error || error == EAGAIN) {
- if (sinp) {
- *sinp = sin;
+ if (error && error != EAGAIN) {
+ if (ssp) {
+ memset(ssp, 0, sizeof *ssp);
+ }
+ if (fd >= 0) {
+ close(fd);
+ fd = -1;
+ }
+ } else {
+ if (ssp) {
+ *ssp = ss;
}
- } else if (fd >= 0) {
- close(fd);
- fd = -1;
}
*fdp = fd;
return error;
}
-/* Parses 'target', which should be a string in the format "[<port>][:<ip>]":
+/* Parses 'target', which should be a string in the format "[<port>][:<host>]":
*
* - If 'default_port' is -1, then <port> is required. Otherwise, if
* <port> is omitted, then 'default_port' is used instead.
* - If <port> (or 'default_port', if used) is 0, then no port is bound
* and the TCP/IP stack will select a port.
*
- * - If <ip> is omitted then the IP address is wildcarded.
+ * - <host> is optional. If supplied, it may be an IPv4 address or an
+ * IPv6 address enclosed in square brackets. If omitted, the IP address
+ * is wildcarded.
*
- * If successful, stores the address into '*sinp' and returns true; otherwise
- * zeros '*sinp' and returns false. */
+ * If successful, stores the address into '*ss' and returns true; otherwise
+ * zeros '*ss' and returns false. */
bool
inet_parse_passive(const char *target_, int default_port,
- struct sockaddr_in *sinp)
+ struct sockaddr_storage *ss)
{
char *target = xstrdup(target_);
- char *string_ptr = target;
- const char *host_name;
- const char *port_string;
- bool ok = false;
- int port;
-
- /* Address defaults. */
- memset(sinp, 0, sizeof *sinp);
- sinp->sin_family = AF_INET;
- sinp->sin_addr.s_addr = htonl(INADDR_ANY);
- sinp->sin_port = htons(default_port);
-
- /* Parse optional port number. */
- port_string = strsep(&string_ptr, ":");
- if (port_string && str_to_int(port_string, 10, &port)) {
- sinp->sin_port = htons(port);
- } else if (default_port < 0) {
- VLOG_ERR("%s: port number must be specified", target_);
- goto exit;
- }
-
- /* Parse optional bind IP. */
- host_name = strsep(&string_ptr, ":");
- if (host_name && host_name[0] && lookup_ip(host_name, &sinp->sin_addr)) {
- goto exit;
+ const char *port;
+ const char *host;
+ char *p;
+ bool ok;
+
+ p = target;
+ port = parse_bracketed_token(&p);
+ host = parse_bracketed_token(&p);
+ if (!port && default_port < 0) {
+ VLOG_ERR("%s: port must be specified", target_);
+ ok = false;
+ } else {
+ ok = parse_sockaddr_components(ss, host ? host : "0.0.0.0",
+ port, default_port, target_);
}
-
- ok = true;
-
-exit:
if (!ok) {
- memset(sinp, 0, sizeof *sinp);
+ memset(ss, 0, sizeof *ss);
}
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().
*
* On success, returns a non-negative file descriptor. On failure, returns a
* negative errno value.
*
- * If 'sinp' is non-null, then on success the bound address is stored into
- * '*sinp'.
+ * If 'ss' is non-null, then on success stores the bound address into '*ss'.
*
* 'dscp' becomes the DSCP bits in the IP headers for the new connection. It
* should be in the range [0, 63] and will automatically be shifted to the
* appropriately place in the IP tos field. */
int
inet_open_passive(int style, const char *target, int default_port,
- 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;
int fd = 0, error;
unsigned int yes = 1;
- if (!inet_parse_passive(target, default_port, &sin)) {
+ if (!inet_parse_passive(target, default_port, &ss)) {
return -EAFNOSUPPORT;
}
+ kernel_chooses_port = ss_get_port(&ss) == 0;
/* 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));
}
/* Bind. */
- if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
+ if (bind(fd, (struct sockaddr *) &ss, ss_length(&ss)) < 0) {
error = errno;
VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
goto error;
goto error;
}
- kernel_chooses_port = sin.sin_port == htons(0);
- if (sinp || kernel_chooses_port) {
- socklen_t sin_len = sizeof sin;
- if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
+ if (ssp || kernel_chooses_port) {
+ socklen_t ss_len = sizeof ss;
+ if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) < 0) {
error = errno;
VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error));
goto error;
}
- if (sin.sin_family != AF_INET || sin_len != sizeof sin) {
- error = EAFNOSUPPORT;
- VLOG_ERR("%s: getsockname: invalid socket name", target);
- goto error;
- }
- if (sinp) {
- *sinp = sin;
- }
if (kernel_chooses_port) {
VLOG_INFO("%s: listening on port %"PRIu16,
- target, ntohs(sin.sin_port));
+ target, ss_get_port(&ss));
+ }
+ if (ssp) {
+ *ssp = ss;
}
}
return fd;
error:
+ if (ssp) {
+ memset(ssp, 0, sizeof *ssp);
+ }
close(fd);
return -error;
}
socklen_t len = sizeof ss;
if (!getaddr(fd, (struct sockaddr *) &ss, &len)) {
- if (ss.ss_family == AF_INET) {
- struct sockaddr_in sin;
+ if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
+ char addrbuf[SS_NTOP_BUFSIZE];
- memcpy(&sin, &ss, sizeof sin);
- ds_put_format(string, IP_FMT":%"PRIu16,
- IP_ARGS(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+ ds_put_format(string, "%s:%"PRIu16,
+ ss_format_address(&ss, addrbuf, sizeof addrbuf),
+ ss_get_port(&ss));
} else if (ss.ss_family == AF_UNIX) {
struct sockaddr_un sun;
const char *null;
}
return error;
}
+\f
+/* sockaddr_storage helpers. */
+/* Returns the IPv4 or IPv6 port in 'ss'. */
+uint16_t
+ss_get_port(const struct sockaddr_storage *ss)
+{
+ if (ss->ss_family == AF_INET) {
+ const struct sockaddr_in *sin
+ = ALIGNED_CAST(const struct sockaddr_in *, ss);
+ return ntohs(sin->sin_port);
+ } else if (ss->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6
+ = ALIGNED_CAST(const struct sockaddr_in6 *, ss);
+ return ntohs(sin6->sin6_port);
+ } else {
+ OVS_NOT_REACHED();
+ }
+}
+
+/* Formats the IPv4 or IPv6 address in 'ss' into the 'bufsize' bytes in 'buf'.
+ * If 'ss' is an IPv6 address, puts square brackets around the address.
+ * 'bufsize' should be at least SS_NTOP_BUFSIZE.
+ *
+ * Returns 'buf'. */
+char *
+ss_format_address(const struct sockaddr_storage *ss,
+ char *buf, size_t bufsize)
+{
+ ovs_assert(bufsize >= SS_NTOP_BUFSIZE);
+ if (ss->ss_family == AF_INET) {
+ const struct sockaddr_in *sin
+ = ALIGNED_CAST(const struct sockaddr_in *, ss);
+
+ snprintf(buf, bufsize, IP_FMT, IP_ARGS(sin->sin_addr.s_addr));
+ } else if (ss->ss_family == AF_INET6) {
+ const struct sockaddr_in6 *sin6
+ = ALIGNED_CAST(const struct sockaddr_in6 *, ss);
+
+ buf[0] = '[';
+ inet_ntop(AF_INET6, sin6->sin6_addr.s6_addr, buf + 1, bufsize - 1);
+ strcpy(strchr(buf, '\0'), "]");
+ } else {
+ OVS_NOT_REACHED();
+ }
+
+ return buf;
+}
+
+size_t
+ss_length(const struct sockaddr_storage *ss)
+{
+ switch (ss->ss_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+
+ default:
+ OVS_NOT_REACHED();
+ }
+}
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
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);
int af_inet_ifreq_ioctl(const char *name, struct ifreq *,
unsigned long int cmd, const char *cmd_name);
+/* Functions for working with sockaddr_storage that might contain an IPv4 or
+ * IPv6 address. */
+uint16_t ss_get_port(const struct sockaddr_storage *);
+#define SS_NTOP_BUFSIZE (1 + INET6_ADDRSTRLEN + 1)
+char *ss_format_address(const struct sockaddr_storage *,
+ char *buf, size_t bufsize);
+size_t ss_length(const struct sockaddr_storage *);
+
#endif /* socket-util.h */
/*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
{
struct pstream pstream;
int fd;
- int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len,
+ int (*accept_cb)(int fd, const struct sockaddr_storage *, size_t ss_len,
struct stream **);
int (*set_dscp_cb)(int fd, uint8_t dscp);
char *unlink_path;
* implementation never fails.) */
int
new_fd_pstream(const char *name, int fd,
- int (*accept_cb)(int fd, const struct sockaddr *sa,
- size_t sa_len, struct stream **streamp),
+ int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
+ size_t ss_len, struct stream **streamp),
int (*set_dscp_cb)(int fd, uint8_t dscp),
char *unlink_path, struct pstream **pstreamp)
{
return retval;
}
- return ps->accept_cb(new_fd, (const struct sockaddr *) &ss, ss_len,
- new_streamp);
+ return ps->accept_cb(new_fd, &ss, ss_len, new_streamp);
}
static void
/*
- * Copyright (c) 2008, 2009, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2012, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct stream;
struct pstream;
-struct sockaddr;
+struct sockaddr_storage;
int new_fd_stream(const char *name, int fd, int connect_status,
struct stream **streamp);
int new_fd_pstream(const char *name, int fd,
- int (*accept_cb)(int fd, const struct sockaddr *,
- size_t sa_len, struct stream **),
+ int (*accept_cb)(int fd, const struct sockaddr_storage *ss,
+ size_t ss_len, struct stream **),
int (*set_dscp_cb)(int fd, uint8_t dscp),
char *unlink_path,
struct pstream **pstreamp);
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
new_ssl_stream(const char *name, int fd, enum session_type type,
enum ssl_state state, struct stream **streamp)
{
- struct sockaddr_in local;
+ struct sockaddr_storage local;
socklen_t local_len = sizeof local;
struct ssl_stream *sslv;
SSL *ssl = NULL;
pssl_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp)
{
+ char bound_name[SS_NTOP_BUFSIZE + 16];
+ char addrbuf[SS_NTOP_BUFSIZE];
+ struct sockaddr_storage ss;
struct pssl_pstream *pssl;
- struct sockaddr_in sin;
- char bound_name[128];
+ uint16_t port;
int retval;
int fd;
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));
+
+ port = ss_get_port(&ss);
+ snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
+ port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
pssl = xmalloc(sizeof *pssl);
pstream_init(&pssl->pstream, &pssl_pstream_class, bound_name);
- pstream_set_bound_port(&pssl->pstream, sin.sin_port);
+ pstream_set_bound_port(&pssl->pstream, htons(port));
pssl->fd = fd;
*pstreamp = &pssl->pstream;
return 0;
pssl_accept(struct pstream *pstream, struct stream **new_streamp)
{
struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
- struct sockaddr_in sin;
- socklen_t sin_len = sizeof sin;
- char name[128];
+ char name[SS_NTOP_BUFSIZE + 16];
+ char addrbuf[SS_NTOP_BUFSIZE];
+ struct sockaddr_storage ss;
+ socklen_t ss_len = sizeof ss;
int new_fd;
int error;
- new_fd = accept(pssl->fd, (struct sockaddr *) &sin, &sin_len);
+ new_fd = accept(pssl->fd, (struct sockaddr *) &ss, &ss_len);
if (new_fd < 0) {
error = errno;
if (error != EAGAIN) {
return error;
}
- sprintf(name, "ssl:"IP_FMT, IP_ARGS(sin.sin_addr.s_addr));
- if (sin.sin_port != htons(OFP_OLD_PORT)) {
- sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin.sin_port));
- }
+ snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
+ ss_format_address(&ss, addrbuf, sizeof addrbuf),
+ ss_get_port(&ss));
return new_ssl_stream(name, new_fd, SERVER, STATE_SSL_CONNECTING,
new_streamp);
}
/*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
+#include "dynamic-string.h"
#include "packets.h"
#include "socket-util.h"
#include "util.h"
new_tcp_stream(const char *name, int fd, int connect_status,
struct stream **streamp)
{
- struct sockaddr_in local;
+ struct sockaddr_storage local;
socklen_t local_len = sizeof local;
int on = 1;
int retval;
/* Get the local IP and port information */
- retval = getsockname(fd, (struct sockaddr *)&local, &local_len);
+ retval = getsockname(fd, (struct sockaddr *) &local, &local_len);
if (retval) {
memset(&local, 0, sizeof local);
}
\f
/* Passive TCP. */
-static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
- struct stream **streamp);
+static int ptcp_accept(int fd, const struct sockaddr_storage *,
+ size_t, struct stream **streamp);
static int
ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
uint8_t dscp)
{
- struct sockaddr_in sin;
- char bound_name[128];
+ char bound_name[SS_NTOP_BUFSIZE + 16];
+ char addrbuf[SS_NTOP_BUFSIZE];
+ struct sockaddr_storage ss;
+ uint16_t port;
int error;
int fd;
- 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));
+ port = ss_get_port(&ss);
+ snprintf(bound_name, sizeof bound_name, "ptcp:%"PRIu16":%s",
+ port, ss_format_address(&ss, addrbuf, sizeof addrbuf));
+
error = new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL,
pstreamp);
if (!error) {
- pstream_set_bound_port(*pstreamp, sin.sin_port);
+ pstream_set_bound_port(*pstreamp, htons(port));
}
return error;
}
static int
-ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
- struct stream **streamp)
+ptcp_accept(int fd, const struct sockaddr_storage *ss,
+ size_t ss_len OVS_UNUSED, struct stream **streamp)
{
- const struct sockaddr_in *sin = ALIGNED_CAST(const struct sockaddr_in *,
- sa);
- char name[128];
+ char name[SS_NTOP_BUFSIZE + 16];
+ char addrbuf[SS_NTOP_BUFSIZE];
- if (sa_len == sizeof(struct sockaddr_in) && sin->sin_family == AF_INET) {
- sprintf(name, "tcp:"IP_FMT, IP_ARGS(sin->sin_addr.s_addr));
- sprintf(strchr(name, '\0'), ":%"PRIu16, ntohs(sin->sin_port));
- } else {
- strcpy(name, "tcp");
- }
+ snprintf(name, sizeof name, "tcp:%s:%"PRIu16,
+ ss_format_address(ss, addrbuf, sizeof addrbuf),
+ ss_get_port(ss));
return new_tcp_stream(name, fd, 0, streamp);
}
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
\f
/* Passive UNIX socket. */
-static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
- struct stream **streamp);
+static int punix_accept(int fd, const struct sockaddr_storage *ss,
+ size_t ss_len, struct stream **streamp);
static int
punix_open(const char *name OVS_UNUSED, char *suffix,
}
static int
-punix_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)
{
- const struct sockaddr_un *sun = (const struct sockaddr_un *) sa;
- int name_len = get_unix_name_len(sa_len);
+ const struct sockaddr_un *sun = (const struct sockaddr_un *) ss;
+ int name_len = get_unix_name_len(ss_len);
char name[128];
if (name_len > 0) {
/*
* 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
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. */
.IP "\fBssl:\fIip\fR[\fB:\fIport\fR]"
.IQ "\fBtcp:\fIip\fR[\fB:\fIport\fR]"
The specified \fIport\fR on the host at the given \fIip\fR, which must
-be expressed as an IP address (not a DNS name). For \fBssl\fR, the
-\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
-options are mandatory.
+be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
+format. Wrap IPv6 addresses in square brackets,
+e.g. \fBtcp:[::1]:6633\fR. For \fBssl\fR, the \fB\-\-private\-key\fR,
+\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory.
.IP
If \fIport\fR is not specified, it currently defaults to 6633. In the
future, the default will change to 6653, which is the IANA-defined
.IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]"
.IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
-Listens for OpenFlow connections on \fIport\fR. By
-default, connections are not bound to a particular local IP address, but
-\fIip\fR may be specified to listen only for connections to the given
-\fIip\fR. For \fBpssl\fR, the \fB\-\-private\-key\fR,
-\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory.
+Listens for OpenFlow connections on \fIport\fR. The default
+\fIport\fR is 6633, but a future version of Open vSwitch will change
+the default to the IANA-defined port 6653. By default, connections
+are allowed from any IPv4 address. Specify \fIip\fR as an IPv4
+address or a bracketed IPv6 address (e.g. \fBptcp:6633:[::1]\fR). DNS
+names may not be used. For \fBpssl\fR, the
+\fB\-\-private\-key\fR,\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
+options are mandatory.
.IP
-If \fIport\fR is not specified, it currently defaults to 6633. In the
-future, the default will change to 6653, which is the IANA-defined
-value.
.
.IP "\fBpunix:\fIfile\fR"
Listens for OpenFlow connections on the Unix domain server socket
/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
for (i = 0; i < c->n_fds; i++) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
if (send(c->fds[i], payload, n, 0) == -1) {
- VLOG_WARN_RL(&rl, "sending to collector failed: %s",
- ovs_strerror(errno));
+ char *s = describe_fd(c->fds[i]);
+ VLOG_WARN_RL(&rl, "%s: sending to collector failed (%s)",
+ s, ovs_strerror(errno));
+ free(s);
}
}
}
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* Add all the remotes. */
HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) {
- struct sockaddr_in *sin = &addrs[n_addrs];
const char *target = rconn_get_target(ofconn->rconn);
+ struct sockaddr_storage ss;
- if (ofconn->band == OFPROTO_OUT_OF_BAND) {
- continue;
- }
-
- if (stream_parse_target_with_default_port(target,
- OFP_OLD_PORT,
- sin)) {
- n_addrs++;
+ if (ofconn->band == OFPROTO_IN_BAND
+ && stream_parse_target_with_default_port(target, OFP_OLD_PORT, &ss)
+ && ss.ss_family == AF_INET) {
+ addrs[n_addrs++] = *(struct sockaddr_in *) &ss;
}
}
for (i = 0; i < mgr->n_extra_remotes; i++) {
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
* Copyright (c) 2009 InMon Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
}
SSET_FOR_EACH (target, targets) {
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
char name[IFNAMSIZ];
- if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &sin)
- && route_table_get_name(sin.sin_addr.s_addr, name)
- && !netdev_get_in4_by_name(name, &in4)) {
- goto success;
+ if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss)
+ && ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
+ if (route_table_get_name(sin->sin_addr.s_addr, name)
+ && !netdev_get_in4_by_name(name, &in4)) {
+ goto success;
+ }
}
}
{
struct flow_wildcards *wc = &ctx->xout->wc;
struct flow *flow = &ctx->xin->flow;
- ovs_be16 vlan_tci = flow->vlan_tci;
int n;
ovs_assert(eth_type_mpls(mpls->ethertype));
n = flow_count_mpls_labels(flow, wc);
if (!n) {
- if (mpls->position == OFPACT_MPLS_BEFORE_VLAN) {
- vlan_tci = 0;
- } else {
- flow->vlan_tci = 0;
- }
ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
&ctx->xout->odp_actions,
&ctx->xout->wc);
}
flow_push_mpls(flow, n, mpls->ethertype, wc);
- flow->vlan_tci = vlan_tci;
}
static void
ofopgroup_submit(group);
}
-/* Deletes 'rule' from 'cls' within 'ofproto'.
+/* Deletes 'rule' from 'ofproto'.
*
* Within an ofproto implementation, this function allows an ofproto
* implementation to destroy any rules that remain when its ->destruct()
.IP "\fBssl:\fIip\fB:\fIport\fR"
The specified SSL \fIport\fR on the host at the given \fIip\fR, which
-must be expressed as an IP address (not a DNS name). The
-\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
+must be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address
+format. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with square
+brackets, e.g.: \fBssl:[::1]:6632\fR.
+The \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR
options are mandatory when this form is used.
.
.IP "\fBtcp:\fIip\fB:\fIport\fR"
-Connect to the given TCP \fIport\fR on \fIip\fR.
+Connect to the given TCP \fIport\fR on \fIip\fR, where \fIip\fR can be IPv4
+or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with
+square brackets, e.g.: \fBtcp:[::1]:6632\fR.
.
.IP "\fBunix:\fIfile\fR"
Connect to the Unix domain server socket named \fIfile\fR.
.IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]"
Listen on the given SSL \fIport\fR for a connection. By default,
-connections are not bound to a particular local IP address, but
+connections are not bound to a particular local IP address and
+it listens only on IPv4 (but not IPv6) addresses, but
specifying \fIip\fR limits connections to those from the given
-\fIip\fR. The \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and
-\fB\-\-ca\-cert\fR options are mandatory when this form is used.
+\fIip\fR, either IPv4 or IPv6 address. If \fIip\fR is
+an IPv6 address, then wrap \fIip\fR with square brackets, e.g.:
+\fBpssl:6632:[::1]\fR. The \fB\-\-private\-key\fR,
+\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory
+when this form is used.
.
.IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]"
Listen on the given TCP \fIport\fR for a connection. By default,
-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.
+\fIip\fR, either IPv4 or IPv6 address. If \fIip\fR is
+an IPv6 address, then wrap \fIip\fR with square brackets, e.g.:
+\fBptcp:6632:[::1]\fR.
.
.IP "\fBpunix:\fIfile\fR"
Listen on the Unix domain server socket named \fIfile\fR for a
-# Copyright (c) 2010, 2012 Nicira, Inc.
+# Copyright (c) 2010, 2012, 2014 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
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]).lstrip('[').rstrip(']')
+ 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
AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),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 p8 'in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
ovs-appctl time/warp 100
+sleep 1 # wait for forwarders process packets
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:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto-dpif - VLAN+MPLS handling])
+OVS_VSWITCHD_START([dnl
+ add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_DATA([flows.txt], [dnl
+cookie=0xa dl_src=40:44:44:44:54:50 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,set_vlan_vid:99,set_vlan_pcp:1,controller
+cookie=0xa dl_src=40:44:44:44:54:51 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,set_vlan_vid:99,set_vlan_pcp:1,controller
+cookie=0xa dl_src=40:44:44:44:54:52 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,load:99->OXM_OF_VLAN_VID[[]],set_vlan_pcp:1,controller
+cookie=0xa dl_src=40:44:44:44:54:53 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,load:99->OXM_OF_VLAN_VID[[]],set_vlan_pcp:1,controller
+cookie=0xa dl_src=40:44:44:44:54:54 actions=push_vlan:0x8100,set_vlan_vid:99,set_vlan_pcp:1,push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xa dl_src=40:44:44:44:54:55 actions=push_vlan:0x8100,set_vlan_vid:99,set_vlan_pcp:1,push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xa dl_src=40:44:44:44:54:56 actions=push_vlan:0x8100,load:99->OXM_OF_VLAN_VID[[]],set_vlan_pcp:1,push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xa dl_src=40:44:44:44:54:57 actions=push_vlan:0x8100,load:99->OXM_OF_VLAN_VID[[]],set_vlan_pcp:1,push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xa dl_src=40:44:44:44:54:58,vlan_tci=0x1000/0x1000 actions=load:99->OXM_OF_VLAN_VID[[]],set_vlan_pcp:1,push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xa dl_src=40:44:44:44:54:59,vlan_tci=0x1000/0x1000 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],set_vlan_pcp:1,load:99->OXM_OF_VLAN_VID[[]],controller
+])
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 add-flows br0 flows.txt])
+
+dnl Modified MPLS controller action.
+dnl In this test, we push the MPLS tag before pushing a VLAN tag, so we see
+dnl both of these in the final flow
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:50,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)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be stripped
+dnl before we push the MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:51,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, we push the MPLS tag before pushing a VLAN tag, so we see
+dnl both of these in the final flow
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:52,dst=52: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)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be stripped
+dnl before we push the MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:53,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, we push the VLAN tag before pushing a MPLS tag, but these
+dnl actions are reordered, so we see both of these in the final flow.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:54,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)'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be stripped
+dnl before we push the MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:55,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, we push the VLAN tag before pushing a MPLS tag, but these
+dnl actions are reordered, so we see both of these in the final flow.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:56,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)'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+00000040 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be stripped
+dnl before we push the MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 -m 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:57,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be stripped
+dnl before we push the MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:58,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+dnl Modified MPLS controller action.
+dnl In this test, the input packet in vlan-tagged, which should be modified
+dnl before we push MPLS and VLAN tags.
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:59,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+dnl
+OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
+00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
+00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
+00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl --protocols=OpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:50 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,set_field:4195->vlan_vid,set_field:1->vlan_pcp,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:51 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,set_field:4195->vlan_vid,set_field:1->vlan_pcp,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:52 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,load:0x63->OXM_OF_VLAN_VID[[]],set_field:1->vlan_pcp,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:53 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],push_vlan:0x8100,load:0x63->OXM_OF_VLAN_VID[[]],set_field:1->vlan_pcp,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:54 actions=push_vlan:0x8100,set_field:4195->vlan_vid,set_field:1->vlan_pcp,push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:55 actions=push_vlan:0x8100,set_field:4195->vlan_vid,set_field:1->vlan_pcp,push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:56 actions=push_vlan:0x8100,load:0x63->OXM_OF_VLAN_VID[[]],set_field:1->vlan_pcp,push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:54:57 actions=push_vlan:0x8100,load:0x63->OXM_OF_VLAN_VID[[]],set_field:1->vlan_pcp,push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, vlan_tci=0x1000/0x1000,dl_src=40:44:44:44:54:58 actions=load:0x63->OXM_OF_VLAN_VID[[]],set_field:1->vlan_pcp,push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, vlan_tci=0x1000/0x1000,dl_src=40:44:44:44:54:59 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],set_field:1->vlan_pcp,load:0x63->OXM_OF_VLAN_VID[[]],CONTROLLER:65535
+OFPST_FLOW reply (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto-dpif - fragment handling])
OVS_VSWITCHD_START
ADD_OF_PORTS([br0], [1], [2], [3], [4], [5], [6], [90])
OVS_VSWITCHD_STOP
AT_CLEANUP
-dnl Test that sFlow samples packets correctly.
-AT_SETUP([ofproto-dpif - sFlow packet sampling])
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-
-ON_EXIT([kill `cat test-sflow.pid`])
-AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > sflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([sflow.log])
-SFLOW_PORT=`parse_listening_port < test-sflow.log`
-
-ovs-appctl time/stop
-
-ADD_OF_PORTS([br0], 1, 2)
-ovs-vsctl \
- set Interface br0 options:ifindex=1002 -- \
- set Interface p1 options:ifindex=1004 -- \
- set Interface p2 options:ifindex=1003 -- \
- set Bridge br0 sflow=@sf -- \
- --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
- header=128 sampling=1 polling=1
-
-dnl open with ARP packets to seed the bridge-learning. The output
-dnl ifIndex numbers should be reported predictably after that.
-dnl Since we set sampling=1 we should see all of these packets
-dnl reported. Sorting the output by data-source and seqNo makes
-dnl it deterministic. Ensuring that we send at least two packets
-dnl into each port means we get to check the seq nos are
-dnl incrementing correctly.
-
-dnl because packets from different ports can be handled by separate
-dnl threads, put some sleeps
-
-ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)'
-sleep 1
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)'
-sleep 1
-ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
-sleep 1
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
-ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
-
-dnl sleep long enough to get more than one counter sample
-dnl from each datasource so we can check sequence numbers
-for i in `seq 1 30`; do
- ovs-appctl time/warp 100
-done
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-sflow exit
+# CHECK_SFLOW_SAMPLING_PACKET(LOOPBACK_ADDR, ADDR_WITHOUT_BRACKETS)
+#
+# Test that sFlow samples packets correctly using IPv4/IPv6 sFlow collector
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_SFLOW_SAMPLING_PACKET],
+ [AT_SETUP([ofproto-dpif - sFlow packet sampling - $2 collector])
+ OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+
+ ON_EXIT([kill `cat test-sflow.pid`])
+ AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
+ AT_CAPTURE_FILE([sflow.log])
+ SFLOW_PORT=`parse_listening_port < test-sflow.log`
+ ovs-appctl time/stop
+
+ ADD_OF_PORTS([br0], 1, 2)
+ ovs-vsctl \
+ set Interface br0 options:ifindex=1002 -- \
+ set Interface p1 options:ifindex=1004 -- \
+ set Interface p2 options:ifindex=1003 -- \
+ set Bridge br0 sflow=@sf -- \
+ --id=@sf create sflow targets=\"$1:$SFLOW_PORT\" \
+ header=128 sampling=1 polling=1 agent=lo
+
+ dnl open with ARP packets to seed the bridge-learning. The output
+ dnl ifIndex numbers should be reported predictably after that.
+ dnl Since we set sampling=1 we should see all of these packets
+ dnl reported. Sorting the output by data-source and seqNo makes
+ dnl it deterministic. Ensuring that we send at least two packets
+ dnl into each port means we get to check the seq nos are
+ dnl incrementing correctly.
+ dnl because packets from different ports can be handled by separate
+ dnl threads, put some sleeps
+
+ ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)'
+ sleep 1
+ ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)'
+ sleep 1
+ ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+ sleep 1
+ ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+ ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
+
+ dnl sleep long enough to get more than one counter sample
+ dnl from each datasource so we can check sequence numbers
+ for i in `seq 1 30`; do
+ ovs-appctl time/warp 100
+ done
+ OVS_VSWITCHD_STOP
+ ovs-appctl -t test-sflow exit
-AT_CHECK([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
+ AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
/g']], [0], [dnl
HEADER
dgramSeqNo=1
hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
])
-AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
+ AT_CHECK_UNQUOTED([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
/g']], [0], [dnl
IFCOUNTERS
dgramSeqNo=2
out_errors=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)
+
+ ovs-appctl time/stop
+ ON_EXIT([kill `cat test-netflow.pid`])
+ AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+ AT_CAPTURE_FILE([netflow.log])
+ NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+
+ ovs-vsctl \
+ set Bridge br0 netflow=@nf -- \
+ --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+ engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
+
+ for delay in 1000 30000; do
+ ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+ ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+
+ ovs-appctl time/warp $delay
+ done
-dnl Test that basic NetFlow reports flow statistics correctly:
-dnl - The initial packet of a flow are correctly accounted.
-dnl - Later packets within a flow are correctly accounted.
-dnl - Flow actions changing (in this case, due to MAC learning)
-dnl cause a record to be sent.
-AT_SETUP([ofproto-dpif - NetFlow flow expiration])
-
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-ADD_OF_PORTS([br0], 1, 2)
-
-ovs-appctl time/stop
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
-
-ovs-vsctl \
- set Bridge br0 netflow=@nf -- \
- --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
- engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
-
-for delay in 1000 30000; do
- ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
- ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
-
- ovs-appctl time/warp $delay
-done
-
-ovs-appctl time/warp 6000
-sleep 1
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-netflow exit
-
-AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
+ ovs-appctl time/warp 6000
+ sleep 1
+ OVS_VSWITCHD_STOP
+ ovs-appctl -t test-netflow exit
-AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
+ AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
-combined=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0" netflow.log | wc -l`
-separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l`
-AT_CHECK([test $separate = 2 || test $combined = 1], [0])
+ AT_CHECK([test `grep "192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0" netflow.log | wc -l` -eq 1])
-AT_CLEANUP
+ combined=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0" netflow.log | wc -l`
+ separate=`grep "192.168.0.2 > 192.168.0.1, if 2 > 1, 1 pkts, 60 bytes, ICMP 0:0" netflow.log | wc -l`
+ AT_CHECK([test $separate = 2 || test $combined = 1], [0])
-dnl Test that basic NetFlow reports active expirations correctly.
-AT_SETUP([ofproto-dpif - NetFlow active expiration])
+ AT_CLEANUP])
-OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
-ADD_OF_PORTS([br0], 1, 2)
+CHECK_NETFLOW_EXPIRATION([127.0.0.1], [IPv4])
+CHECK_NETFLOW_EXPIRATION([[[::1]]], [IPv6])
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+# CHECK_NETFLOW_ACTIVE_EXPIRATION(LOOPBACK_ADDR, IP_VERSION_TYPE)
+#
+# Test that basic NetFlow reports active expirations correctly.
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_NETFLOW_ACTIVE_EXPIRATION],
+ [AT_SETUP([ofproto-dpif - NetFlow active expiration - $2 collector])
-ovs-vsctl \
- set Bridge br0 netflow=@nf -- \
- --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
- engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
+ OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+ ADD_OF_PORTS([br0], 1, 2)
-AT_CHECK([ovs-appctl time/stop])
-n=1
-while test $n -le 60; do
- n=`expr $n + 1`
+ ON_EXIT([kill `cat test-netflow.pid`])
+ AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+ AT_CAPTURE_FILE([netflow.log])
+ NETFLOW_PORT=`parse_listening_port < test-netflow.log`
- ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=1234,dst=80)'
- ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=1234)'
+ ovs-vsctl \
+ set Bridge br0 netflow=@nf -- \
+ --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+ engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
- ovs-appctl time/warp 1000
-done
+ AT_CHECK([ovs-appctl time/stop])
+ n=1
+ while test $n -le 60; do
+ n=`expr $n + 1`
-ovs-appctl time/warp 10000
+ ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=1234,dst=80)'
+ ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=1234)'
-sleep 1
-OVS_VSWITCHD_STOP
-ovs-appctl -t test-netflow exit
-
-# Count the number of reported packets:
-# - From source to destination before MAC learning kicks in (just one).
-# - From source to destination after that.
-# - From destination to source.
-n_learn=0
-n_in=0
-n_out=0
-n_other=0
-n_recs=0
-none=0
-while read line; do
- pkts=`echo "$line" | sed 's/.*, \([[0-9]]*\) pkts,.*/\1/'`
- case $pkts in
- [[0-9]]*) ;;
- *) continue ;;
- esac
-
- case $line in
- "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
- counter=n_learn
- ;;
- "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
- counter=n_in
- ;;
- "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
- counter=n_out
- ;;
- *)
- counter=n_other
- ;;
- esac
- eval $counter=\`expr \$$counter + \$pkts\`
- n_recs=`expr $n_recs + 1`
-done < netflow.log
-
-# There should be exactly 1 MAC learning packet,
-# exactly 59 other packets in that direction,
-# and exactly 60 packets in the other direction.
-AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
-])
+ ovs-appctl time/warp 1000
+ done
-AT_CLEANUP
+ ovs-appctl time/warp 10000
+
+ sleep 1
+ OVS_VSWITCHD_STOP
+ ovs-appctl -t test-netflow exit
+
+ # Count the number of reported packets:
+ # - From source to destination before MAC learning kicks in (just one).
+ # - From source to destination after that.
+ # - From destination to source.
+ n_learn=0
+ n_in=0
+ n_out=0
+ n_other=0
+ n_recs=0
+ none=0
+ while read line; do
+ pkts=`echo "$line" | sed 's/.*, \([[0-9]]*\) pkts,.*/\1/'`
+ case $pkts in
+ [[0-9]]*) ;;
+ *) continue ;;
+ esac
+
+ case $line in
+ "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+ counter=n_learn
+ ;;
+ "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+ counter=n_in
+ ;;
+ "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
+ counter=n_out
+ ;;
+ *)
+ counter=n_other
+ ;;
+ esac
+ eval $counter=\`expr \$$counter + \$pkts\`
+ n_recs=`expr $n_recs + 1`
+ done < netflow.log
+
+ # There should be exactly 1 MAC learning packet,
+ # exactly 59 other packets in that direction,
+ # and exactly 60 packets in the other direction.
+ AT_CHECK([echo $n_learn $n_in $n_out $n_other], [0], [1 59 60 0
+])
+
+ AT_CLEANUP])
+
+CHECK_NETFLOW_ACTIVE_EXPIRATION([127.0.0.1], [IPv4])
+CHECK_NETFLOW_ACTIVE_EXPIRATION([[[::1]]], [IPv6])
AT_SETUP([idle_age and hard_age increase over time])
OVS_VSWITCHD_START
OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([ofproto-dpif megaflow - netflow])
-OVS_VSWITCHD_START
-ADD_OF_PORTS([br0], [1], [2])
-
-dnl NetFlow configuration disables wildcarding relevant fields
-ON_EXIT([kill `cat test-netflow.pid`])
-AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:127.0.0.1 > netflow.log], [0], [], [ignore])
-AT_CAPTURE_FILE([netflow.log])
-NETFLOW_PORT=`parse_listening_port < test-netflow.log`
-ovs-vsctl \
- set Bridge br0 netflow=@nf -- \
- --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
- engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
-
-AT_CHECK([ovs-ofctl add-flow br0 action=normal])
-AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
+# CHECK_MEGAFLOW_NETFLOW(LOOPBACK_ADDR, IP_VERSION_TYPE)
+#
+# IP_VERSION_TYPE is used in AT_SETUP
+m4_define([CHECK_MEGAFLOW_NETFLOW],
+ [AT_SETUP([ofproto-dpif megaflow - netflow - $2 collector])
+ OVS_VSWITCHD_START
+ ADD_OF_PORTS([br0], [1], [2])
+
+ dnl NetFlow configuration disables wildcarding relevant fields
+ ON_EXIT([kill `cat test-netflow.pid`])
+ AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+ AT_CAPTURE_FILE([netflow.log])
+ NETFLOW_PORT=`parse_listening_port < test-netflow.log`
+ ovs-vsctl \
+ set Bridge br0 netflow=@nf -- \
+ --id=@nf create NetFlow targets=\"$1:$NETFLOW_PORT\" \
+ engine_id=1 engine_type=2 active_timeout=30 add-id-to-interface=false
+
+ AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+ sleep 1
+ AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
])
-OVS_VSWITCHD_STOP
-AT_CLEANUP
+ OVS_VSWITCHD_STOP
+ AT_CLEANUP])
+
+CHECK_MEGAFLOW_NETFLOW([127.0.0.1], [IPv4])
+CHECK_MEGAFLOW_NETFLOW([[[::1]]], [IPv6])
AT_SETUP([ofproto-dpif megaflow - normal, active-backup bonding])
OVS_VSWITCHD_START(
# log, given that the server was told to listen on a kernel-chosen
# port, file provided on stdin, and prints the port number on stdout.
# You should specify the listening remote as ptcp:0:127.0.0.1 or
-# pssl:0:127.0.0.1.
+# pssl:0:127.0.0.1, or the equivalent with [::1] instead of 127.0.0.1.
#
# Here's an example of how to use this with ovsdb-server:
#
# ovsdb-server --log-file --remote=ptcp:0:127.0.0.1 ...
# TCP_PORT=`parse_listening_port < ovsdb-server.log`
parse_listening_port () {
- sed -n 's/.*0:127\.0\.0\.1: listening on port \([0-9]*\)$/\1/p'
+ sed -n 's/.*0:.*: listening on port \([0-9]*\)$/\1/p'
}]
m4_divert_pop([PREPARE_TESTS])
[[[{"uuid":["uuid","<0>"]},{"details":"This \"uuid-name\" appeared on an earlier \"insert\" operation.","error":"duplicate uuid-name","syntax":"\"x\""}]
]])
-m4_define([EXECUTION_EXAMPLES], [
+m4_define([ONE_EXECUTION_EXAMPLE], [dnl
dnl At one point the "commit" code ignored new rows with all-default values,
dnl so this checks for that problem.
OVSDB_CHECK_EXECUTION([insert default row, query table],
[[[{"uuid":["uuid","<0>"]}]
[{"rows":[{"_uuid":["uuid","<0>"],"_version":["uuid","<1>"],"name":"","number":0}]}]
]])
+])
+m4_define([EXECUTION_EXAMPLES], [
+ONE_EXECUTION_EXAMPLE
OVSDB_CHECK_EXECUTION([insert row, query table],
[ordinal_schema],
[[[["ordinals",
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP])
+# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp6
+m4_define([OVSDB_CHECK_IDL_TCP6_PY],
+ [AT_SETUP([$1 - Python tcp6])
+ AT_SKIP_IF([test $HAVE_PYTHON = no])
+ AT_KEYWORDS([ovsdb server idl positive Python with tcp6 socket $5])
+ OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+ OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+ AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
+ [0], [stdout], [ignore])
+ AT_CHECK([ovsdb-server --log-file '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+ TCP_PORT=`parse_listening_port < ovsdb-server.log`
+ echo "TCP_PORT=$TCP_PORT"
+
+ m4_if([$2], [], [],
+ [AT_CHECK([ovsdb-client transact "tcp:[[::1]]:$TCP_PORT" $2], [0], [ignore], [ignore], [kill `cat pid`])])
+ AT_CHECK([$PYTHON $srcdir/test-ovsdb.py -t10 idl $srcdir/idltest.ovsschema tcp:[[::1]]:$TCP_PORT $3],
+ [0], [stdout], [ignore], [kill `cat pid`])
+ AT_CHECK([sort stdout | ${PERL} $srcdir/uuidfilt.pl]m4_if([$6],,, [[| $6]]),
+ [0], [$4], [], [kill `cat pid`])
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
m4_define([OVSDB_CHECK_IDL],
[OVSDB_CHECK_IDL_C($@)
OVSDB_CHECK_IDL_PY($@)
- OVSDB_CHECK_IDL_TCP_PY($@)])
+ OVSDB_CHECK_IDL_TCP_PY($@)
+ OVSDB_CHECK_IDL_TCP6_PY($@)])
OVSDB_CHECK_IDL([simple idl, initially empty, no ops],
[],
done
AT_CLEANUP
\f
-AT_BANNER([OVSDB -- ovsdb-server transactions (SSL sockets)])
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv4 sockets)])
# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
#
EXECUTION_EXAMPLES
-AT_BANNER([OVSDB -- ovsdb-server transactions (TCP sockets)])
+AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv6 sockets)])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number. The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+ [AT_SETUP([$1])
+ AT_KEYWORDS([ovsdb server positive ssl6 $5])
+ AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+ OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+ OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+ $2 > schema
+ PKIDIR=$abs_top_builddir/tests
+ AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+ AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --private-key=$PKIDIR/testpki-privkey2.pem --certificate=$PKIDIR/testpki-cert2.pem --ca-cert=$PKIDIR/testpki-cacert.pem --remote=pssl:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+ SSL_PORT=`parse_listening_port < ovsdb-server.log`
+ m4_foreach([txn], [$3],
+ [AT_CHECK([ovsdb-client --private-key=$PKIDIR/testpki-privkey.pem --certificate=$PKIDIR/testpki-cert.pem --ca-cert=$PKIDIR/testpki-cacert.pem transact ssl:[[::1]]:$SSL_PORT 'txn'], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+ AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+ [test ! -e pid || kill `cat pid`])
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (TCP IPv4 sockets)])
AT_SETUP([ovsdb-client get-schema-version - tcp socket])
AT_KEYWORDS([ovsdb server positive tcp])
AT_CLEANUP])
EXECUTION_EXAMPLES
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number. The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+ [AT_SETUP([$1])
+ AT_KEYWORDS([ovsdb server positive tcp6 $5])
+ OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+ OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+ $2 > schema
+ PKIDIR=$abs_top_builddir/tests
+ AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+ AT_CHECK([ovsdb-server --log-file --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:0:[[::1]] --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+ TCP_PORT=`parse_listening_port < ovsdb-server.log`
+ m4_foreach([txn], [$3],
+ [AT_CHECK([ovsdb-client transact tcp:[[::1]]:$TCP_PORT 'txn'], [0], [stdout], [ignore],
+ [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+ AT_CHECK([${PERL} $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+ [test ! -e pid || kill `cat pid`])
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
+ONE_EXECUTION_EXAMPLE
\f
AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
/*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
* Copyright (c) 2013 InMon Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
/* Datagram. */
#define SFLOW_VERSION_5 5
#define SFLOW_MIN_LEN 36
-#define SFLOW_MAX_AGENTIP_STRLEN 64
/* Sample tag numbers. */
#define SFLOW_FLOW_SAMPLE 1
/* Agent. */
struct sflow_addr agentAddr;
- char agentIPStr[SFLOW_MAX_AGENTIP_STRLEN];
+ char agentIPStr[INET6_ADDRSTRLEN + 2];
uint32_t subAgentId;
uint32_t uptime_mS;
/* Store the agent address as a string. */
if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
- snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
- "%04x:%04x:%04x:%04x",
- x->agentAddr.a.ip6[0],
- x->agentAddr.a.ip6[1],
- x->agentAddr.a.ip6[2],
- x->agentAddr.a.ip6[3]);
+ char ipstr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, (const void *) &x->agentAddr.a.ip6,
+ ipstr, INET6_ADDRSTRLEN);
+ snprintf(x->agentIPStr, sizeof x->agentIPStr, "[%s]", ipstr);
} else {
- snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
+ snprintf(x->agentIPStr, sizeof x->agentIPStr,
IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
}
managers = xmalloc(sset_count(&targets) * sizeof *managers);
SSET_FOR_EACH (target, &targets) {
- struct sockaddr_in *sin = &managers[n_managers];
+ struct sockaddr_storage ss;
- if (stream_parse_target_with_default_port(target,
- OVSDB_OLD_PORT,
- sin)) {
- n_managers++;
+ if (stream_parse_target_with_default_port(target, OVSDB_OLD_PORT,
+ &ss)
+ && ss.ss_family == AF_INET) {
+ managers[n_managers++] = *(struct sockaddr_in *) &ss;
}
}
}
</dd>
<dt><code>tcp:<var>ip</var></code>[<code>:<var>port</var></code>]</dt>
<dd>
- <p>The specified TCP <var>port</var> on the host at the
- given <var>ip</var>, which must be expressed as an IP
- address (not a DNS name).</p>
- <p>If <var>port</var> is not specified, it currently
- defaults to 6633. In the future, the default will change to
- 6653, which is the IANA-defined value.</p>
+ <p>
+ The specified TCP <var>port</var> on the host at the given
+ <var>ip</var>, which must be expressed as an IP address (not a
+ DNS name), where <var>ip</var> can be IPv4 or IPv6 address. If
+ <var>ip</var> is an IPv6 address, wrap it in square brackets,
+ e.g. <code>tcp:[::1]:6632</code>.
+ </p>
+ <p>
+ If <var>port</var> is not specified, it currently defaults to
+ 6633. In the future, the default will change to 6653, which is
+ the IANA-defined value.
+ </p>
</dd>
</dl>
<p>
<dl>
<dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd>
- <p> Listens for SSL connections on the specified TCP
- <var>port</var>. If <var>ip</var>, which must be expressed
- as an IP address (not a DNS name), is specified, then
- connections are restricted to the specified local IP
- address. The <ref table="Open_vSwitch" column="ssl"/>
- column in the <ref table="Open_vSwitch"/> table must point
- to a valid SSL configuration when this form is used.</p>
- <p>If <var>port</var> is not specified, it currently
- defaults to 6633. In the future, the default will change to
- 6653, which is the IANA-defined value.</p>
- <p>SSL support is an optional feature that is not always built as
- part of Open vSwitch.</p>
+ <p>
+ Listens for SSL connections on the specified TCP <var>port</var>.
+ If <var>ip</var>, which must be expressed as an IP address (not a
+ DNS name), is specified, then connections are restricted to the
+ specified local IP address (either IPv4 or IPv6). If
+ <var>ip</var> is an IPv6 address, wrap it in square brackets,
+ e.g. <code>pssl:6632:[::1]</code>.
+ </p>
+ <p>
+ If <var>port</var> is not specified, it currently defaults to
+ 6633. If <var>ip</var> is not specified then it listens only on
+ IPv4 (but not IPv6) addresses. The
+ <ref table="Open_vSwitch" column="ssl"/>
+ column in the <ref table="Open_vSwitch"/> table must point to a
+ valid SSL configuration when this form is used.
+ </p>
+ <p>
+ If <var>port</var> is not specified, it currently defaults to
+ 6633. In the future, the default will change to 6653, which is
+ the IANA-defined value.
+ </p>
+ <p>
+ SSL support is an optional feature that is not always built as
+ part of Open vSwitch.
+ </p>
</dd>
<dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd>
- <p>Listens for connections on the specified TCP
- <var>port</var>. If <var>ip</var>, which must be expressed
- as an IP address (not a DNS name), is specified, then
- connections are restricted to the specified local IP
- address.</p>
- <p>If <var>port</var> is not specified, it currently
- defaults to 6633. In the future, the default will change to
- 6653, which is the IANA-defined value.</p>
+ <p>
+ Listens for connections on the specified TCP <var>port</var>. If
+ <var>ip</var>, which must be expressed as an IP address (not a
+ DNS name), is specified, then connections are restricted to the
+ specified local IP address (either IPv4 or IPv6). If
+ <var>ip</var> is an IPv6 address, wrap it in square brackets,
+ e.g. <code>ptcp:6632:[::1]</code>. If <var>ip</var> is not
+ specified then it listens only on IPv4 addresses.
+ </p>
+ <p>
+ If <var>port</var> is not specified, it currently defaults to
+ 6633. In the future, the default will change to 6653, which is
+ the IANA-defined value.
+ </p>
</dd>
</dl>
<p>When multiple controllers are configured for a single bridge, the
<dd>
<p>
The specified TCP <var>port</var> on the host at the given
- <var>ip</var>, which must be expressed as an IP address
- (not a DNS name).
+ <var>ip</var>, which must be expressed as an IP address (not a
+ DNS name), where <var>ip</var> can be IPv4 or IPv6 address. If
+ <var>ip</var> is an IPv6 address, wrap it in square brackets,
+ e.g. <code>tcp:[::1]:6632</code>.
</p>
<p>
If <var>port</var> is not specified, it currently defaults
<dt><code>pssl:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd>
<p>
- Listens for SSL connections on the specified TCP
- <var>port</var>. Specify 0 for <var>port</var> to have
- the kernel automatically choose an available port. If
- <var>ip</var>, which must be expressed as an IP address
- (not a DNS name), is specified, then connections are
- restricted to the specified local IP address. The <ref
- table="Open_vSwitch" column="ssl"/> column in the <ref
+ Listens for SSL connections on the specified TCP <var>port</var>.
+ Specify 0 for <var>port</var> to have the kernel automatically
+ choose an available port. If <var>ip</var>, which must be
+ expressed as an IP address (not a DNS name), is specified, then
+ connections are restricted to the specified local IP address
+ (either IPv4 or IPv6 address). If <var>ip</var> is an IPv6
+ address, wrap in square brackets,
+ e.g. <code>pssl:6632:[::1]</code>. If <var>ip</var> is not
+ specified then it listens only on IPv4 (but not IPv6) addresses.
+ The <ref table="Open_vSwitch" column="ssl"/> column in the <ref
table="Open_vSwitch"/> table must point to a valid SSL
configuration when this form is used.
</p>
<dt><code>ptcp:</code>[<var>port</var>][<code>:<var>ip</var></code>]</dt>
<dd>
<p>
- Listens for connections on the specified TCP
- <var>port</var>. Specify 0 for <var>port</var> to have
- the kernel automatically choose an available port. If
- <var>ip</var>, which must be expressed as an IP address
- (not a DNS name), is specified, then connections are
- restricted to the specified local IP address.
+ Listens for connections on the specified TCP <var>port</var>.
+ Specify 0 for <var>port</var> to have the kernel automatically
+ choose an available port. If <var>ip</var>, which must be
+ expressed as an IP address (not a DNS name), is specified, then
+ connections are restricted to the specified local IP address
+ (either IPv4 or IPv6 address). If <var>ip</var> is an IPv6
+ address, wrap it in square brackets,
+ e.g. <code>ptcp:6632:[::1]</code>. If <var>ip</var> is not
+ specified then it listens only on IPv4 addresses.
</p>
<p>
If <var>port</var> is not specified, it currently defaults