]>
git.proxmox.com Git - mirror_ovs.git/blob - vswitchd/mgmt.c
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
;
60 #define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */
61 struct rconn_packet_counter
*txqlen
; /* # pkts queued for tx on mgmt_rconn. */
63 static uint64_t pick_fallback_mgmt_id(void);
64 static void send_config_update(uint32_t xid
, bool use_xid
);
65 static void send_resources_update(uint32_t xid
, bool use_xid
);
66 static int recv_ofmp(uint32_t xid
, struct ofmp_header
*ofmph
, size_t len
);
71 txqlen
= rconn_packet_counter_create();
74 svec_init(&capabilities
);
75 svec_add_nocopy(&capabilities
,
76 xasprintf("com.nicira.mgmt.manager=true\n"));
78 mgmt_id
= cfg_get_dpid(0, "mgmt.id");
80 /* Randomly generate a mgmt id */
81 mgmt_id
= pick_fallback_mgmt_id();
84 ofpbuf_init(&ext_data_buffer
, 0);
89 config_string_change(const char *key
, char **valuep
)
91 const char *value
= cfg_get_string(0, "%s", key
);
92 if (value
&& (!*valuep
|| strcmp(value
, *valuep
))) {
94 *valuep
= xstrdup(value
);
102 mgmt_configure_ssl(void)
104 static char *private_key_file
;
105 static char *certificate_file
;
106 static char *cacert_file
;
109 /* XXX SSL should be configurable separate from the bridges.
110 * XXX should be possible to de-configure SSL. */
111 if (config_string_change("ssl.private-key", &private_key_file
)) {
112 vconn_ssl_set_private_key_file(private_key_file
);
115 if (config_string_change("ssl.certificate", &certificate_file
)) {
116 vconn_ssl_set_certificate_file(certificate_file
);
119 /* We assume that even if the filename hasn't changed, if the CA cert
120 * file has been removed, that we want to move back into
121 * boot-strapping mode. This opens a small security hole, because
122 * the old certificate will still be trusted until vSwitch is
123 * restarted. We may want to address this in vconn's SSL library. */
124 if (config_string_change("ssl.ca-cert", &cacert_file
)
125 || (stat(cacert_file
, &s
) && errno
== ENOENT
)) {
126 vconn_ssl_set_ca_cert_file(cacert_file
,
127 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
133 mgmt_reconfigure(void)
136 uint8_t new_cookie
[CFG_COOKIE_LEN
];
137 bool cfg_updated
= false;
138 const char *controller_name
;
140 int inactivity_probe
;
143 if (!cfg_has_section("mgmt")) {
144 svec_clear(&mgmt_cfg
);
146 rconn_destroy(mgmt_rconn
);
152 /* If this is an established connection, send a resources update. */
153 /* xxx This is wasteful if there were no resource changes!!! */
155 send_resources_update(0, false);
158 cfg_get_cookie(new_cookie
);
159 if (memcmp(cfg_cookie
, new_cookie
, sizeof(cfg_cookie
))) {
160 memcpy(cfg_cookie
, new_cookie
, sizeof(cfg_cookie
));
165 cfg_get_section(&new_cfg
, "mgmt");
166 if (svec_equal(&mgmt_cfg
, &new_cfg
)) {
167 /* Reconnecting to the controller causes the config file to be
168 * resent automatically. If we're not reconnecting and the
169 * config file has changed, we need to notify the controller of
171 if (cfg_updated
&& mgmt_rconn
) {
172 send_config_update(0, false);
174 svec_destroy(&new_cfg
);
178 controller_name
= cfg_get_string(0, "mgmt.controller");
179 if (!controller_name
) {
180 VLOG_ERR("no controller specified for managment");
181 svec_destroy(&new_cfg
);
185 max_backoff
= cfg_get_int(0, "mgmt.max-backoff");
186 if (max_backoff
< 1) {
187 max_backoff
= MAX_BACKOFF_DEFAULT
;
188 } else if (max_backoff
> 3600) {
192 inactivity_probe
= cfg_get_int(0, "mgmt.inactivity-probe");
193 if (inactivity_probe
< 5) {
194 inactivity_probe
= INACTIVITY_PROBE_DEFAULT
;
197 /* xxx If this changes, we need to restart bridges to use new id,
198 * xxx but they need the id before the connect to controller, but we
199 * xxx need their dpids. */
200 /* Check if a different mgmt id has been assigned. */
201 if (cfg_has("mgmt.id")) {
202 uint64_t cfg_mgmt_id
= cfg_get_dpid(0, "mgmt.id");
203 if (cfg_mgmt_id
!= mgmt_id
) {
204 mgmt_id
= cfg_mgmt_id
;
208 svec_swap(&new_cfg
, &mgmt_cfg
);
209 svec_destroy(&new_cfg
);
213 mgmt_configure_ssl();
217 rconn_destroy(mgmt_rconn
);
220 mgmt_rconn
= rconn_create(inactivity_probe
, max_backoff
);
221 retval
= rconn_connect(mgmt_rconn
, controller_name
);
222 if (retval
== EAFNOSUPPORT
) {
223 VLOG_ERR("no support for %s vconn", controller_name
);
228 make_ofmp_xid(size_t ofmp_len
, uint16_t type
, uint32_t xid
,
229 struct ofpbuf
**bufferp
)
231 struct ofmp_header
*oh
;
233 oh
= make_openflow_xid(ofmp_len
, OFPT_VENDOR
, xid
, bufferp
);
234 oh
->header
.vendor
= htonl(NX_VENDOR_ID
);
235 oh
->header
.subtype
= htonl(NXT_MGMT
);
236 oh
->type
= htons(type
);
242 make_ofmp(size_t ofmp_len
, uint16_t type
, struct ofpbuf
**bufferp
)
244 struct ofmp_header
*oh
;
246 oh
= make_openflow(ofmp_len
, OFPT_VENDOR
, bufferp
);
247 oh
->header
.vendor
= htonl(NX_VENDOR_ID
);
248 oh
->header
.subtype
= htonl(NXT_MGMT
);
249 oh
->type
= htons(type
);
255 send_openflow_buffer(struct ofpbuf
*buffer
)
260 VLOG_ERR("attempt to send openflow packet with no rconn\n");
264 /* OpenFlow messages use a 16-bit length field, so messages over 64K
265 * must be broken into multiple pieces.
267 if (buffer
->size
<= 65535) {
268 update_openflow_length(buffer
);
269 retval
= rconn_send_with_limit(mgmt_rconn
, buffer
, txqlen
, TXQ_LIMIT
);
271 VLOG_WARN_RL(&rl
, "send to %s failed: %s",
272 rconn_get_name(mgmt_rconn
), strerror(retval
));
276 struct ofmp_header
*header
= (struct ofmp_header
*)buffer
->data
;
277 uint32_t xid
= header
->header
.header
.xid
;
278 size_t remain
= buffer
->size
;
279 uint8_t *ptr
= buffer
->data
;
281 /* Mark the OpenFlow header with a zero length to indicate some
284 header
->header
.header
.length
= 0;
287 struct ofpbuf
*new_buffer
;
288 struct ofmp_extended_data
*oed
;
289 size_t new_len
= MIN(65535 - sizeof *oed
, remain
);
291 oed
= make_ofmp_xid(sizeof *oed
, OFMPT_EXTENDED_DATA
, xid
,
293 oed
->type
= header
->type
;
295 if (remain
> 65535) {
296 oed
->flags
|= OFMPEDF_MORE_DATA
;
299 printf("xxx SENDING LEN: %d\n", new_len
);
301 /* Copy the entire original message, including the OpenFlow
302 * header, since management protocol structure definitions
303 * include these headers.
305 ofpbuf_put(new_buffer
, ptr
, new_len
);
307 update_openflow_length(new_buffer
);
308 retval
= rconn_send_with_limit(mgmt_rconn
, new_buffer
, txqlen
,
311 VLOG_WARN_RL(&rl
, "send to %s failed: %s",
312 rconn_get_name(mgmt_rconn
), strerror(retval
));
313 ofpbuf_delete(buffer
);
321 ofpbuf_delete(buffer
);
327 send_features_reply(uint32_t xid
)
329 struct ofpbuf
*buffer
;
330 struct ofp_switch_features
*ofr
;
332 ofr
= make_openflow_xid(sizeof *ofr
, OFPT_FEATURES_REPLY
, xid
, &buffer
);
333 ofr
->datapath_id
= 0;
336 ofr
->capabilities
= 0;
338 send_openflow_buffer(buffer
);
342 send_capability_reply(uint32_t xid
)
345 struct ofpbuf
*buffer
;
346 struct ofmp_capability_reply
*ofmpcr
;
348 ofmpcr
= make_ofmp_xid(sizeof *ofmpcr
, OFMPT_CAPABILITY_REPLY
,
350 ofmpcr
->format
= htonl(OFMPCOF_SIMPLE
);
351 ofmpcr
->mgmt_id
= htonll(mgmt_id
);
352 for (i
=0; i
<capabilities
.n
; i
++) {
353 ofpbuf_put(buffer
, capabilities
.names
[i
],
354 strlen(capabilities
.names
[i
]));
356 send_openflow_buffer(buffer
);
360 send_resources_update(uint32_t xid
, bool use_xid
)
362 struct ofpbuf
*buffer
;
363 struct ofmp_resources_update
*ofmpru
;
364 struct ofmp_tlv
*tlv
;
366 struct svec port_list
;
367 const char *host_uuid
;
371 ofmpru
= make_ofmp_xid(sizeof *ofmpru
, OFMPT_RESOURCES_UPDATE
,
374 ofmpru
= make_ofmp(sizeof *ofmpru
, OFMPT_RESOURCES_UPDATE
, &buffer
);
377 /* On XenServer systems, each host has its own UUID, which we provide
380 host_uuid
= xenserver_get_host_uuid();
382 struct ofmptsr_mgmt_uuid
*mgmt_uuid_tlv
;
384 mgmt_uuid_tlv
= ofpbuf_put_zeros(buffer
, sizeof(*mgmt_uuid_tlv
));
385 mgmt_uuid_tlv
->type
= htons(OFMPTSR_MGMT_UUID
);
386 mgmt_uuid_tlv
->len
= htons(sizeof(*mgmt_uuid_tlv
));
387 mgmt_uuid_tlv
->mgmt_id
= htonll(mgmt_id
);
388 memcpy(mgmt_uuid_tlv
->uuid
, host_uuid
, OFMP_UUID_LEN
);
392 cfg_get_subsections(&br_list
, "bridge");
393 for (i
=0; i
< br_list
.n
; i
++) {
394 struct ofmptsr_dp
*dp_tlv
;
398 dp_id
= bridge_get_datapathid(br_list
.names
[i
]);
400 VLOG_WARN_RL(&rl
, "bridge %s doesn't seem to exist",
404 dp_tlv
= ofpbuf_put_zeros(buffer
, sizeof(*dp_tlv
));
405 dp_tlv
->type
= htons(OFMPTSR_DP
);
406 dp_tlv
->len
= htons(sizeof(*dp_tlv
));
408 dp_tlv
->dp_id
= htonll(dp_id
);
409 memcpy(dp_tlv
->name
, br_list
.names
[i
], strlen(br_list
.names
[i
])+1);
411 /* On XenServer systems, each network has one or more UUIDs
412 * associated with it, which we provide to the controller.
414 n_uuid
= cfg_count("bridge.%s.xs-network-uuids", br_list
.names
[i
]);
416 struct ofmptsr_dp_uuid
*dp_uuid_tlv
;
417 size_t tlv_len
= sizeof(*dp_uuid_tlv
) + n_uuid
* OFMP_UUID_LEN
;
420 dp_uuid_tlv
= ofpbuf_put_zeros(buffer
, sizeof(*dp_uuid_tlv
));
421 dp_uuid_tlv
->type
= htons(OFMPTSR_DP_UUID
);
422 dp_uuid_tlv
->len
= htons(tlv_len
);
423 dp_uuid_tlv
->dp_id
= htonll(dp_id
);
425 for (j
=0; j
<n_uuid
; j
++) {
426 const char *dp_uuid
= cfg_get_string(j
,
427 "bridge.%s.xs-network-uuids", br_list
.names
[i
]);
429 /* The UUID list could change underneath us, so just
430 * fill with zeros in that case. Another update will be
431 * initiated shortly, which should contain corrected data.
434 ofpbuf_put(buffer
, dp_uuid
, OFMP_UUID_LEN
);
436 ofpbuf_put_zeros(buffer
, OFMP_UUID_LEN
);
441 svec_destroy(&br_list
);
443 /* On XenServer systems, extended information about virtual interfaces
444 * (VIFs) is available, which is needed by the controller.
446 svec_init(&port_list
);
447 bridge_get_ifaces(&port_list
);
448 for (i
=0; i
< port_list
.n
; i
++) {
449 const char *vif_uuid
, *vm_uuid
, *net_uuid
;
451 struct ofmptsr_vif
*vif_tlv
;
453 vif_uuid
= cfg_get_string(0, "port.%s.vif-uuid", port_list
.names
[i
]);
458 vif_tlv
= ofpbuf_put_zeros(buffer
, sizeof(*vif_tlv
));
459 vif_tlv
->type
= htons(OFMPTSR_VIF
);
460 vif_tlv
->len
= htons(sizeof(*vif_tlv
));
462 memcpy(vif_tlv
->name
, port_list
.names
[i
], strlen(port_list
.names
[i
])+1);
463 memcpy(vif_tlv
->vif_uuid
, vif_uuid
, sizeof(vif_tlv
->vif_uuid
));
465 vm_uuid
= cfg_get_string(0, "port.%s.vm-uuid", port_list
.names
[i
]);
467 memcpy(vif_tlv
->vm_uuid
, vm_uuid
, sizeof(vif_tlv
->vm_uuid
));
469 /* In case the vif disappeared underneath us. */
470 memset(vif_tlv
->vm_uuid
, '\0', sizeof(vif_tlv
->vm_uuid
));
473 net_uuid
= cfg_get_string(0, "port.%s.net-uuid", port_list
.names
[i
]);
475 memcpy(vif_tlv
->net_uuid
, net_uuid
, sizeof(vif_tlv
->net_uuid
));
477 /* In case the vif disappeared underneath us. */
478 memset(vif_tlv
->net_uuid
, '\0', sizeof(vif_tlv
->net_uuid
));
481 vif_mac
= cfg_get_mac(0, "port.%s.vif-mac", port_list
.names
[i
]);
482 vif_tlv
->vif_mac
= htonll(vif_mac
);
484 svec_destroy(&port_list
);
486 /* Put end marker. */
487 tlv
= ofpbuf_put_zeros(buffer
, sizeof(*tlv
));
488 tlv
->type
= htons(OFMPTSR_END
);
489 tlv
->len
= htons(sizeof(*tlv
));
490 send_openflow_buffer(buffer
);
494 send_config_update(uint32_t xid
, bool use_xid
)
496 struct ofpbuf
*buffer
;
497 struct ofmp_config_update
*ofmpcu
;
500 ofmpcu
= make_ofmp_xid(sizeof *ofmpcu
, OFMPT_CONFIG_UPDATE
,
503 ofmpcu
= make_ofmp(sizeof *ofmpcu
, OFMPT_CONFIG_UPDATE
, &buffer
);
506 ofmpcu
->format
= htonl(OFMPCOF_SIMPLE
);
507 memcpy(ofmpcu
->cookie
, cfg_cookie
, sizeof(ofmpcu
->cookie
));
509 send_openflow_buffer(buffer
);
513 send_config_update_ack(uint32_t xid
, bool success
)
515 struct ofpbuf
*buffer
;
516 struct ofmp_config_update_ack
*ofmpcua
;
518 ofmpcua
= make_ofmp_xid(sizeof *ofmpcua
, OFMPT_CONFIG_UPDATE_ACK
,
521 ofmpcua
->format
= htonl(OFMPCOF_SIMPLE
);
523 ofmpcua
->flags
= htonl(OFMPCUAF_SUCCESS
);
525 cfg_get_cookie(ofmpcua
->cookie
);
526 send_openflow_buffer(buffer
);
530 send_ofmp_error_msg(uint32_t xid
, uint16_t type
, uint16_t code
,
531 const void *data
, size_t len
)
533 struct ofpbuf
*buffer
;
534 struct ofmp_error_msg
*oem
;
536 oem
= make_ofmp_xid(sizeof(*oem
)+len
, OFMPT_ERROR
, xid
, &buffer
);
537 oem
->type
= htons(type
);
538 oem
->code
= htons(code
);
539 memcpy(oem
->data
, data
, len
);
540 send_openflow_buffer(buffer
);
544 send_error_msg(uint32_t xid
, uint16_t type
, uint16_t code
,
545 const void *data
, size_t len
)
547 struct ofpbuf
*buffer
;
548 struct ofp_error_msg
*oem
;
550 oem
= make_openflow_xid(sizeof(*oem
)+len
, OFPT_ERROR
, xid
, &buffer
);
551 oem
->type
= htons(type
);
552 oem
->code
= htons(code
);
553 memcpy(oem
->data
, data
, len
);
554 send_openflow_buffer(buffer
);
558 recv_echo_request(uint32_t xid UNUSED
, const void *msg
)
560 const struct ofp_header
*rq
= msg
;
561 send_openflow_buffer(make_echo_reply(rq
));
566 recv_features_request(uint32_t xid
, const void *msg UNUSED
)
568 send_features_reply(xid
);
573 recv_set_config(uint32_t xid UNUSED
, const void *msg UNUSED
)
575 /* Nothing to configure! */
580 recv_ofmp_capability_request(uint32_t xid
, const struct ofmp_header
*ofmph
,
583 struct ofmp_capability_request
*ofmpcr
;
585 if (len
!= sizeof(*ofmpcr
)) {
590 ofmpcr
= (struct ofmp_capability_request
*)ofmph
;
591 if (ofmpcr
->format
!= htonl(OFMPCAF_SIMPLE
)) {
596 send_capability_reply(xid
);
602 recv_ofmp_resources_request(uint32_t xid
, const void *msg UNUSED
,
605 send_resources_update(xid
, true);
610 recv_ofmp_config_request(uint32_t xid
, const struct ofmp_header
*ofmph
,
613 struct ofmp_config_request
*ofmpcr
;
615 if (len
!= sizeof(*ofmpcr
)) {
620 ofmpcr
= (struct ofmp_config_request
*)ofmph
;
621 if (ofmpcr
->format
!= htonl(OFMPCOF_SIMPLE
)) {
626 send_config_update(xid
, true);
632 recv_ofmp_config_update(uint32_t xid
, const struct ofmp_header
*ofmph
,
635 struct ofmp_config_update
*ofmpcu
;
638 data_len
= len
- sizeof(*ofmpcu
);
639 if (data_len
<= sizeof(*ofmpcu
)) {
640 /* xxx Send error. */
644 ofmpcu
= (struct ofmp_config_update
*)ofmph
;
645 if (ofmpcu
->format
!= htonl(OFMPCOF_SIMPLE
)) {
650 /* Check if the supplied cookie matches our current understanding of
651 * it. If they don't match, tell the controller and let it sort
653 if (cfg_lock(ofmpcu
->cookie
, 0)) {
654 /* xxx cfg_lock can fail for other reasons, such as being
656 VLOG_WARN_RL(&rl
, "config update failed due to bad cookie\n");
657 send_config_update_ack(xid
, false);
661 /* xxx We should probably do more sanity checking than this. */
663 cfg_write_data(ofmpcu
->data
, data_len
);
666 /* Send the ACK before running reconfigure, since our management
667 * connection settings may have changed. */
668 send_config_update_ack(xid
, true);
670 need_reconfigure
= true;
676 recv_ofmp_extended_data(uint32_t xid
, const struct ofmp_header
*ofmph
,
680 struct ofmp_extended_data
*ofmped
;
683 data_len
= len
- sizeof(*ofmped
);
684 if (data_len
<= sizeof(*ofmped
)) {
685 /* xxx Send error. */
689 ofmped
= (struct ofmp_extended_data
*)ofmph
;
691 ptr
= ofpbuf_put(&ext_data_buffer
, ofmped
->data
, data_len
);
693 if (!ofmped
->flags
& OFMPEDF_MORE_DATA
) {
694 recv_ofmp(xid
, ext_data_buffer
.data
, ext_data_buffer
.size
);
695 ofpbuf_clear(&ext_data_buffer
);
701 /* Handles receiving a management message. Generally, this function
702 * will be called 'len' set to zero, and the length will be derived by
703 * the OpenFlow header. With the extended data message, management
704 * messages are not constrained by OpenFlow's 64K message length limit.
705 * The extended data handler calls this function with the 'len' set to
706 * the total message length and the OpenFlow header's length field is
710 int recv_ofmp(uint32_t xid
, struct ofmp_header
*ofmph
, size_t len
)
713 len
= ntohs(ofmph
->header
.header
.length
);
716 /* xxx Should sanity-check for min/max length */
717 switch (ntohs(ofmph
->type
))
719 case OFMPT_CAPABILITY_REQUEST
:
720 return recv_ofmp_capability_request(xid
, ofmph
, len
);
721 case OFMPT_RESOURCES_REQUEST
:
722 return recv_ofmp_resources_request(xid
, ofmph
, len
);
723 case OFMPT_CONFIG_REQUEST
:
724 return recv_ofmp_config_request(xid
, ofmph
, len
);
725 case OFMPT_CONFIG_UPDATE
:
726 return recv_ofmp_config_update(xid
, ofmph
, len
);
727 case OFMPT_EXTENDED_DATA
:
728 return recv_ofmp_extended_data(xid
, ofmph
, len
);
730 VLOG_WARN_RL(&rl
, "unknown mgmt message: %d",
737 recv_nx_msg(uint32_t xid
, const void *oh
)
739 const struct nicira_header
*nh
= oh
;
741 switch (ntohl(nh
->subtype
)) {
744 return recv_ofmp(xid
, (struct ofmp_header
*)oh
, 0);
747 send_error_msg(xid
, OFPET_BAD_REQUEST
, OFPBRC_BAD_SUBTYPE
,
748 oh
, ntohs(nh
->header
.length
));
754 recv_vendor(uint32_t xid
, const void *oh
)
756 const struct ofp_vendor_header
*ovh
= oh
;
758 switch (ntohl(ovh
->vendor
))
761 return recv_nx_msg(xid
, oh
);
764 VLOG_WARN_RL(&rl
, "unknown vendor: 0x%x", ntohl(ovh
->vendor
));
765 send_error_msg(xid
, OFPET_BAD_REQUEST
, OFPBRC_BAD_VENDOR
,
766 oh
, ntohs(ovh
->header
.length
));
772 handle_msg(uint32_t xid
, const void *msg
, size_t length
)
774 int (*handler
)(uint32_t, const void *);
775 struct ofp_header
*oh
;
778 COVERAGE_INC(mgmt_received
);
780 /* Check encapsulated length. */
781 oh
= (struct ofp_header
*) msg
;
782 if (ntohs(oh
->length
) > length
) {
785 assert(oh
->version
== OFP_VERSION
);
787 /* Figure out how to handle it. */
789 case OFPT_ECHO_REQUEST
:
790 min_size
= sizeof(struct ofp_header
);
791 handler
= recv_echo_request
;
793 case OFPT_ECHO_REPLY
:
795 case OFPT_FEATURES_REQUEST
:
796 min_size
= sizeof(struct ofp_header
);
797 handler
= recv_features_request
;
799 case OFPT_SET_CONFIG
:
800 min_size
= sizeof(struct ofp_switch_config
);
801 handler
= recv_set_config
;
804 min_size
= sizeof(struct ofp_vendor_header
);
805 handler
= recv_vendor
;
808 VLOG_WARN_RL(&rl
, "unknown openflow type: %d", oh
->type
);
809 send_error_msg(xid
, OFPET_BAD_REQUEST
, OFPBRC_BAD_TYPE
,
815 if (length
< min_size
) {
818 return handler(xid
, msg
);
830 need_reconfigure
= false;
831 rconn_run(mgmt_rconn
);
833 /* Do some processing, but cap it at a reasonable amount so that
834 * other processing doesn't starve. */
835 for (i
=0; i
<50; i
++) {
836 struct ofpbuf
*buffer
;
837 struct ofp_header
*oh
;
839 buffer
= rconn_recv(mgmt_rconn
);
844 if (buffer
->size
>= sizeof *oh
) {
846 handle_msg(oh
->xid
, buffer
->data
, buffer
->size
);
847 ofpbuf_delete(buffer
);
849 VLOG_WARN_RL(&rl
, "received too-short OpenFlow message");
853 return need_reconfigure
;
863 rconn_run_wait(mgmt_rconn
);
864 rconn_recv_wait(mgmt_rconn
);
868 pick_fallback_mgmt_id(void)
870 uint8_t ea
[ETH_ADDR_LEN
];
872 ea
[0] = 0x00; /* Set Nicira OUI. */
875 return eth_addr_to_uint64(ea
);