f42f679ceb843c82df25458e4a655287c653e287
[openvswitch] / vswitchd / mgmt.c
1 /* Copyright (c) 2009 Nicira Networks
2  * 
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.
7  *
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.
12  *
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/>.
15  *
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.
25  *
26  */
27
28 #include <config.h>
29
30 #include <arpa/inet.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <stdlib.h>
34
35 #include "bridge.h"
36 #include "cfg.h"
37 #include "coverage.h"
38 #include "list.h"
39 #include "mgmt.h"
40 #include "openflow/nicira-ext.h"
41 #include "openflow/openflow.h"
42 #include "openflow/openflow-mgmt.h"
43 #include "ofpbuf.h"
44 #include "ovs-vswitchd.h"
45 #include "packets.h"
46 #include "rconn.h"
47 #include "svec.h"
48 #include "vconn.h"
49 #include "vconn-ssl.h"
50 #include "xenserver.h"
51 #include "xtoxll.h"
52
53 #define THIS_MODULE VLM_mgmt
54 #include "vlog.h"
55
56 #define MAX_BACKOFF_DEFAULT 15
57 #define INACTIVITY_PROBE_DEFAULT 15
58
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;
64 uint64_t mgmt_id;
65
66
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. */
69
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);
73
74 void
75 mgmt_init(void)
76 {
77     txqlen = rconn_packet_counter_create();
78
79     svec_init(&mgmt_cfg);
80     svec_init(&capabilities);
81     svec_add_nocopy(&capabilities, 
82             xasprintf("com.nicira.mgmt.manager=true\n"));
83
84     mgmt_id = cfg_get_dpid(0, "mgmt.id");
85     if (!mgmt_id) {
86         /* Randomly generate a mgmt id */
87         mgmt_id = pick_fallback_mgmt_id();
88     }
89 }
90
91 #ifdef HAVE_OPENSSL
92 static bool
93 config_string_change(const char *key, char **valuep)
94 {
95     const char *value = cfg_get_string(0, "%s", key);
96     if (value && (!*valuep || strcmp(value, *valuep))) {
97         free(*valuep);
98         *valuep = xstrdup(value);
99         return true;
100     } else {
101         return false;
102     }
103 }
104
105 static void
106 mgmt_configure_ssl(void)
107 {
108     static char *private_key_file;
109     static char *certificate_file;
110     static char *cacert_file;
111
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);
116     }
117
118     if (config_string_change("ssl.certificate", &certificate_file)) {
119         vconn_ssl_set_certificate_file(certificate_file);
120     }
121
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"));
125     }
126 }
127 #endif
128
129 void
130 mgmt_reconfigure(void)
131 {
132     struct svec new_cfg;
133     uint8_t new_cookie[CFG_COOKIE_LEN];
134     bool cfg_updated = false;
135     const char *controller_name;
136     int max_backoff;
137     int inactivity_probe;
138     int retval;
139
140     if (!cfg_has_section("mgmt")) {
141         if (mgmt_rconn) {
142             rconn_destroy(mgmt_rconn);
143             mgmt_rconn = NULL;
144         }
145         return;
146     }
147
148     /* If this is an established connection, send a resources update. */
149     /* xxx This is wasteful if there were no resource changes!!! */
150     if (mgmt_rconn) {
151         send_resources_update(0, false);
152     }
153
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));
157         cfg_updated = true;
158     }
159
160     svec_init(&new_cfg);
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
166          * changes. */
167         if (cfg_updated && mgmt_rconn) {
168             send_config_update(0, false);
169         }
170         svec_destroy(&new_cfg);
171         return;
172     }
173
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);
178         return;
179     }
180
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) {
185         max_backoff = 3600;
186     }
187
188     inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
189     if (inactivity_probe < 5) {
190         inactivity_probe = INACTIVITY_PROBE_DEFAULT;
191     }
192
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;
201         }
202     }
203
204     svec_swap(&new_cfg, &mgmt_cfg);
205     svec_destroy(&new_cfg);
206
207 #ifdef HAVE_OPENSSL
208     /* Configure SSL. */
209     mgmt_configure_ssl();
210 #endif
211
212     if (mgmt_rconn) {
213         rconn_destroy(mgmt_rconn);
214         mgmt_rconn = NULL;
215     }
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);
220     }
221 }
222
223 static int
224 send_openflow_buffer(struct ofpbuf *buffer)
225 {               
226     int retval;
227
228     if (!mgmt_rconn) {
229         VLOG_ERR("attempt to send openflow packet with no rconn\n");
230         return EINVAL;
231     }
232
233     update_openflow_length(buffer);
234     retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
235     if (retval) {
236         VLOG_WARN_RL(&rl, "send to %s failed: %s",
237                      rconn_get_name(mgmt_rconn), strerror(retval));
238     }   
239     return retval;
240 }   
241     
242 static void
243 send_features_reply(uint32_t xid)
244 {
245     struct ofpbuf *buffer;
246     struct ofp_switch_features *ofr;
247
248     ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
249     ofr->datapath_id  = 0;
250     ofr->n_tables     = 0;
251     ofr->n_buffers    = 0;
252     ofr->capabilities = 0;
253     ofr->actions      = 0;
254     send_openflow_buffer(buffer);
255 }
256
257 static void *
258 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
259         struct ofpbuf **bufferp)
260 {
261     struct ofmp_header *oh;
262
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);
267
268     return oh;
269 }
270
271 static void *
272 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
273 {
274     struct ofmp_header *oh;
275
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);
280
281     return oh;
282 }
283
284 static void 
285 send_capability_reply(uint32_t xid)
286 {
287     int i;
288     struct ofpbuf *buffer;
289     struct ofmp_capability_reply *ofmpcr;
290
291     ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY, 
292             xid, &buffer);
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]));
298     }
299     send_openflow_buffer(buffer);
300 }
301
302 static void 
303 send_resources_update(uint32_t xid, bool use_xid)
304 {
305     struct ofpbuf *buffer;
306     struct ofmp_resources_update *ofmpru;
307     struct ofmp_tlv *tlv;
308     struct svec br_list;
309     struct svec port_list;
310     const char *host_uuid;
311     int i;
312
313     if (use_xid) {
314         ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, 
315                 xid, &buffer);
316     } else {
317         ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
318     }
319
320     /* On XenServer systems, each host has its own UUID, which we provide
321      * to the controller. 
322      */ 
323     host_uuid = xenserver_get_host_uuid();
324     if (host_uuid) {
325         struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
326
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);
332     }
333
334     svec_init(&br_list);
335     cfg_get_subsections(&br_list, "bridge");
336     for (i=0; i < br_list.n; i++) {
337         struct ofmptsr_dp *dp_tlv;
338         uint64_t dp_id;
339         int n_uuid;
340
341         dp_id = bridge_get_datapathid(br_list.names[i]);
342         if (!dp_id) {
343             VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist", 
344                     br_list.names[i]);
345             continue;
346         }
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));
350
351         dp_tlv->dp_id = htonll(dp_id);
352         memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
353
354         /* On XenServer systems, each network has one or more UUIDs
355          * associated with it, which we provide to the controller. 
356          */
357         n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
358         if (n_uuid) {
359             struct ofmptsr_dp_uuid *dp_uuid_tlv;
360             size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
361             int j;
362
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);
367
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]);
371
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.
375                  */
376                 if (dp_uuid) {
377                     ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
378                 } else {
379                     ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
380                 }
381             }
382         }
383     }
384     svec_destroy(&br_list);
385
386     /* On XenServer systems, extended information about virtual interfaces 
387      * (VIFs) is available, which is needed by the controller. 
388      */ 
389     svec_init(&port_list);
390     bridge_get_ifaces(&port_list);
391     for (i=0; i < port_list.n; i++) {
392         const char *vif_uuid, *vm_uuid, *net_uuid;
393         uint64_t vif_mac;
394         struct ofmptsr_vif *vif_tlv;
395
396         vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
397         if (!vif_uuid) {
398             continue;
399         }
400
401         vif_tlv = ofpbuf_put_zeros(buffer, sizeof(*vif_tlv));
402         vif_tlv->type = htons(OFMPTSR_VIF);
403         vif_tlv->len = htons(sizeof(*vif_tlv));
404
405         memcpy(vif_tlv->name, port_list.names[i], strlen(port_list.names[i])+1);
406         memcpy(vif_tlv->vif_uuid, vif_uuid, sizeof(vif_tlv->vif_uuid));
407
408         vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
409         if (vm_uuid) {
410             memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
411         } else {
412             /* In case the vif disappeared underneath us. */
413             memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
414         }
415
416         net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
417         if (net_uuid) {
418             memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
419         } else {
420             /* In case the vif disappeared underneath us. */
421             memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
422         }
423
424         vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
425         vif_tlv->vif_mac = htonll(vif_mac);
426     }
427     svec_destroy(&port_list);
428
429     /* Put end marker. */
430     tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
431     tlv->type = htons(OFMPTSR_END);
432     tlv->len = htons(sizeof(*tlv));
433     send_openflow_buffer(buffer);
434 }
435
436 static void 
437 send_config_update(uint32_t xid, bool use_xid)
438 {
439     struct ofpbuf *buffer;
440     struct ofmp_config_update *ofmpcu;
441
442     if (use_xid) {
443         ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, 
444                 xid, &buffer);
445     } else {
446         ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
447     }
448
449     ofmpcu->format = htonl(OFMPCOF_SIMPLE);
450     memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
451     cfg_buf_put(buffer);
452     send_openflow_buffer(buffer);
453 }
454
455 static void 
456 send_config_update_ack(uint32_t xid, bool success)
457 {
458     struct ofpbuf *buffer;
459     struct ofmp_config_update_ack *ofmpcua;
460
461     ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK, 
462             xid, &buffer);
463
464     ofmpcua->format = htonl(OFMPCOF_SIMPLE);
465     if (success) {
466         ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
467     }
468     cfg_get_cookie(ofmpcua->cookie);
469     send_openflow_buffer(buffer);
470 }
471
472 static void
473 send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
474             const void *data, size_t len)
475 {
476     struct ofpbuf *buffer;
477     struct ofmp_error_msg *oem;
478
479     oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
480     oem->type = htons(type);
481     oem->code = htons(code);
482     memcpy(oem->data, data, len);
483     send_openflow_buffer(buffer);
484 }
485
486 static void
487 send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
488             const void *data, size_t len)
489 {
490     struct ofpbuf *buffer;
491     struct ofp_error_msg *oem;
492
493     oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
494     oem->type = htons(type);
495     oem->code = htons(code);
496     memcpy(oem->data, data, len);
497     send_openflow_buffer(buffer);
498 }
499
500 static int
501 recv_echo_request(uint32_t xid UNUSED, const void *msg)
502 {
503     const struct ofp_header *rq = msg;
504     send_openflow_buffer(make_echo_reply(rq));
505     return 0;
506 }
507
508 static int
509 recv_features_request(uint32_t xid, const void *msg UNUSED)
510 {
511     send_features_reply(xid);
512     return 0;
513 }
514
515 static int
516 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
517 {
518     /* Nothing to configure! */
519     return 0;
520 }
521
522 static int
523 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph)
524 {
525     struct ofmp_capability_request *ofmpcr;
526
527     if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
528         /* xxx Send error */
529         return -EINVAL;
530     }
531
532     ofmpcr = (struct ofmp_capability_request *)ofmph;
533     if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
534         /* xxx Send error */
535         return -EINVAL;
536     }
537
538     send_capability_reply(xid);
539
540     return 0;
541 }
542
543 static int
544 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED)
545 {
546     send_resources_update(xid, true);
547     return 0;
548 }
549
550 static int
551 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph)
552 {
553     struct ofmp_config_request *ofmpcr;
554
555     if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
556         /* xxx Send error */
557         return -EINVAL;
558     }
559
560     ofmpcr = (struct ofmp_config_request *)ofmph;
561     if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
562         /* xxx Send error */
563         return -EINVAL;
564     }
565
566     send_config_update(xid, true);
567
568     return 0;
569 }
570
571 static int
572 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph)
573 {
574     struct ofmp_config_update *ofmpcu;
575     int data_len;
576
577     data_len = htons(ofmph->header.header.length) - sizeof(*ofmpcu);
578     if (data_len <= sizeof(*ofmpcu)) {
579         /* xxx Send error. */
580         return -EINVAL;
581     }
582
583     ofmpcu = (struct ofmp_config_update *)ofmph;
584     if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
585         /* xxx Send error */
586         return -EINVAL;
587     }
588
589     /* Check if the supplied cookie matches our current understanding of
590      * it.  If they don't match, tell the controller and let it sort
591      * things out. */
592     if (cfg_lock(ofmpcu->cookie, 0)) {  
593         /* xxx cfg_lock can fail for other reasons, such as being
594          * xxx locked... */
595         VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
596         send_config_update_ack(xid, false);
597         return 0;
598     }
599
600     /* xxx We should probably do more sanity checking than this. */
601
602     cfg_write_data(ofmpcu->data, data_len);
603     cfg_unlock();
604
605     /* Send the ACK before running reconfigure, since our management
606      * connection settings may have changed. */
607     send_config_update_ack(xid, true);
608
609     reconfigure();
610
611
612     return 0;
613 }
614
615 static
616 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph)
617 {
618     /* xxx Should sanity-check for min/max length */
619     switch (ntohs(ofmph->type)) 
620     {
621         case OFMPT_CAPABILITY_REQUEST:
622             return recv_ofmp_capability_request(xid, ofmph);
623         case OFMPT_RESOURCES_REQUEST:
624             return recv_ofmp_resources_request(xid, ofmph);
625         case OFMPT_CONFIG_REQUEST:
626             return recv_ofmp_config_request(xid, ofmph);
627         case OFMPT_CONFIG_UPDATE:
628             return recv_ofmp_config_update(xid, ofmph);
629         default:
630             VLOG_WARN_RL(&rl, "unknown mgmt message: %d", 
631                     ntohs(ofmph->type));
632             return -EINVAL;
633     }
634 }
635
636 static int 
637 recv_nx_msg(uint32_t xid, const void *oh)
638 {
639     const struct nicira_header *nh = oh;
640
641     switch (ntohl(nh->subtype)) {
642
643     case NXT_MGMT:
644         return recv_ofmp(xid, (struct ofmp_header *)oh);
645
646     default:
647         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, 
648                 oh, htons(nh->header.length));
649         return -EINVAL;
650     }
651 }
652
653 static int
654 recv_vendor(uint32_t xid, const void *oh)
655 {
656     const struct ofp_vendor_header *ovh = oh;
657
658     switch (ntohl(ovh->vendor))
659     {
660     case NX_VENDOR_ID:
661         return recv_nx_msg(xid, oh);
662
663     default:
664         VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
665         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR, 
666                 oh, ntohs(ovh->header.length));
667         return -EINVAL; 
668     }
669 }
670
671 static int
672 handle_msg(uint32_t xid, const void *msg, size_t length)
673 {
674     int (*handler)(uint32_t, const void *);
675     struct ofp_header *oh;
676     size_t min_size;
677
678     COVERAGE_INC(mgmt_received);
679
680     /* Check encapsulated length. */
681     oh = (struct ofp_header *) msg;
682     if (ntohs(oh->length) > length) {
683         return -EINVAL;
684     }
685     assert(oh->version == OFP_VERSION);
686
687     /* Figure out how to handle it. */
688     switch (oh->type) {
689     case OFPT_ECHO_REQUEST:
690         min_size = sizeof(struct ofp_header);
691         handler = recv_echo_request;
692         break;
693     case OFPT_ECHO_REPLY:
694         return 0;
695     case OFPT_FEATURES_REQUEST:
696         min_size = sizeof(struct ofp_header);
697         handler = recv_features_request;
698         break;
699     case OFPT_SET_CONFIG:
700         min_size = sizeof(struct ofp_switch_config);
701         handler = recv_set_config;
702         break;
703     case OFPT_VENDOR:
704         min_size = sizeof(struct ofp_vendor_header);
705         handler = recv_vendor;
706         break;
707     default:
708         VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
709         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
710                 msg, length);
711         return -EINVAL;
712     }
713
714     /* Handle it. */
715     if (length < min_size) {
716         return -EFAULT;
717     }
718     return handler(xid, msg);
719 }
720
721 void 
722 mgmt_run(void)
723 {
724     int i;
725
726     if (!mgmt_rconn) {
727         return;
728     }
729
730     rconn_run(mgmt_rconn);
731
732     /* Do some processing, but cap it at a reasonable amount so that
733      * other processing doesn't starve. */
734     for (i=0; i<50; i++) {
735         struct ofpbuf *buffer;
736         struct ofp_header *oh;
737
738         buffer = rconn_recv(mgmt_rconn);
739         if (!buffer) {
740             break;
741         }
742
743         if (buffer->size >= sizeof *oh) {
744             oh = buffer->data;
745             handle_msg(oh->xid, buffer->data, buffer->size);
746             ofpbuf_delete(buffer);
747         } else {
748             VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
749         }
750     }
751 }
752
753 void
754 mgmt_wait(void)
755 {
756     if (!mgmt_rconn) {
757         return;
758     }
759
760     rconn_run_wait(mgmt_rconn);
761     rconn_recv_wait(mgmt_rconn);
762 }
763
764 static uint64_t
765 pick_fallback_mgmt_id(void)
766 {
767     uint8_t ea[ETH_ADDR_LEN];
768     eth_addr_random(ea);
769     ea[0] = 0x00;               /* Set Nicira OUI. */
770     ea[1] = 0x23;
771     ea[2] = 0x20;
772     return eth_addr_to_uint64(ea);
773 }