#include <assert.h>
#include <errno.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include "bridge.h"
#include "cfg.h"
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
static struct svec capabilities;
static struct ofpbuf ext_data_buffer;
+static uint32_t ext_data_xid = UINT32_MAX;
uint64_t mgmt_id;
static char *private_key_file;
static char *certificate_file;
static char *cacert_file;
+ struct stat s;
/* XXX SSL should be configurable separate from the bridges.
* XXX should be possible to de-configure SSL. */
vconn_ssl_set_certificate_file(certificate_file);
}
- if (config_string_change("ssl.ca-cert", &cacert_file)) {
+ /* We assume that even if the filename hasn't changed, if the CA cert
+ * file has been removed, that we want to move back into
+ * boot-strapping mode. This opens a small security hole, because
+ * the old certificate will still be trusted until vSwitch is
+ * restarted. We may want to address this in vconn's SSL library. */
+ if (config_string_change("ssl.ca-cert", &cacert_file)
+ || (stat(cacert_file, &s) && errno == ENOENT)) {
vconn_ssl_set_ca_cert_file(cacert_file,
cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
}
if (retval == EAFNOSUPPORT) {
VLOG_ERR("no support for %s vconn", controller_name);
}
+
+ /* Reset the extended message buffer when we create a new
+ * management connection. */
+ ofpbuf_clear(&ext_data_buffer);
}
static void *
return EINVAL;
}
+ /* Make sure there's room to transmit the data. We don't want to
+ * fail part way through a send. */
+ if (rconn_packet_counter_read(txqlen) >= TXQ_LIMIT) {
+ return EAGAIN;
+ }
+
/* OpenFlow messages use a 16-bit length field, so messages over 64K
* must be broken into multiple pieces.
*/
if (buffer->size <= 65535) {
update_openflow_length(buffer);
- retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
+ retval = rconn_send(mgmt_rconn, buffer, txqlen);
if (retval) {
VLOG_WARN_RL(&rl, "send to %s failed: %s",
rconn_get_name(mgmt_rconn), strerror(retval));
&new_buffer);
oed->type = header->type;
- if (remain > 65535) {
+ if (remain > new_len) {
oed->flags |= OFMPEDF_MORE_DATA;
}
- printf("xxx SENDING LEN: %d\n", new_len);
-
/* Copy the entire original message, including the OpenFlow
* header, since management protocol structure definitions
* include these headers.
ofpbuf_put(new_buffer, ptr, new_len);
update_openflow_length(new_buffer);
- retval = rconn_send_with_limit(mgmt_rconn, new_buffer, txqlen,
- TXQ_LIMIT);
+ retval = rconn_send(mgmt_rconn, new_buffer, txqlen);
if (retval) {
VLOG_WARN_RL(&rl, "send to %s failed: %s",
rconn_get_name(mgmt_rconn), strerror(retval));
send_openflow_buffer(buffer);
}
-static void
-send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code,
- const void *data, size_t len)
-{
- struct ofpbuf *buffer;
- struct ofmp_error_msg *oem;
-
- oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
- oem->type = htons(type);
- oem->code = htons(code);
- memcpy(oem->data, data, len);
- send_openflow_buffer(buffer);
-}
-
static void
send_error_msg(uint32_t xid, uint16_t type, uint16_t code,
const void *data, size_t len)
/* xxx cfg_lock can fail for other reasons, such as being
* xxx locked... */
VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
+
+ /* Check if our local view matches the controller, in which
+ * case, it is likely that there were local modifications
+ * without our being told to reread the config file. */
+ if (!memcmp(cfg_cookie, ofmpcu->cookie, sizeof cfg_cookie)) {
+ VLOG_WARN_RL(&rl, "config appears to have been locally modified "
+ "without having told ovs-vswitchd to reload");
+ }
send_config_update_ack(xid, false);
return 0;
}
recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
size_t len)
{
- size_t data_len;
+ int data_len;
struct ofmp_extended_data *ofmped;
- uint8_t *ptr;
- data_len = len - sizeof(*ofmped);
- if (data_len <= sizeof(*ofmped)) {
+ if (len <= sizeof(*ofmped)) {
/* xxx Send error. */
return -EINVAL;
}
+ ext_data_xid = xid;
ofmped = (struct ofmp_extended_data *)ofmph;
- ptr = ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
+ data_len = len - sizeof(*ofmped);
+ ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
+
+ if (!(ofmped->flags & OFMPEDF_MORE_DATA)) {
+ struct ofmp_header *new_oh;
+ int error;
+
+ /* An embedded message must be greater than the size of an
+ * OpenFlow message. */
+ new_oh = ofpbuf_at(&ext_data_buffer, 0, 65536);
+ if (!new_oh) {
+ VLOG_WARN_RL(&rl, "received short embedded message: %zu\n",
+ ext_data_buffer.size);
+ return -EINVAL;
+ }
+
+ /* Make sure that this is a management message and that there's
+ * not an embedded extended data message. */
+ if ((new_oh->header.vendor != htonl(NX_VENDOR_ID))
+ || (new_oh->header.subtype != htonl(NXT_MGMT))
+ || (new_oh->type == htonl(OFMPT_EXTENDED_DATA))) {
+ VLOG_WARN_RL(&rl, "received bad embedded message\n");
+ return -EINVAL;
+ }
+ new_oh->header.header.xid = ext_data_xid;
+ new_oh->header.header.length = 0;
- if (!ofmped->flags & OFMPEDF_MORE_DATA) {
- recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
+ error = recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
ofpbuf_clear(&ext_data_buffer);
+
+ return error;
}
return 0;
len = ntohs(ofmph->header.header.length);
}
+ /* Reset the extended data buffer if this isn't a continuation of an
+ * existing extended data message. */
+ if (ext_data_xid != xid) {
+ ofpbuf_clear(&ext_data_buffer);
+ }
+
/* xxx Should sanity-check for min/max length */
switch (ntohs(ofmph->type))
{