X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fmgmt.c;h=5a0e3fb6f51ee019cfffb2076f5099967389a47d;hb=67a4917b07031b387beafaedce413b4207214059;hp=a65934b6e40de6e61c5e0c9f41f7c16d75882890;hpb=23834de273c6bd42362f4e6c013703c5b6fa2fd5;p=openvswitch diff --git a/vswitchd/mgmt.c b/vswitchd/mgmt.c index a65934b6..5a0e3fb6 100644 --- a/vswitchd/mgmt.c +++ b/vswitchd/mgmt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009 Nicira Networks +/* Copyright (c) 2009, 2010 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include "bridge.h" #include "cfg.h" @@ -51,6 +54,7 @@ static struct rconn *mgmt_rconn; 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; @@ -101,6 +105,7 @@ mgmt_configure_ssl(void) 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. */ @@ -112,7 +117,13 @@ mgmt_configure_ssl(void) 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")); } @@ -131,6 +142,7 @@ mgmt_reconfigure(void) int retval; if (!cfg_has_section("mgmt")) { + svec_clear(&mgmt_cfg); if (mgmt_rconn) { rconn_destroy(mgmt_rconn); mgmt_rconn = NULL; @@ -211,6 +223,10 @@ mgmt_reconfigure(void) 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 * @@ -250,12 +266,18 @@ send_openflow_buffer(struct ofpbuf *buffer) 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)); @@ -281,12 +303,10 @@ send_openflow_buffer(struct ofpbuf *buffer) &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. @@ -294,8 +314,7 @@ send_openflow_buffer(struct ofpbuf *buffer) 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)); @@ -515,20 +534,6 @@ send_config_update_ack(uint32_t xid, bool success) 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) @@ -544,7 +549,7 @@ send_error_msg(uint32_t xid, uint16_t type, uint16_t code, } static int -recv_echo_request(uint32_t xid UNUSED, const void *msg) +recv_echo_request(uint32_t xid OVS_UNUSED, const void *msg) { const struct ofp_header *rq = msg; send_openflow_buffer(make_echo_reply(rq)); @@ -552,14 +557,14 @@ recv_echo_request(uint32_t xid UNUSED, const void *msg) } static int -recv_features_request(uint32_t xid, const void *msg UNUSED) +recv_features_request(uint32_t xid, const void *msg OVS_UNUSED) { send_features_reply(xid); return 0; } static int -recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED) +recv_set_config(uint32_t xid OVS_UNUSED, const void *msg OVS_UNUSED) { /* Nothing to configure! */ return 0; @@ -588,8 +593,8 @@ recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph, } static int -recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED, - size_t len UNUSED) +recv_ofmp_resources_request(uint32_t xid, const void *msg OVS_UNUSED, + size_t len OVS_UNUSED) { send_resources_update(xid, true); return 0; @@ -643,6 +648,14 @@ recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph, /* 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; } @@ -665,23 +678,48 @@ static int 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; @@ -702,6 +740,12 @@ int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len) 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)) {