1 /* Copyright (c) 2009 Nicira Networks
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 * In addition, as a special exception, Nicira Networks gives permission
17 * to link the code of its release of vswitchd with the OpenSSL project's
18 * "OpenSSL" library (or with modified versions of it that use the same
19 * license as the "OpenSSL" library), and distribute the linked
20 * executables. You must obey the GNU General Public License in all
21 * respects for all of the code used other than "OpenSSL". If you modify
22 * this file, you may extend this exception to your version of the file,
23 * but you are not obligated to do so. If you do not wish to do so,
24 * delete this exception statement from your version.
30 #include <arpa/inet.h>
40 #include "openflow/nicira-ext.h"
41 #include "openflow/openflow.h"
42 #include "openflow/openflow-mgmt.h"
44 #include "ovs-vswitchd.h"
49 #include "vconn-ssl.h"
52 #define THIS_MODULE VLM_mgmt
55 #define MAX_BACKOFF_DEFAULT 15
56 #define INACTIVITY_PROBE_DEFAULT 15
58 static struct svec mgmt_cfg;
59 static uint8_t cfg_cookie[CFG_COOKIE_LEN];
60 static struct rconn *mgmt_rconn;
61 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
62 static struct svec capabilities;
66 #define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */
67 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
69 static uint64_t pick_fallback_mgmt_id(void);
70 static void send_config_update(uint32_t xid, bool use_xid);
71 static void send_resources_update(uint32_t xid, bool use_xid);
76 txqlen = rconn_packet_counter_create();
79 svec_init(&capabilities);
80 svec_add_nocopy(&capabilities,
81 xasprintf("com.nicira.mgmt.manager=true\n"));
83 mgmt_id = cfg_get_dpid(0, "mgmt.id");
85 /* Randomly generate a mgmt id */
86 mgmt_id = pick_fallback_mgmt_id();
92 config_string_change(const char *key, char **valuep)
94 const char *value = cfg_get_string(0, "%s", key);
95 if (value && (!*valuep || strcmp(value, *valuep))) {
97 *valuep = xstrdup(value);
105 mgmt_configure_ssl(void)
107 static char *private_key_file;
108 static char *certificate_file;
109 static char *cacert_file;
111 /* XXX SSL should be configurable separate from the bridges.
112 * XXX should be possible to de-configure SSL. */
113 if (config_string_change("ssl.private-key", &private_key_file)) {
114 vconn_ssl_set_private_key_file(private_key_file);
117 if (config_string_change("ssl.certificate", &certificate_file)) {
118 vconn_ssl_set_certificate_file(certificate_file);
121 if (config_string_change("ssl.ca-cert", &cacert_file)) {
122 vconn_ssl_set_ca_cert_file(cacert_file,
123 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
129 mgmt_reconfigure(void)
132 uint8_t new_cookie[CFG_COOKIE_LEN];
133 bool cfg_updated = false;
134 const char *controller_name;
136 int inactivity_probe;
139 if (!cfg_has_section("mgmt")) {
141 rconn_destroy(mgmt_rconn);
147 /* If this is an established connection, send a resources update. */
148 /* xxx This is wasteful if there were no resource changes!!! */
150 send_resources_update(0, false);
153 cfg_get_cookie(new_cookie);
154 if (memcmp(cfg_cookie, new_cookie, sizeof(cfg_cookie))) {
155 memcpy(cfg_cookie, new_cookie, sizeof(cfg_cookie));
160 cfg_get_section(&new_cfg, "mgmt");
161 if (svec_equal(&mgmt_cfg, &new_cfg)) {
162 /* Reconnecting to the controller causes the config file to be
163 * resent automatically. If we're not reconnecting and the
164 * config file has changed, we need to notify the controller of
166 if (cfg_updated && mgmt_rconn) {
167 send_config_update(0, false);
169 svec_destroy(&new_cfg);
173 controller_name = cfg_get_string(0, "mgmt.controller");
174 if (!controller_name) {
175 VLOG_ERR("no controller specified for managment");
176 svec_destroy(&new_cfg);
180 max_backoff = cfg_get_int(0, "mgmt.max-backoff");
181 if (max_backoff < 1) {
182 max_backoff = MAX_BACKOFF_DEFAULT;
183 } else if (max_backoff > 3600) {
187 inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
188 if (inactivity_probe < 5) {
189 inactivity_probe = INACTIVITY_PROBE_DEFAULT;
192 /* xxx If this changes, we need to restart bridges to use new id,
193 * xxx but they need the id before the connect to controller, but we
194 * xxx need their dpids. */
195 /* Check if a different mgmt id has been assigned. */
196 if (cfg_has("mgmt.id")) {
197 uint64_t cfg_mgmt_id = cfg_get_dpid(0, "mgmt.id");
198 if (cfg_mgmt_id != mgmt_id) {
199 mgmt_id = cfg_mgmt_id;
203 svec_swap(&new_cfg, &mgmt_cfg);
204 svec_destroy(&new_cfg);
208 mgmt_configure_ssl();
212 rconn_destroy(mgmt_rconn);
215 mgmt_rconn = rconn_create(inactivity_probe, max_backoff);
216 retval = rconn_connect(mgmt_rconn, controller_name);
217 if (retval == EAFNOSUPPORT) {
218 VLOG_ERR("no support for %s vconn", controller_name);
223 send_openflow_buffer(struct ofpbuf *buffer)
228 VLOG_ERR("attempt to send openflow packet with no rconn\n");
232 update_openflow_length(buffer);
233 retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
235 VLOG_WARN_RL(&rl, "send to %s failed: %s",
236 rconn_get_name(mgmt_rconn), strerror(retval));
242 send_features_reply(uint32_t xid)
244 struct ofpbuf *buffer;
245 struct ofp_switch_features *ofr;
247 ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
248 ofr->datapath_id = 0;
251 ofr->capabilities = 0;
253 send_openflow_buffer(buffer);
257 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
258 struct ofpbuf **bufferp)
260 struct ofmp_header *oh;
262 oh = make_openflow_xid(ofmp_len, OFPT_VENDOR, xid, bufferp);
263 oh->header.vendor = htonl(NX_VENDOR_ID);
264 oh->header.subtype = htonl(NXT_MGMT);
265 oh->type = htons(type);
271 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
273 struct ofmp_header *oh;
275 oh = make_openflow(ofmp_len, OFPT_VENDOR, bufferp);
276 oh->header.vendor = htonl(NX_VENDOR_ID);
277 oh->header.subtype = htonl(NXT_MGMT);
278 oh->type = htons(type);
284 send_capability_reply(uint32_t xid)
287 struct ofpbuf *buffer;
288 struct ofmp_capability_reply *ofmpcr;
290 ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY,
292 ofmpcr->format = htonl(OFMPCOF_SIMPLE);
293 ofmpcr->mgmt_id = htonll(mgmt_id);
294 for (i=0; i<capabilities.n; i++) {
295 ofpbuf_put(buffer, capabilities.names[i],
296 strlen(capabilities.names[i]));
298 send_openflow_buffer(buffer);
302 send_resources_update(uint32_t xid, bool use_xid)
304 struct ofpbuf *buffer;
305 struct ofmp_resources_update *ofmpru;
306 struct ofmp_tlv *tlv;
311 ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE,
314 ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
318 cfg_get_subsections(&br_list, "bridge");
319 for (i=0; i < br_list.n; i++) {
320 struct ofmptsr_dp *dp_tlv;
321 uint64_t dp_id = bridge_get_datapathid(br_list.names[i]);
323 VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist",
327 dp_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_tlv));
328 dp_tlv->type = htons(OFMPTSR_DP);
329 dp_tlv->len = htons(sizeof(*dp_tlv));
331 dp_tlv->dp_id = htonll(dp_id);
332 memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
335 /* Put end marker. */
336 tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
337 tlv->type = htons(OFMPTSR_END);
338 tlv->len = htons(sizeof(*tlv));
339 send_openflow_buffer(buffer);
343 send_config_update(uint32_t xid, bool use_xid)
345 struct ofpbuf *buffer;
346 struct ofmp_config_update *ofmpcu;
349 ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE,
352 ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
355 ofmpcu->format = htonl(OFMPCOF_SIMPLE);
356 memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
358 send_openflow_buffer(buffer);
362 send_config_update_ack(uint32_t xid, bool success)
364 struct ofpbuf *buffer;
365 struct ofmp_config_update_ack *ofmpcua;
367 ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK,
370 ofmpcua->format = htonl(OFMPCOF_SIMPLE);
372 ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
374 cfg_get_cookie(ofmpcua->cookie);
375 send_openflow_buffer(buffer);
379 send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code,
380 const void *data, size_t len)
382 struct ofpbuf *buffer;
383 struct ofmp_error_msg *oem;
385 oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
386 oem->type = htons(type);
387 oem->code = htons(code);
388 memcpy(oem->data, data, len);
389 send_openflow_buffer(buffer);
393 send_error_msg(uint32_t xid, uint16_t type, uint16_t code,
394 const void *data, size_t len)
396 struct ofpbuf *buffer;
397 struct ofp_error_msg *oem;
399 oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
400 oem->type = htons(type);
401 oem->code = htons(code);
402 memcpy(oem->data, data, len);
403 send_openflow_buffer(buffer);
407 recv_echo_request(uint32_t xid UNUSED, const void *msg)
409 const struct ofp_header *rq = msg;
410 send_openflow_buffer(make_echo_reply(rq));
415 recv_features_request(uint32_t xid, const void *msg UNUSED)
417 send_features_reply(xid);
422 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
424 /* Nothing to configure! */
429 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph)
431 struct ofmp_capability_request *ofmpcr;
433 if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
438 ofmpcr = (struct ofmp_capability_request *)ofmph;
439 if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
444 send_capability_reply(xid);
450 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED)
452 send_resources_update(xid, true);
457 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph)
459 struct ofmp_config_request *ofmpcr;
461 if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
466 ofmpcr = (struct ofmp_config_request *)ofmph;
467 if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
472 send_config_update(xid, true);
478 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph)
480 struct ofmp_config_update *ofmpcu;
483 data_len = htons(ofmph->header.header.length) - sizeof(*ofmpcu);
484 if (data_len <= sizeof(*ofmpcu)) {
485 /* xxx Send error. */
489 ofmpcu = (struct ofmp_config_update *)ofmph;
490 if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
495 /* Check if the supplied cookie matches our current understanding of
496 * it. If they don't match, tell the controller and let it sort
498 if (cfg_lock(ofmpcu->cookie, 0)) {
499 /* xxx cfg_lock can fail for other reasons, such as being
501 VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
502 send_config_update_ack(xid, false);
506 /* xxx We should probably do more sanity checking than this. */
508 cfg_write_data(ofmpcu->data, data_len);
511 /* Send the ACK before running reconfigure, since our management
512 * connection settings may have changed. */
513 send_config_update_ack(xid, true);
522 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph)
524 /* xxx Should sanity-check for min/max length */
525 switch (ntohs(ofmph->type))
527 case OFMPT_CAPABILITY_REQUEST:
528 return recv_ofmp_capability_request(xid, ofmph);
529 case OFMPT_RESOURCES_REQUEST:
530 return recv_ofmp_resources_request(xid, ofmph);
531 case OFMPT_CONFIG_REQUEST:
532 return recv_ofmp_config_request(xid, ofmph);
533 case OFMPT_CONFIG_UPDATE:
534 return recv_ofmp_config_update(xid, ofmph);
536 VLOG_WARN_RL(&rl, "unknown mgmt message: %d",
543 recv_nx_msg(uint32_t xid, const void *oh)
545 const struct nicira_header *nh = oh;
547 switch (ntohl(nh->subtype)) {
550 return recv_ofmp(xid, (struct ofmp_header *)oh);
553 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE,
554 oh, htons(nh->header.length));
560 recv_vendor(uint32_t xid, const void *oh)
562 const struct ofp_vendor_header *ovh = oh;
564 switch (ntohl(ovh->vendor))
567 return recv_nx_msg(xid, oh);
570 VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
571 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR,
572 oh, ntohs(ovh->header.length));
578 handle_msg(uint32_t xid, const void *msg, size_t length)
580 int (*handler)(uint32_t, const void *);
581 struct ofp_header *oh;
584 COVERAGE_INC(mgmt_received);
586 /* Check encapsulated length. */
587 oh = (struct ofp_header *) msg;
588 if (ntohs(oh->length) > length) {
591 assert(oh->version == OFP_VERSION);
593 /* Figure out how to handle it. */
595 case OFPT_ECHO_REQUEST:
596 min_size = sizeof(struct ofp_header);
597 handler = recv_echo_request;
599 case OFPT_ECHO_REPLY:
601 case OFPT_FEATURES_REQUEST:
602 min_size = sizeof(struct ofp_header);
603 handler = recv_features_request;
605 case OFPT_SET_CONFIG:
606 min_size = sizeof(struct ofp_switch_config);
607 handler = recv_set_config;
610 min_size = sizeof(struct ofp_vendor_header);
611 handler = recv_vendor;
614 VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
615 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
621 if (length < min_size) {
624 return handler(xid, msg);
636 rconn_run(mgmt_rconn);
638 /* Do some processing, but cap it at a reasonable amount so that
639 * other processing doesn't starve. */
640 for (i=0; i<50; i++) {
641 struct ofpbuf *buffer;
642 struct ofp_header *oh;
644 buffer = rconn_recv(mgmt_rconn);
649 if (buffer->size >= sizeof *oh) {
651 handle_msg(oh->xid, buffer->data, buffer->size);
652 ofpbuf_delete(buffer);
654 VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
666 rconn_run_wait(mgmt_rconn);
667 rconn_recv_wait(mgmt_rconn);
671 pick_fallback_mgmt_id(void)
673 uint8_t ea[ETH_ADDR_LEN];
675 ea[0] = 0x00; /* Set Nicira OUI. */
678 return eth_addr_to_uint64(ea);