/*
- * 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.
VCS_DISCONNECTED /* Connection failed or connection closed. */
};
-static struct vconn_class *vconn_classes[] = {
+static const struct vconn_class *vconn_classes[] = {
&tcp_vconn_class,
&unix_vconn_class,
#ifdef HAVE_OPENSSL
#endif
};
-static struct pvconn_class *pvconn_classes[] = {
+static const struct pvconn_class *pvconn_classes[] = {
&ptcp_pvconn_class,
&punix_pvconn_class,
#ifdef HAVE_OPENSSL
size_t i;
for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
- struct vconn_class *class = vconn_classes[i];
+ const struct vconn_class *class = vconn_classes[i];
ovs_assert(class->name != NULL);
ovs_assert(class->open != NULL);
if (class->close || class->recv || class->send
}
for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
- struct pvconn_class *class = pvconn_classes[i];
+ const struct pvconn_class *class = pvconn_classes[i];
ovs_assert(class->name != NULL);
ovs_assert(class->listen != NULL);
if (class->close || class->accept || class->wait) {
if (active) {
printf("Active OpenFlow connection methods:\n");
printf(" tcp:IP[:PORT] "
- "PORT (default: %d) at remote IP\n", OFP_TCP_PORT);
+ "PORT (default: %d) at remote IP\n", OFP_OLD_PORT);
#ifdef HAVE_OPENSSL
printf(" ssl:IP[:PORT] "
- "SSL PORT (default: %d) at remote IP\n", OFP_SSL_PORT);
+ "SSL PORT (default: %d) at remote IP\n", OFP_OLD_PORT);
#endif
printf(" unix:FILE Unix domain socket named FILE\n");
}
printf("Passive OpenFlow connection methods:\n");
printf(" ptcp:[PORT][:IP] "
"listen to TCP PORT (default: %d) on IP\n",
- OFP_TCP_PORT);
+ OFP_OLD_PORT);
#ifdef HAVE_OPENSSL
printf(" pssl:[PORT][:IP] "
"listen for SSL on PORT (default: %d) on IP\n",
- OFP_SSL_PORT);
+ OFP_OLD_PORT);
#endif
printf(" punix:FILE "
"listen on Unix domain socket FILE\n");
* a null pointer into '*classp' if 'name' is in the wrong form or if no such
* class exists. */
static int
-vconn_lookup_class(const char *name, struct vconn_class **classp)
+vconn_lookup_class(const char *name, const struct vconn_class **classp)
{
size_t prefix_len;
size_t i;
for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
- struct vconn_class *class = vconn_classes[i];
+ const struct vconn_class *class = vconn_classes[i];
if (strlen(class->name) == prefix_len
&& !memcmp(class->name, name, prefix_len)) {
*classp = class;
int
vconn_verify_name(const char *name)
{
- struct vconn_class *class;
+ const struct vconn_class *class;
return vconn_lookup_class(name, &class);
}
vconn_open(const char *name, uint32_t allowed_versions, uint8_t dscp,
struct vconn **vconnp)
{
- struct vconn_class *class;
+ const struct vconn_class *class;
struct vconn *vconn;
char *suffix_copy;
int error;
}
}
+/* Returns 0 if 'vconn' is healthy (connecting or connected), a positive errno
+ * value if the connection died abnormally (connection failed or aborted), or
+ * EOF if the connection was closed in a normal way. */
+int
+vconn_get_status(const struct vconn *vconn)
+{
+ return vconn->error == EAGAIN ? 0 : vconn->error;
+}
+
int
vconn_open_block(const char *name, uint32_t allowed_versions, uint8_t dscp,
struct vconn **vconnp)
vconn->allowed_versions = allowed_versions;
}
-/* Returns the IP address of the peer, or 0 if the peer is not connected over
- * an IP-based protocol or if its IP address is not yet known. */
-ovs_be32
-vconn_get_remote_ip(const struct vconn *vconn)
-{
- return vconn->remote_ip;
-}
-
-/* Returns the transport port of the peer, or 0 if the connection does not
- * contain a port or if the port is not yet known. */
-ovs_be16
-vconn_get_remote_port(const struct vconn *vconn)
-{
- return vconn->remote_port;
-}
-
-/* Returns the IP address used to connect to the peer, or 0 if the
- * connection is not an IP-based protocol or if its IP address is not
- * yet known. */
-ovs_be32
-vconn_get_local_ip(const struct vconn *vconn)
-{
- return vconn->local_ip;
-}
-
-/* Returns the transport port used to connect to the peer, or 0 if the
- * connection does not contain a port or if the port is not yet known. */
-ovs_be16
-vconn_get_local_port(const struct vconn *vconn)
-{
- return vconn->local_port;
-}
-
/* Returns the OpenFlow version negotiated with the peer, or -1 if version
* negotiation is not yet complete.
*
return vconn->version ? vconn->version : -1;
}
+/* By default, a vconn accepts only OpenFlow messages whose version matches the
+ * one negotiated for the connection. A message received with a different
+ * version is an error that causes the vconn to drop the connection.
+ *
+ * This functions allows 'vconn' to accept messages with any OpenFlow version.
+ * This is useful in the special case where 'vconn' is used as an rconn
+ * "monitor" connection (see rconn_add_monitor()), that is, where 'vconn' is
+ * used as a target for mirroring OpenFlow messages for debugging and
+ * troubleshooting.
+ *
+ * This function should be called after a successful vconn_open() or
+ * pvconn_accept() but before the connection completes, that is, before
+ * vconn_connect() returns success. Otherwise, messages that arrive on 'vconn'
+ * beforehand with an unexpected version will the vconn to drop the
+ * connection. */
+void
+vconn_set_recv_any_version(struct vconn *vconn)
+{
+ vconn->recv_any_version = true;
+}
+
static void
vcs_connecting(struct vconn *vconn)
{
} else if (is_pow2((bitmap >> 1) + 1)) {
ds_put_cstr(&s, "version ");
ofputil_format_version(&s, leftmost_1bit_idx(bitmap));
- ds_put_cstr(&s, "and earlier");
+ ds_put_cstr(&s, " and earlier");
} else {
ds_put_cstr(&s, "versions ");
ofputil_format_version_bitmap(&s, bitmap);
enum ofptype type;
enum ofperr error;
- error = ofptype_decode(&type, b->data);
+ error = ofptype_decode(&type, ofpbuf_data(b));
if (!error && type == OFPTYPE_HELLO) {
char *peer_s, *local_s;
uint32_t common_versions;
- if (!ofputil_decode_hello(b->data, &vconn->peer_versions)) {
+ if (!ofputil_decode_hello(ofpbuf_data(b), &vconn->peer_versions)) {
struct ds msg = DS_EMPTY_INITIALIZER;
ds_put_format(&msg, "%s: unknown data in hello:\n",
vconn->name);
- ds_put_hex_dump(&msg, b->data, b->size, 0, true);
+ ds_put_hex_dump(&msg, ofpbuf_data(b), ofpbuf_size(b), 0, true);
VLOG_WARN_RL(&bad_ofmsg_rl, "%s", ds_cstr(&msg));
ds_destroy(&msg);
}
ofpbuf_delete(b);
return;
} else {
- char *s = ofp_to_string(b->data, b->size, 1);
+ char *s = ofp_to_string(ofpbuf_data(b), ofpbuf_size(b), 1);
VLOG_WARN_RL(&bad_ofmsg_rl,
"%s: received message while expecting hello: %s",
vconn->name, s);
return vconn->error;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
} while (vconn->state != last_state);
if (!retval) {
retval = do_recv(vconn, &msg);
}
- if (!retval) {
- const struct ofp_header *oh = msg->data;
+ if (!retval && !vconn->recv_any_version) {
+ const struct ofp_header *oh = ofpbuf_data(msg);
if (oh->version != vconn->version) {
enum ofptype type;
- if (ofptype_decode(&type, msg->data)
+ if (ofptype_decode(&type, ofpbuf_data(msg))
|| (type != OFPTYPE_HELLO &&
type != OFPTYPE_ERROR &&
type != OFPTYPE_ECHO_REQUEST &&
type != OFPTYPE_ECHO_REPLY)) {
+ struct ofpbuf *reply;
+
VLOG_ERR_RL(&bad_ofmsg_rl, "%s: received OpenFlow version "
"0x%02"PRIx8" != expected %02x",
vconn->name, oh->version, vconn->version);
+
+ /* Send a "bad version" reply, if we can. */
+ reply = ofperr_encode_reply(OFPERR_OFPBRC_BAD_VERSION, oh);
+ retval = vconn_send(vconn, reply);
+ if (retval) {
+ VLOG_INFO_RL(&bad_ofmsg_rl,
+ "%s: failed to queue error reply (%s)",
+ vconn->name, ovs_strerror(retval));
+ ofpbuf_delete(reply);
+ }
+
+ /* Suppress the received message, as if it had not arrived. */
+ retval = EAGAIN;
ofpbuf_delete(msg);
- retval = EPROTO;
}
}
}
if (!retval) {
COVERAGE_INC(vconn_received);
if (VLOG_IS_DBG_ENABLED()) {
- char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
+ char *s = ofp_to_string(ofpbuf_data(*msgp), ofpbuf_size(*msgp), 1);
VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
free(s);
}
{
int retval;
- ovs_assert(msg->size >= sizeof(struct ofp_header));
+ ovs_assert(ofpbuf_size(msg) >= sizeof(struct ofp_header));
ofpmsg_update_length(msg);
if (!VLOG_IS_DBG_ENABLED()) {
COVERAGE_INC(vconn_sent);
retval = (vconn->class->send)(vconn, msg);
} else {
- char *s = ofp_to_string(msg->data, msg->size, 1);
+ char *s = ofp_to_string(ofpbuf_data(msg), ofpbuf_size(msg), 1);
retval = (vconn->class->send)(vconn, msg);
if (retval != EAGAIN) {
VLOG_DBG_RL(&ofmsg_rl, "%s: sent (%s): %s",
- vconn->name, strerror(retval), s);
+ vconn->name, ovs_strerror(retval), s);
}
free(s);
}
return retval;
}
-/* Waits until a message with a transaction ID matching 'xid' is recived on
+/* Waits until a message with a transaction ID matching 'xid' is received on
* 'vconn'. Returns 0 if successful, in which case the reply is stored in
* '*replyp' for the caller to examine and free. Otherwise returns a positive
* errno value, or EOF, and sets '*replyp' to null.
*replyp = NULL;
return error;
}
- recv_xid = ((struct ofp_header *) reply->data)->xid;
+ recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid;
if (xid == recv_xid) {
*replyp = reply;
return 0;
vconn_transact(struct vconn *vconn, struct ofpbuf *request,
struct ofpbuf **replyp)
{
- ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
+ ovs_be32 send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
int error;
*replyp = NULL;
*replyp = NULL;
/* Send request. */
- request_xid = ((struct ofp_header *) request->data)->xid;
+ request_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
error = vconn_send_block(vconn, request);
if (error) {
ofpbuf_delete(request);
/* Send barrier. */
barrier = ofputil_encode_barrier_request(vconn_get_version(vconn));
- barrier_xid = ((struct ofp_header *) barrier->data)->xid;
+ barrier_xid = ((struct ofp_header *) ofpbuf_data(barrier))->xid;
error = vconn_send_block(vconn, barrier);
if (error) {
ofpbuf_delete(barrier);
return error;
}
- msg_xid = ((struct ofp_header *) msg->data)->xid;
+ msg_xid = ((struct ofp_header *) ofpbuf_data(msg))->xid;
if (msg_xid == request_xid) {
if (*replyp) {
VLOG_WARN_RL(&bad_ofmsg_rl, "%s: duplicate replies with "
* a null pointer into '*classp' if 'name' is in the wrong form or if no such
* class exists. */
static int
-pvconn_lookup_class(const char *name, struct pvconn_class **classp)
+pvconn_lookup_class(const char *name, const struct pvconn_class **classp)
{
size_t prefix_len;
size_t i;
for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
- struct pvconn_class *class = pvconn_classes[i];
+ const struct pvconn_class *class = pvconn_classes[i];
if (strlen(class->name) == prefix_len
&& !memcmp(class->name, name, prefix_len)) {
*classp = class;
int
pvconn_verify_name(const char *name)
{
- struct pvconn_class *class;
+ const struct pvconn_class *class;
return pvconn_lookup_class(name, &class);
}
pvconn_open(const char *name, uint32_t allowed_versions, uint8_t dscp,
struct pvconn **pvconnp)
{
- struct pvconn_class *class;
+ const struct pvconn_class *class;
struct pvconn *pvconn;
char *suffix_copy;
int error;
*
* The caller retains ownership of 'name'. */
void
-vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
- const char *name, uint32_t allowed_versions)
+vconn_init(struct vconn *vconn, const struct vconn_class *class,
+ int connect_status, const char *name, uint32_t allowed_versions)
{
+ memset(vconn, 0, sizeof *vconn);
vconn->class = class;
vconn->state = (connect_status == EAGAIN ? VCS_CONNECTING
: !connect_status ? VCS_SEND_HELLO
: VCS_DISCONNECTED);
vconn->error = connect_status;
- vconn->version = 0;
vconn->allowed_versions = allowed_versions;
- vconn->remote_ip = 0;
- vconn->remote_port = 0;
- vconn->local_ip = 0;
- vconn->local_port = 0;
vconn->name = xstrdup(name);
ovs_assert(vconn->state != VCS_CONNECTING || class->connect);
}
void
-vconn_set_remote_ip(struct vconn *vconn, ovs_be32 ip)
-{
- vconn->remote_ip = ip;
-}
-
-void
-vconn_set_remote_port(struct vconn *vconn, ovs_be16 port)
-{
- vconn->remote_port = port;
-}
-
-void
-vconn_set_local_ip(struct vconn *vconn, ovs_be32 ip)
-{
- vconn->local_ip = ip;
-}
-
-void
-vconn_set_local_port(struct vconn *vconn, ovs_be16 port)
-{
- vconn->local_port = port;
-}
-
-void
-pvconn_init(struct pvconn *pvconn, struct pvconn_class *class,
+pvconn_init(struct pvconn *pvconn, const struct pvconn_class *class,
const char *name, uint32_t allowed_versions)
{
pvconn->class = class;