1 /* Copyright (c) 2009 Nicira Networks
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 #include <arpa/inet.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
31 #include "openflow/nicira-ext.h"
32 #include "openflow/openflow.h"
33 #include "openflow/openflow-mgmt.h"
35 #include "ovs-vswitchd.h"
40 #include "vconn-ssl.h"
41 #include "xenserver.h"
44 #define THIS_MODULE VLM_mgmt
47 #define MAX_BACKOFF_DEFAULT 15
48 #define INACTIVITY_PROBE_DEFAULT 15
50 static struct svec mgmt_cfg;
51 static uint8_t cfg_cookie[CFG_COOKIE_LEN];
52 static bool need_reconfigure = false;
53 static struct rconn *mgmt_rconn;
54 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
55 static struct svec capabilities;
56 static struct ofpbuf ext_data_buffer;
57 static uint32_t ext_data_xid = UINT32_MAX;
61 #define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */
62 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
64 static uint64_t pick_fallback_mgmt_id(void);
65 static void send_config_update(uint32_t xid, bool use_xid);
66 static void send_resources_update(uint32_t xid, bool use_xid);
67 static int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len);
72 txqlen = rconn_packet_counter_create();
75 svec_init(&capabilities);
76 svec_add_nocopy(&capabilities,
77 xasprintf("com.nicira.mgmt.manager=true\n"));
79 mgmt_id = cfg_get_dpid(0, "mgmt.id");
81 /* Randomly generate a mgmt id */
82 mgmt_id = pick_fallback_mgmt_id();
85 ofpbuf_init(&ext_data_buffer, 0);
90 config_string_change(const char *key, char **valuep)
92 const char *value = cfg_get_string(0, "%s", key);
93 if (value && (!*valuep || strcmp(value, *valuep))) {
95 *valuep = xstrdup(value);
103 mgmt_configure_ssl(void)
105 static char *private_key_file;
106 static char *certificate_file;
107 static char *cacert_file;
110 /* XXX SSL should be configurable separate from the bridges.
111 * XXX should be possible to de-configure SSL. */
112 if (config_string_change("ssl.private-key", &private_key_file)) {
113 vconn_ssl_set_private_key_file(private_key_file);
116 if (config_string_change("ssl.certificate", &certificate_file)) {
117 vconn_ssl_set_certificate_file(certificate_file);
120 /* We assume that even if the filename hasn't changed, if the CA cert
121 * file has been removed, that we want to move back into
122 * boot-strapping mode. This opens a small security hole, because
123 * the old certificate will still be trusted until vSwitch is
124 * restarted. We may want to address this in vconn's SSL library. */
125 if (config_string_change("ssl.ca-cert", &cacert_file)
126 || (stat(cacert_file, &s) && errno == ENOENT)) {
127 vconn_ssl_set_ca_cert_file(cacert_file,
128 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
134 mgmt_reconfigure(void)
137 uint8_t new_cookie[CFG_COOKIE_LEN];
138 bool cfg_updated = false;
139 const char *controller_name;
141 int inactivity_probe;
144 if (!cfg_has_section("mgmt")) {
145 svec_clear(&mgmt_cfg);
147 rconn_destroy(mgmt_rconn);
153 /* If this is an established connection, send a resources update. */
154 /* xxx This is wasteful if there were no resource changes!!! */
156 send_resources_update(0, false);
159 cfg_get_cookie(new_cookie);
160 if (memcmp(cfg_cookie, new_cookie, sizeof(cfg_cookie))) {
161 memcpy(cfg_cookie, new_cookie, sizeof(cfg_cookie));
166 cfg_get_section(&new_cfg, "mgmt");
167 if (svec_equal(&mgmt_cfg, &new_cfg)) {
168 /* Reconnecting to the controller causes the config file to be
169 * resent automatically. If we're not reconnecting and the
170 * config file has changed, we need to notify the controller of
172 if (cfg_updated && mgmt_rconn) {
173 send_config_update(0, false);
175 svec_destroy(&new_cfg);
179 controller_name = cfg_get_string(0, "mgmt.controller");
180 if (!controller_name) {
181 VLOG_ERR("no controller specified for managment");
182 svec_destroy(&new_cfg);
186 max_backoff = cfg_get_int(0, "mgmt.max-backoff");
187 if (max_backoff < 1) {
188 max_backoff = MAX_BACKOFF_DEFAULT;
189 } else if (max_backoff > 3600) {
193 inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
194 if (inactivity_probe < 5) {
195 inactivity_probe = INACTIVITY_PROBE_DEFAULT;
198 /* xxx If this changes, we need to restart bridges to use new id,
199 * xxx but they need the id before the connect to controller, but we
200 * xxx need their dpids. */
201 /* Check if a different mgmt id has been assigned. */
202 if (cfg_has("mgmt.id")) {
203 uint64_t cfg_mgmt_id = cfg_get_dpid(0, "mgmt.id");
204 if (cfg_mgmt_id != mgmt_id) {
205 mgmt_id = cfg_mgmt_id;
209 svec_swap(&new_cfg, &mgmt_cfg);
210 svec_destroy(&new_cfg);
214 mgmt_configure_ssl();
218 rconn_destroy(mgmt_rconn);
221 mgmt_rconn = rconn_create(inactivity_probe, max_backoff);
222 retval = rconn_connect(mgmt_rconn, controller_name);
223 if (retval == EAFNOSUPPORT) {
224 VLOG_ERR("no support for %s vconn", controller_name);
227 /* Reset the extended message buffer when we create a new
228 * management connection. */
229 ofpbuf_clear(&ext_data_buffer);
233 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
234 struct ofpbuf **bufferp)
236 struct ofmp_header *oh;
238 oh = make_openflow_xid(ofmp_len, OFPT_VENDOR, xid, bufferp);
239 oh->header.vendor = htonl(NX_VENDOR_ID);
240 oh->header.subtype = htonl(NXT_MGMT);
241 oh->type = htons(type);
247 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
249 struct ofmp_header *oh;
251 oh = make_openflow(ofmp_len, OFPT_VENDOR, bufferp);
252 oh->header.vendor = htonl(NX_VENDOR_ID);
253 oh->header.subtype = htonl(NXT_MGMT);
254 oh->type = htons(type);
260 send_openflow_buffer(struct ofpbuf *buffer)
265 VLOG_ERR("attempt to send openflow packet with no rconn\n");
269 /* Make sure there's room to transmit the data. We don't want to
270 * fail part way through a send. */
271 if (rconn_packet_counter_read(txqlen) >= TXQ_LIMIT) {
275 /* OpenFlow messages use a 16-bit length field, so messages over 64K
276 * must be broken into multiple pieces.
278 if (buffer->size <= 65535) {
279 update_openflow_length(buffer);
280 retval = rconn_send(mgmt_rconn, buffer, txqlen);
282 VLOG_WARN_RL(&rl, "send to %s failed: %s",
283 rconn_get_name(mgmt_rconn), strerror(retval));
287 struct ofmp_header *header = (struct ofmp_header *)buffer->data;
288 uint32_t xid = header->header.header.xid;
289 size_t remain = buffer->size;
290 uint8_t *ptr = buffer->data;
292 /* Mark the OpenFlow header with a zero length to indicate some
295 header->header.header.length = 0;
298 struct ofpbuf *new_buffer;
299 struct ofmp_extended_data *oed;
300 size_t new_len = MIN(65535 - sizeof *oed, remain);
302 oed = make_ofmp_xid(sizeof *oed, OFMPT_EXTENDED_DATA, xid,
304 oed->type = header->type;
306 if (remain > new_len) {
307 oed->flags |= OFMPEDF_MORE_DATA;
310 /* Copy the entire original message, including the OpenFlow
311 * header, since management protocol structure definitions
312 * include these headers.
314 ofpbuf_put(new_buffer, ptr, new_len);
316 update_openflow_length(new_buffer);
317 retval = rconn_send(mgmt_rconn, new_buffer, txqlen);
319 VLOG_WARN_RL(&rl, "send to %s failed: %s",
320 rconn_get_name(mgmt_rconn), strerror(retval));
321 ofpbuf_delete(buffer);
329 ofpbuf_delete(buffer);
335 send_features_reply(uint32_t xid)
337 struct ofpbuf *buffer;
338 struct ofp_switch_features *ofr;
340 ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
341 ofr->datapath_id = 0;
344 ofr->capabilities = 0;
346 send_openflow_buffer(buffer);
350 send_capability_reply(uint32_t xid)
353 struct ofpbuf *buffer;
354 struct ofmp_capability_reply *ofmpcr;
356 ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY,
358 ofmpcr->format = htonl(OFMPCOF_SIMPLE);
359 ofmpcr->mgmt_id = htonll(mgmt_id);
360 for (i=0; i<capabilities.n; i++) {
361 ofpbuf_put(buffer, capabilities.names[i],
362 strlen(capabilities.names[i]));
364 send_openflow_buffer(buffer);
368 send_resources_update(uint32_t xid, bool use_xid)
370 struct ofpbuf *buffer;
371 struct ofmp_resources_update *ofmpru;
372 struct ofmp_tlv *tlv;
374 struct svec port_list;
375 const char *host_uuid;
379 ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE,
382 ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
385 /* On XenServer systems, each host has its own UUID, which we provide
388 host_uuid = xenserver_get_host_uuid();
390 struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
392 mgmt_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*mgmt_uuid_tlv));
393 mgmt_uuid_tlv->type = htons(OFMPTSR_MGMT_UUID);
394 mgmt_uuid_tlv->len = htons(sizeof(*mgmt_uuid_tlv));
395 mgmt_uuid_tlv->mgmt_id = htonll(mgmt_id);
396 memcpy(mgmt_uuid_tlv->uuid, host_uuid, OFMP_UUID_LEN);
400 cfg_get_subsections(&br_list, "bridge");
401 for (i=0; i < br_list.n; i++) {
402 struct ofmptsr_dp *dp_tlv;
406 dp_id = bridge_get_datapathid(br_list.names[i]);
408 VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist",
412 dp_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_tlv));
413 dp_tlv->type = htons(OFMPTSR_DP);
414 dp_tlv->len = htons(sizeof(*dp_tlv));
416 dp_tlv->dp_id = htonll(dp_id);
417 memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
419 /* On XenServer systems, each network has one or more UUIDs
420 * associated with it, which we provide to the controller.
422 n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
424 struct ofmptsr_dp_uuid *dp_uuid_tlv;
425 size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
428 dp_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_uuid_tlv));
429 dp_uuid_tlv->type = htons(OFMPTSR_DP_UUID);
430 dp_uuid_tlv->len = htons(tlv_len);
431 dp_uuid_tlv->dp_id = htonll(dp_id);
433 for (j=0; j<n_uuid; j++) {
434 const char *dp_uuid = cfg_get_string(j,
435 "bridge.%s.xs-network-uuids", br_list.names[i]);
437 /* The UUID list could change underneath us, so just
438 * fill with zeros in that case. Another update will be
439 * initiated shortly, which should contain corrected data.
442 ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
444 ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
449 svec_destroy(&br_list);
451 /* On XenServer systems, extended information about virtual interfaces
452 * (VIFs) is available, which is needed by the controller.
454 svec_init(&port_list);
455 bridge_get_ifaces(&port_list);
456 for (i=0; i < port_list.n; i++) {
457 const char *vif_uuid, *vm_uuid, *net_uuid;
459 struct ofmptsr_vif *vif_tlv;
461 vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
466 vif_tlv = ofpbuf_put_zeros(buffer, sizeof(*vif_tlv));
467 vif_tlv->type = htons(OFMPTSR_VIF);
468 vif_tlv->len = htons(sizeof(*vif_tlv));
470 memcpy(vif_tlv->name, port_list.names[i], strlen(port_list.names[i])+1);
471 memcpy(vif_tlv->vif_uuid, vif_uuid, sizeof(vif_tlv->vif_uuid));
473 vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
475 memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
477 /* In case the vif disappeared underneath us. */
478 memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
481 net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
483 memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
485 /* In case the vif disappeared underneath us. */
486 memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
489 vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
490 vif_tlv->vif_mac = htonll(vif_mac);
492 svec_destroy(&port_list);
494 /* Put end marker. */
495 tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
496 tlv->type = htons(OFMPTSR_END);
497 tlv->len = htons(sizeof(*tlv));
498 send_openflow_buffer(buffer);
502 send_config_update(uint32_t xid, bool use_xid)
504 struct ofpbuf *buffer;
505 struct ofmp_config_update *ofmpcu;
508 ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE,
511 ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
514 ofmpcu->format = htonl(OFMPCOF_SIMPLE);
515 memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
517 send_openflow_buffer(buffer);
521 send_config_update_ack(uint32_t xid, bool success)
523 struct ofpbuf *buffer;
524 struct ofmp_config_update_ack *ofmpcua;
526 ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK,
529 ofmpcua->format = htonl(OFMPCOF_SIMPLE);
531 ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
533 cfg_get_cookie(ofmpcua->cookie);
534 send_openflow_buffer(buffer);
538 send_error_msg(uint32_t xid, uint16_t type, uint16_t code,
539 const void *data, size_t len)
541 struct ofpbuf *buffer;
542 struct ofp_error_msg *oem;
544 oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
545 oem->type = htons(type);
546 oem->code = htons(code);
547 memcpy(oem->data, data, len);
548 send_openflow_buffer(buffer);
552 recv_echo_request(uint32_t xid UNUSED, const void *msg)
554 const struct ofp_header *rq = msg;
555 send_openflow_buffer(make_echo_reply(rq));
560 recv_features_request(uint32_t xid, const void *msg UNUSED)
562 send_features_reply(xid);
567 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
569 /* Nothing to configure! */
574 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph,
577 struct ofmp_capability_request *ofmpcr;
579 if (len != sizeof(*ofmpcr)) {
584 ofmpcr = (struct ofmp_capability_request *)ofmph;
585 if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
590 send_capability_reply(xid);
596 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED,
599 send_resources_update(xid, true);
604 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph,
607 struct ofmp_config_request *ofmpcr;
609 if (len != sizeof(*ofmpcr)) {
614 ofmpcr = (struct ofmp_config_request *)ofmph;
615 if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
620 send_config_update(xid, true);
626 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph,
629 struct ofmp_config_update *ofmpcu;
632 data_len = len - sizeof(*ofmpcu);
633 if (data_len <= sizeof(*ofmpcu)) {
634 /* xxx Send error. */
638 ofmpcu = (struct ofmp_config_update *)ofmph;
639 if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
644 /* Check if the supplied cookie matches our current understanding of
645 * it. If they don't match, tell the controller and let it sort
647 if (cfg_lock(ofmpcu->cookie, 0)) {
648 /* xxx cfg_lock can fail for other reasons, such as being
650 VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
652 /* Check if our local view matches the controller, in which
653 * case, it is likely that there were local modifications
654 * without our being told to reread the config file. */
655 if (!memcmp(cfg_cookie, ofmpcu->cookie, sizeof cfg_cookie)) {
656 VLOG_WARN_RL(&rl, "config appears to have been locally modified "
657 "without having told ovs-vswitchd to reload");
659 send_config_update_ack(xid, false);
663 /* xxx We should probably do more sanity checking than this. */
665 cfg_write_data(ofmpcu->data, data_len);
668 /* Send the ACK before running reconfigure, since our management
669 * connection settings may have changed. */
670 send_config_update_ack(xid, true);
672 need_reconfigure = true;
678 recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
682 struct ofmp_extended_data *ofmped;
684 if (len <= sizeof(*ofmped)) {
685 /* xxx Send error. */
690 ofmped = (struct ofmp_extended_data *)ofmph;
692 data_len = len - sizeof(*ofmped);
693 ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
695 if (!(ofmped->flags & OFMPEDF_MORE_DATA)) {
696 struct ofmp_header *new_oh;
699 /* An embedded message must be greater than the size of an
700 * OpenFlow message. */
701 new_oh = ofpbuf_at(&ext_data_buffer, 0, 65536);
703 VLOG_WARN_RL(&rl, "received short embedded message: %d\n",
704 ext_data_buffer.size);
708 /* Make sure that this is a management message and that there's
709 * not an embedded extended data message. */
710 if ((new_oh->header.vendor != htonl(NX_VENDOR_ID))
711 || (new_oh->header.subtype != htonl(NXT_MGMT))
712 || (new_oh->type == htonl(OFMPT_EXTENDED_DATA))) {
713 VLOG_WARN_RL(&rl, "received bad embedded message\n");
716 new_oh->header.header.xid = ext_data_xid;
717 new_oh->header.header.length = 0;
719 error = recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
720 ofpbuf_clear(&ext_data_buffer);
728 /* Handles receiving a management message. Generally, this function
729 * will be called 'len' set to zero, and the length will be derived by
730 * the OpenFlow header. With the extended data message, management
731 * messages are not constrained by OpenFlow's 64K message length limit.
732 * The extended data handler calls this function with the 'len' set to
733 * the total message length and the OpenFlow header's length field is
737 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len)
740 len = ntohs(ofmph->header.header.length);
743 /* Reset the extended data buffer if this isn't a continuation of an
744 * existing extended data message. */
745 if (ext_data_xid != xid) {
746 ofpbuf_clear(&ext_data_buffer);
749 /* xxx Should sanity-check for min/max length */
750 switch (ntohs(ofmph->type))
752 case OFMPT_CAPABILITY_REQUEST:
753 return recv_ofmp_capability_request(xid, ofmph, len);
754 case OFMPT_RESOURCES_REQUEST:
755 return recv_ofmp_resources_request(xid, ofmph, len);
756 case OFMPT_CONFIG_REQUEST:
757 return recv_ofmp_config_request(xid, ofmph, len);
758 case OFMPT_CONFIG_UPDATE:
759 return recv_ofmp_config_update(xid, ofmph, len);
760 case OFMPT_EXTENDED_DATA:
761 return recv_ofmp_extended_data(xid, ofmph, len);
763 VLOG_WARN_RL(&rl, "unknown mgmt message: %d",
770 recv_nx_msg(uint32_t xid, const void *oh)
772 const struct nicira_header *nh = oh;
774 switch (ntohl(nh->subtype)) {
777 return recv_ofmp(xid, (struct ofmp_header *)oh, 0);
780 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE,
781 oh, ntohs(nh->header.length));
787 recv_vendor(uint32_t xid, const void *oh)
789 const struct ofp_vendor_header *ovh = oh;
791 switch (ntohl(ovh->vendor))
794 return recv_nx_msg(xid, oh);
797 VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
798 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR,
799 oh, ntohs(ovh->header.length));
805 handle_msg(uint32_t xid, const void *msg, size_t length)
807 int (*handler)(uint32_t, const void *);
808 struct ofp_header *oh;
811 COVERAGE_INC(mgmt_received);
813 /* Check encapsulated length. */
814 oh = (struct ofp_header *) msg;
815 if (ntohs(oh->length) > length) {
818 assert(oh->version == OFP_VERSION);
820 /* Figure out how to handle it. */
822 case OFPT_ECHO_REQUEST:
823 min_size = sizeof(struct ofp_header);
824 handler = recv_echo_request;
826 case OFPT_ECHO_REPLY:
828 case OFPT_FEATURES_REQUEST:
829 min_size = sizeof(struct ofp_header);
830 handler = recv_features_request;
832 case OFPT_SET_CONFIG:
833 min_size = sizeof(struct ofp_switch_config);
834 handler = recv_set_config;
837 min_size = sizeof(struct ofp_vendor_header);
838 handler = recv_vendor;
841 VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
842 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
848 if (length < min_size) {
851 return handler(xid, msg);
863 need_reconfigure = false;
864 rconn_run(mgmt_rconn);
866 /* Do some processing, but cap it at a reasonable amount so that
867 * other processing doesn't starve. */
868 for (i=0; i<50; i++) {
869 struct ofpbuf *buffer;
870 struct ofp_header *oh;
872 buffer = rconn_recv(mgmt_rconn);
877 if (buffer->size >= sizeof *oh) {
879 handle_msg(oh->xid, buffer->data, buffer->size);
880 ofpbuf_delete(buffer);
882 VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
886 return need_reconfigure;
896 rconn_run_wait(mgmt_rconn);
897 rconn_recv_wait(mgmt_rconn);
901 pick_fallback_mgmt_id(void)
903 uint8_t ea[ETH_ADDR_LEN];
905 ea[0] = 0x00; /* Set Nicira OUI. */
908 return eth_addr_to_uint64(ea);