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"
50 #include "xenserver.h"
53 #define THIS_MODULE VLM_mgmt
56 #define MAX_BACKOFF_DEFAULT 15
57 #define INACTIVITY_PROBE_DEFAULT 15
59 static struct svec mgmt_cfg;
60 static uint8_t cfg_cookie[CFG_COOKIE_LEN];
61 static struct rconn *mgmt_rconn;
62 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
63 static struct svec capabilities;
67 #define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */
68 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
70 static uint64_t pick_fallback_mgmt_id(void);
71 static void send_config_update(uint32_t xid, bool use_xid);
72 static void send_resources_update(uint32_t xid, bool use_xid);
77 txqlen = rconn_packet_counter_create();
80 svec_init(&capabilities);
81 svec_add_nocopy(&capabilities,
82 xasprintf("com.nicira.mgmt.manager=true\n"));
84 mgmt_id = cfg_get_dpid(0, "mgmt.id");
86 /* Randomly generate a mgmt id */
87 mgmt_id = pick_fallback_mgmt_id();
93 config_string_change(const char *key, char **valuep)
95 const char *value = cfg_get_string(0, "%s", key);
96 if (value && (!*valuep || strcmp(value, *valuep))) {
98 *valuep = xstrdup(value);
106 mgmt_configure_ssl(void)
108 static char *private_key_file;
109 static char *certificate_file;
110 static char *cacert_file;
112 /* XXX SSL should be configurable separate from the bridges.
113 * XXX should be possible to de-configure SSL. */
114 if (config_string_change("ssl.private-key", &private_key_file)) {
115 vconn_ssl_set_private_key_file(private_key_file);
118 if (config_string_change("ssl.certificate", &certificate_file)) {
119 vconn_ssl_set_certificate_file(certificate_file);
122 if (config_string_change("ssl.ca-cert", &cacert_file)) {
123 vconn_ssl_set_ca_cert_file(cacert_file,
124 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
130 mgmt_reconfigure(void)
133 uint8_t new_cookie[CFG_COOKIE_LEN];
134 bool cfg_updated = false;
135 const char *controller_name;
137 int inactivity_probe;
140 if (!cfg_has_section("mgmt")) {
142 rconn_destroy(mgmt_rconn);
148 /* If this is an established connection, send a resources update. */
149 /* xxx This is wasteful if there were no resource changes!!! */
151 send_resources_update(0, false);
154 cfg_get_cookie(new_cookie);
155 if (memcmp(cfg_cookie, new_cookie, sizeof(cfg_cookie))) {
156 memcpy(cfg_cookie, new_cookie, sizeof(cfg_cookie));
161 cfg_get_section(&new_cfg, "mgmt");
162 if (svec_equal(&mgmt_cfg, &new_cfg)) {
163 /* Reconnecting to the controller causes the config file to be
164 * resent automatically. If we're not reconnecting and the
165 * config file has changed, we need to notify the controller of
167 if (cfg_updated && mgmt_rconn) {
168 send_config_update(0, false);
170 svec_destroy(&new_cfg);
174 controller_name = cfg_get_string(0, "mgmt.controller");
175 if (!controller_name) {
176 VLOG_ERR("no controller specified for managment");
177 svec_destroy(&new_cfg);
181 max_backoff = cfg_get_int(0, "mgmt.max-backoff");
182 if (max_backoff < 1) {
183 max_backoff = MAX_BACKOFF_DEFAULT;
184 } else if (max_backoff > 3600) {
188 inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
189 if (inactivity_probe < 5) {
190 inactivity_probe = INACTIVITY_PROBE_DEFAULT;
193 /* xxx If this changes, we need to restart bridges to use new id,
194 * xxx but they need the id before the connect to controller, but we
195 * xxx need their dpids. */
196 /* Check if a different mgmt id has been assigned. */
197 if (cfg_has("mgmt.id")) {
198 uint64_t cfg_mgmt_id = cfg_get_dpid(0, "mgmt.id");
199 if (cfg_mgmt_id != mgmt_id) {
200 mgmt_id = cfg_mgmt_id;
204 svec_swap(&new_cfg, &mgmt_cfg);
205 svec_destroy(&new_cfg);
209 mgmt_configure_ssl();
213 rconn_destroy(mgmt_rconn);
216 mgmt_rconn = rconn_create(inactivity_probe, max_backoff);
217 retval = rconn_connect(mgmt_rconn, controller_name);
218 if (retval == EAFNOSUPPORT) {
219 VLOG_ERR("no support for %s vconn", controller_name);
224 send_openflow_buffer(struct ofpbuf *buffer)
229 VLOG_ERR("attempt to send openflow packet with no rconn\n");
233 update_openflow_length(buffer);
234 retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
236 VLOG_WARN_RL(&rl, "send to %s failed: %s",
237 rconn_get_name(mgmt_rconn), strerror(retval));
243 send_features_reply(uint32_t xid)
245 struct ofpbuf *buffer;
246 struct ofp_switch_features *ofr;
248 ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
249 ofr->datapath_id = 0;
252 ofr->capabilities = 0;
254 send_openflow_buffer(buffer);
258 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
259 struct ofpbuf **bufferp)
261 struct ofmp_header *oh;
263 oh = make_openflow_xid(ofmp_len, OFPT_VENDOR, xid, bufferp);
264 oh->header.vendor = htonl(NX_VENDOR_ID);
265 oh->header.subtype = htonl(NXT_MGMT);
266 oh->type = htons(type);
272 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
274 struct ofmp_header *oh;
276 oh = make_openflow(ofmp_len, OFPT_VENDOR, bufferp);
277 oh->header.vendor = htonl(NX_VENDOR_ID);
278 oh->header.subtype = htonl(NXT_MGMT);
279 oh->type = htons(type);
285 send_capability_reply(uint32_t xid)
288 struct ofpbuf *buffer;
289 struct ofmp_capability_reply *ofmpcr;
291 ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY,
293 ofmpcr->format = htonl(OFMPCOF_SIMPLE);
294 ofmpcr->mgmt_id = htonll(mgmt_id);
295 for (i=0; i<capabilities.n; i++) {
296 ofpbuf_put(buffer, capabilities.names[i],
297 strlen(capabilities.names[i]));
299 send_openflow_buffer(buffer);
303 send_resources_update(uint32_t xid, bool use_xid)
305 struct ofpbuf *buffer;
306 struct ofmp_resources_update *ofmpru;
307 struct ofmp_tlv *tlv;
309 struct svec port_list;
310 const char *host_uuid;
314 ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE,
317 ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
320 /* On XenServer systems, each host has its own UUID, which we provide
323 host_uuid = xenserver_get_host_uuid();
325 struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
327 mgmt_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*mgmt_uuid_tlv));
328 mgmt_uuid_tlv->type = htons(OFMPTSR_MGMT_UUID);
329 mgmt_uuid_tlv->len = htons(sizeof(*mgmt_uuid_tlv));
330 mgmt_uuid_tlv->mgmt_id = htonll(mgmt_id);
331 memcpy(mgmt_uuid_tlv->uuid, host_uuid, OFMP_UUID_LEN);
335 cfg_get_subsections(&br_list, "bridge");
336 for (i=0; i < br_list.n; i++) {
337 struct ofmptsr_dp *dp_tlv;
341 dp_id = bridge_get_datapathid(br_list.names[i]);
343 VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist",
347 dp_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_tlv));
348 dp_tlv->type = htons(OFMPTSR_DP);
349 dp_tlv->len = htons(sizeof(*dp_tlv));
351 dp_tlv->dp_id = htonll(dp_id);
352 memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
354 /* On XenServer systems, each network has one or more UUIDs
355 * associated with it, which we provide to the controller.
357 n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
359 struct ofmptsr_dp_uuid *dp_uuid_tlv;
360 size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
363 dp_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_uuid_tlv));
364 dp_uuid_tlv->type = htons(OFMPTSR_DP_UUID);
365 dp_uuid_tlv->len = htons(tlv_len);
366 dp_uuid_tlv->dp_id = htonll(dp_id);
368 for (j=0; j<n_uuid; j++) {
369 const char *dp_uuid = cfg_get_string(j,
370 "bridge.%s.xs-network-uuids", br_list.names[i]);
372 /* The UUID list could change underneath us, so just
373 * fill with zeros in that case. Another update will be
374 * initiated shortly, which should contain corrected data.
377 ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
379 ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
385 /* On XenServer systems, extended information about virtual interfaces
386 * (VIFs) is available, which is needed by the controller.
388 svec_init(&port_list);
389 bridge_get_ifaces(&port_list);
390 for (i=0; i < port_list.n; i++) {
391 const char *vif_uuid, *vm_uuid, *net_uuid;
393 struct ofmptsr_vif *vif_tlv;
395 vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
400 vif_tlv = ofpbuf_put_zeros(buffer, sizeof(*vif_tlv));
401 vif_tlv->type = htons(OFMPTSR_VIF);
402 vif_tlv->len = htons(sizeof(*vif_tlv));
404 memcpy(vif_tlv->name, port_list.names[i], strlen(port_list.names[i])+1);
405 memcpy(vif_tlv->vif_uuid, vif_uuid, sizeof(vif_tlv->vif_uuid));
407 vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
409 memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
411 /* In case the vif disappeared underneath us. */
412 memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
415 net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
417 memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
419 /* In case the vif disappeared underneath us. */
420 memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
423 vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
424 vif_tlv->vif_mac = htonll(vif_mac);
427 /* Put end marker. */
428 tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
429 tlv->type = htons(OFMPTSR_END);
430 tlv->len = htons(sizeof(*tlv));
431 send_openflow_buffer(buffer);
435 send_config_update(uint32_t xid, bool use_xid)
437 struct ofpbuf *buffer;
438 struct ofmp_config_update *ofmpcu;
441 ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE,
444 ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
447 ofmpcu->format = htonl(OFMPCOF_SIMPLE);
448 memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
450 send_openflow_buffer(buffer);
454 send_config_update_ack(uint32_t xid, bool success)
456 struct ofpbuf *buffer;
457 struct ofmp_config_update_ack *ofmpcua;
459 ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK,
462 ofmpcua->format = htonl(OFMPCOF_SIMPLE);
464 ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
466 cfg_get_cookie(ofmpcua->cookie);
467 send_openflow_buffer(buffer);
471 send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code,
472 const void *data, size_t len)
474 struct ofpbuf *buffer;
475 struct ofmp_error_msg *oem;
477 oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
478 oem->type = htons(type);
479 oem->code = htons(code);
480 memcpy(oem->data, data, len);
481 send_openflow_buffer(buffer);
485 send_error_msg(uint32_t xid, uint16_t type, uint16_t code,
486 const void *data, size_t len)
488 struct ofpbuf *buffer;
489 struct ofp_error_msg *oem;
491 oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
492 oem->type = htons(type);
493 oem->code = htons(code);
494 memcpy(oem->data, data, len);
495 send_openflow_buffer(buffer);
499 recv_echo_request(uint32_t xid UNUSED, const void *msg)
501 const struct ofp_header *rq = msg;
502 send_openflow_buffer(make_echo_reply(rq));
507 recv_features_request(uint32_t xid, const void *msg UNUSED)
509 send_features_reply(xid);
514 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
516 /* Nothing to configure! */
521 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph)
523 struct ofmp_capability_request *ofmpcr;
525 if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
530 ofmpcr = (struct ofmp_capability_request *)ofmph;
531 if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
536 send_capability_reply(xid);
542 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED)
544 send_resources_update(xid, true);
549 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph)
551 struct ofmp_config_request *ofmpcr;
553 if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
558 ofmpcr = (struct ofmp_config_request *)ofmph;
559 if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
564 send_config_update(xid, true);
570 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph)
572 struct ofmp_config_update *ofmpcu;
575 data_len = htons(ofmph->header.header.length) - sizeof(*ofmpcu);
576 if (data_len <= sizeof(*ofmpcu)) {
577 /* xxx Send error. */
581 ofmpcu = (struct ofmp_config_update *)ofmph;
582 if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
587 /* Check if the supplied cookie matches our current understanding of
588 * it. If they don't match, tell the controller and let it sort
590 if (cfg_lock(ofmpcu->cookie, 0)) {
591 /* xxx cfg_lock can fail for other reasons, such as being
593 VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
594 send_config_update_ack(xid, false);
598 /* xxx We should probably do more sanity checking than this. */
600 cfg_write_data(ofmpcu->data, data_len);
603 /* Send the ACK before running reconfigure, since our management
604 * connection settings may have changed. */
605 send_config_update_ack(xid, true);
614 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph)
616 /* xxx Should sanity-check for min/max length */
617 switch (ntohs(ofmph->type))
619 case OFMPT_CAPABILITY_REQUEST:
620 return recv_ofmp_capability_request(xid, ofmph);
621 case OFMPT_RESOURCES_REQUEST:
622 return recv_ofmp_resources_request(xid, ofmph);
623 case OFMPT_CONFIG_REQUEST:
624 return recv_ofmp_config_request(xid, ofmph);
625 case OFMPT_CONFIG_UPDATE:
626 return recv_ofmp_config_update(xid, ofmph);
628 VLOG_WARN_RL(&rl, "unknown mgmt message: %d",
635 recv_nx_msg(uint32_t xid, const void *oh)
637 const struct nicira_header *nh = oh;
639 switch (ntohl(nh->subtype)) {
642 return recv_ofmp(xid, (struct ofmp_header *)oh);
645 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE,
646 oh, htons(nh->header.length));
652 recv_vendor(uint32_t xid, const void *oh)
654 const struct ofp_vendor_header *ovh = oh;
656 switch (ntohl(ovh->vendor))
659 return recv_nx_msg(xid, oh);
662 VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
663 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR,
664 oh, ntohs(ovh->header.length));
670 handle_msg(uint32_t xid, const void *msg, size_t length)
672 int (*handler)(uint32_t, const void *);
673 struct ofp_header *oh;
676 COVERAGE_INC(mgmt_received);
678 /* Check encapsulated length. */
679 oh = (struct ofp_header *) msg;
680 if (ntohs(oh->length) > length) {
683 assert(oh->version == OFP_VERSION);
685 /* Figure out how to handle it. */
687 case OFPT_ECHO_REQUEST:
688 min_size = sizeof(struct ofp_header);
689 handler = recv_echo_request;
691 case OFPT_ECHO_REPLY:
693 case OFPT_FEATURES_REQUEST:
694 min_size = sizeof(struct ofp_header);
695 handler = recv_features_request;
697 case OFPT_SET_CONFIG:
698 min_size = sizeof(struct ofp_switch_config);
699 handler = recv_set_config;
702 min_size = sizeof(struct ofp_vendor_header);
703 handler = recv_vendor;
706 VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
707 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
713 if (length < min_size) {
716 return handler(xid, msg);
728 rconn_run(mgmt_rconn);
730 /* Do some processing, but cap it at a reasonable amount so that
731 * other processing doesn't starve. */
732 for (i=0; i<50; i++) {
733 struct ofpbuf *buffer;
734 struct ofp_header *oh;
736 buffer = rconn_recv(mgmt_rconn);
741 if (buffer->size >= sizeof *oh) {
743 handle_msg(oh->xid, buffer->data, buffer->size);
744 ofpbuf_delete(buffer);
746 VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
758 rconn_run_wait(mgmt_rconn);
759 rconn_recv_wait(mgmt_rconn);
763 pick_fallback_mgmt_id(void)
765 uint8_t ea[ETH_ADDR_LEN];
767 ea[0] = 0x00; /* Set Nicira OUI. */
770 return eth_addr_to_uint64(ea);