4f79263c4f17db769f30fcedda00b9328f0fb35d
[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 static struct ofpbuf ext_data_buffer;
65 uint64_t mgmt_id;
66
67
68 #define TXQ_LIMIT 128         /* Max number of packets to queue for tx. */
69 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
70
71 static uint64_t pick_fallback_mgmt_id(void);
72 static void send_config_update(uint32_t xid, bool use_xid);
73 static void send_resources_update(uint32_t xid, bool use_xid);
74 static int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len);
75
76 void
77 mgmt_init(void)
78 {
79     txqlen = rconn_packet_counter_create();
80
81     svec_init(&mgmt_cfg);
82     svec_init(&capabilities);
83     svec_add_nocopy(&capabilities, 
84             xasprintf("com.nicira.mgmt.manager=true\n"));
85
86     mgmt_id = cfg_get_dpid(0, "mgmt.id");
87     if (!mgmt_id) {
88         /* Randomly generate a mgmt id */
89         mgmt_id = pick_fallback_mgmt_id();
90     }
91
92     ofpbuf_init(&ext_data_buffer, 0);
93 }
94
95 #ifdef HAVE_OPENSSL
96 static bool
97 config_string_change(const char *key, char **valuep)
98 {
99     const char *value = cfg_get_string(0, "%s", key);
100     if (value && (!*valuep || strcmp(value, *valuep))) {
101         free(*valuep);
102         *valuep = xstrdup(value);
103         return true;
104     } else {
105         return false;
106     }
107 }
108
109 static void
110 mgmt_configure_ssl(void)
111 {
112     static char *private_key_file;
113     static char *certificate_file;
114     static char *cacert_file;
115
116     /* XXX SSL should be configurable separate from the bridges.
117      * XXX should be possible to de-configure SSL. */
118     if (config_string_change("ssl.private-key", &private_key_file)) {
119         vconn_ssl_set_private_key_file(private_key_file);
120     }
121
122     if (config_string_change("ssl.certificate", &certificate_file)) {
123         vconn_ssl_set_certificate_file(certificate_file);
124     }
125
126     if (config_string_change("ssl.ca-cert", &cacert_file)) {
127         vconn_ssl_set_ca_cert_file(cacert_file,
128                 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
129     }
130 }
131 #endif
132
133 void
134 mgmt_reconfigure(void)
135 {
136     struct svec new_cfg;
137     uint8_t new_cookie[CFG_COOKIE_LEN];
138     bool cfg_updated = false;
139     const char *controller_name;
140     int max_backoff;
141     int inactivity_probe;
142     int retval;
143
144     if (!cfg_has_section("mgmt")) {
145         if (mgmt_rconn) {
146             rconn_destroy(mgmt_rconn);
147             mgmt_rconn = NULL;
148         }
149         return;
150     }
151
152     /* If this is an established connection, send a resources update. */
153     /* xxx This is wasteful if there were no resource changes!!! */
154     if (mgmt_rconn) {
155         send_resources_update(0, false);
156     }
157
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));
161         cfg_updated = true;
162     }
163
164     svec_init(&new_cfg);
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
170          * changes. */
171         if (cfg_updated && mgmt_rconn) {
172             send_config_update(0, false);
173         }
174         svec_destroy(&new_cfg);
175         return;
176     }
177
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);
182         return;
183     }
184
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) {
189         max_backoff = 3600;
190     }
191
192     inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
193     if (inactivity_probe < 5) {
194         inactivity_probe = INACTIVITY_PROBE_DEFAULT;
195     }
196
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;
205         }
206     }
207
208     svec_swap(&new_cfg, &mgmt_cfg);
209     svec_destroy(&new_cfg);
210
211 #ifdef HAVE_OPENSSL
212     /* Configure SSL. */
213     mgmt_configure_ssl();
214 #endif
215
216     if (mgmt_rconn) {
217         rconn_destroy(mgmt_rconn);
218         mgmt_rconn = NULL;
219     }
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);
224     }
225 }
226
227 static void *
228 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
229         struct ofpbuf **bufferp)
230 {
231     struct ofmp_header *oh;
232
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);
237
238     return oh;
239 }
240
241 static void *
242 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
243 {
244     struct ofmp_header *oh;
245
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);
250
251     return oh;
252 }
253
254 static int
255 send_openflow_buffer(struct ofpbuf *buffer)
256 {               
257     int retval;
258
259     if (!mgmt_rconn) {
260         VLOG_ERR("attempt to send openflow packet with no rconn\n");
261         return EINVAL;
262     }
263
264     /* OpenFlow messages use a 16-bit length field, so messages over 64K
265      * must be broken into multiple pieces. 
266      */
267     if (buffer->size <= 65535) {
268         update_openflow_length(buffer);
269         retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
270         if (retval) {
271             VLOG_WARN_RL(&rl, "send to %s failed: %s",
272                          rconn_get_name(mgmt_rconn), strerror(retval));
273         }   
274         return retval;
275     } else {
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;
280         
281         /* Mark the OpenFlow header with a zero length to indicate some
282          * funkiness. 
283          */
284         header->header.header.length = 0;
285
286         while (remain > 0) {
287             struct ofpbuf *new_buffer;
288             struct ofmp_extended_data *oed;
289             size_t new_len = MIN(65535 - sizeof *oed, remain);
290
291             oed = make_ofmp_xid(sizeof *oed, OFMPT_EXTENDED_DATA, xid, 
292                     &new_buffer);
293             oed->type = header->type;
294
295             if (remain > 65535) {
296                 oed->flags |= OFMPEDF_MORE_DATA;
297             }
298
299             printf("xxx SENDING LEN: %d\n", new_len);
300
301             /* Copy the entire original message, including the OpenFlow
302              * header, since management protocol structure definitions
303              * include these headers.
304              */
305             ofpbuf_put(new_buffer, ptr, new_len);
306
307             update_openflow_length(new_buffer);
308             retval = rconn_send_with_limit(mgmt_rconn, new_buffer, txqlen, 
309                     TXQ_LIMIT);
310             if (retval) {
311                 VLOG_WARN_RL(&rl, "send to %s failed: %s",
312                              rconn_get_name(mgmt_rconn), strerror(retval));
313                 ofpbuf_delete(buffer);
314                 return retval;
315             }   
316
317             remain -= new_len;
318             ptr += new_len;
319         }
320
321         ofpbuf_delete(buffer);
322         return 0;
323     }
324 }   
325     
326 static void
327 send_features_reply(uint32_t xid)
328 {
329     struct ofpbuf *buffer;
330     struct ofp_switch_features *ofr;
331
332     ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
333     ofr->datapath_id  = 0;
334     ofr->n_tables     = 0;
335     ofr->n_buffers    = 0;
336     ofr->capabilities = 0;
337     ofr->actions      = 0;
338     send_openflow_buffer(buffer);
339 }
340
341 static void 
342 send_capability_reply(uint32_t xid)
343 {
344     int i;
345     struct ofpbuf *buffer;
346     struct ofmp_capability_reply *ofmpcr;
347
348     ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY, 
349             xid, &buffer);
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]));
355     }
356     send_openflow_buffer(buffer);
357 }
358
359 static void 
360 send_resources_update(uint32_t xid, bool use_xid)
361 {
362     struct ofpbuf *buffer;
363     struct ofmp_resources_update *ofmpru;
364     struct ofmp_tlv *tlv;
365     struct svec br_list;
366     struct svec port_list;
367     const char *host_uuid;
368     int i;
369
370     if (use_xid) {
371         ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, 
372                 xid, &buffer);
373     } else {
374         ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
375     }
376
377     /* On XenServer systems, each host has its own UUID, which we provide
378      * to the controller. 
379      */ 
380     host_uuid = xenserver_get_host_uuid();
381     if (host_uuid) {
382         struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
383
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);
389     }
390
391     svec_init(&br_list);
392     cfg_get_subsections(&br_list, "bridge");
393     for (i=0; i < br_list.n; i++) {
394         struct ofmptsr_dp *dp_tlv;
395         uint64_t dp_id;
396         int n_uuid;
397
398         dp_id = bridge_get_datapathid(br_list.names[i]);
399         if (!dp_id) {
400             VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist", 
401                     br_list.names[i]);
402             continue;
403         }
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));
407
408         dp_tlv->dp_id = htonll(dp_id);
409         memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
410
411         /* On XenServer systems, each network has one or more UUIDs
412          * associated with it, which we provide to the controller. 
413          */
414         n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
415         if (n_uuid) {
416             struct ofmptsr_dp_uuid *dp_uuid_tlv;
417             size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
418             int j;
419
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);
424
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]);
428
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.
432                  */
433                 if (dp_uuid) {
434                     ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
435                 } else {
436                     ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
437                 }
438             }
439         }
440     }
441     svec_destroy(&br_list);
442
443     /* On XenServer systems, extended information about virtual interfaces 
444      * (VIFs) is available, which is needed by the controller. 
445      */ 
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;
450         uint64_t vif_mac;
451         struct ofmptsr_vif *vif_tlv;
452
453         vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
454         if (!vif_uuid) {
455             continue;
456         }
457
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));
461
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));
464
465         vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
466         if (vm_uuid) {
467             memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
468         } else {
469             /* In case the vif disappeared underneath us. */
470             memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
471         }
472
473         net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
474         if (net_uuid) {
475             memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
476         } else {
477             /* In case the vif disappeared underneath us. */
478             memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
479         }
480
481         vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
482         vif_tlv->vif_mac = htonll(vif_mac);
483     }
484     svec_destroy(&port_list);
485
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);
491 }
492
493 static void 
494 send_config_update(uint32_t xid, bool use_xid)
495 {
496     struct ofpbuf *buffer;
497     struct ofmp_config_update *ofmpcu;
498
499     if (use_xid) {
500         ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, 
501                 xid, &buffer);
502     } else {
503         ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
504     }
505
506     ofmpcu->format = htonl(OFMPCOF_SIMPLE);
507     memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
508     cfg_buf_put(buffer);
509     send_openflow_buffer(buffer);
510 }
511
512 static void 
513 send_config_update_ack(uint32_t xid, bool success)
514 {
515     struct ofpbuf *buffer;
516     struct ofmp_config_update_ack *ofmpcua;
517
518     ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK, 
519             xid, &buffer);
520
521     ofmpcua->format = htonl(OFMPCOF_SIMPLE);
522     if (success) {
523         ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
524     }
525     cfg_get_cookie(ofmpcua->cookie);
526     send_openflow_buffer(buffer);
527 }
528
529 static void
530 send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
531             const void *data, size_t len)
532 {
533     struct ofpbuf *buffer;
534     struct ofmp_error_msg *oem;
535
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);
541 }
542
543 static void
544 send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
545             const void *data, size_t len)
546 {
547     struct ofpbuf *buffer;
548     struct ofp_error_msg *oem;
549
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);
555 }
556
557 static int
558 recv_echo_request(uint32_t xid UNUSED, const void *msg)
559 {
560     const struct ofp_header *rq = msg;
561     send_openflow_buffer(make_echo_reply(rq));
562     return 0;
563 }
564
565 static int
566 recv_features_request(uint32_t xid, const void *msg UNUSED)
567 {
568     send_features_reply(xid);
569     return 0;
570 }
571
572 static int
573 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
574 {
575     /* Nothing to configure! */
576     return 0;
577 }
578
579 static int
580 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph,
581         size_t len)
582 {
583     struct ofmp_capability_request *ofmpcr;
584
585     if (len != sizeof(*ofmpcr)) {
586         /* xxx Send error */
587         return -EINVAL;
588     }
589
590     ofmpcr = (struct ofmp_capability_request *)ofmph;
591     if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
592         /* xxx Send error */
593         return -EINVAL;
594     }
595
596     send_capability_reply(xid);
597
598     return 0;
599 }
600
601 static int
602 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED, 
603         size_t len UNUSED)
604 {
605     send_resources_update(xid, true);
606     return 0;
607 }
608
609 static int
610 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph, 
611         size_t len)
612 {
613     struct ofmp_config_request *ofmpcr;
614
615     if (len != sizeof(*ofmpcr)) {
616         /* xxx Send error */
617         return -EINVAL;
618     }
619
620     ofmpcr = (struct ofmp_config_request *)ofmph;
621     if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
622         /* xxx Send error */
623         return -EINVAL;
624     }
625
626     send_config_update(xid, true);
627
628     return 0;
629 }
630
631 static int
632 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph,
633         size_t len)
634 {
635     struct ofmp_config_update *ofmpcu;
636     int data_len;
637
638     data_len = len - sizeof(*ofmpcu);
639     if (data_len <= sizeof(*ofmpcu)) {
640         /* xxx Send error. */
641         return -EINVAL;
642     }
643
644     ofmpcu = (struct ofmp_config_update *)ofmph;
645     if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
646         /* xxx Send error */
647         return -EINVAL;
648     }
649
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
652      * things out. */
653     if (cfg_lock(ofmpcu->cookie, 0)) {  
654         /* xxx cfg_lock can fail for other reasons, such as being
655          * xxx locked... */
656         VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
657         send_config_update_ack(xid, false);
658         return 0;
659     }
660
661     /* xxx We should probably do more sanity checking than this. */
662
663     cfg_write_data(ofmpcu->data, data_len);
664     cfg_unlock();
665
666     /* Send the ACK before running reconfigure, since our management
667      * connection settings may have changed. */
668     send_config_update_ack(xid, true);
669
670     reconfigure();
671
672
673     return 0;
674 }
675
676 static int
677 recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
678         size_t len)
679 {
680     size_t data_len;
681     struct ofmp_extended_data *ofmped;
682     uint8_t *ptr;
683
684     data_len = len - sizeof(*ofmped);
685     if (data_len <= sizeof(*ofmped)) {
686         /* xxx Send error. */
687         return -EINVAL;
688     }
689
690     ofmped = (struct ofmp_extended_data *)ofmph;
691
692     ptr = ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
693
694     if (!ofmped->flags & OFMPEDF_MORE_DATA) {
695         recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
696         ofpbuf_clear(&ext_data_buffer);
697     }
698
699     return 0;
700 }
701
702 /* Handles receiving a management message.  Generally, this function
703  * will be called 'len' set to zero, and the length will be derived by
704  * the OpenFlow header.  With the extended data message, management
705  * messages are not constrained by OpenFlow's 64K message length limit.  
706  * The extended data handler calls this function with the 'len' set to
707  * the total message length and the OpenFlow header's length field is 
708  * ignored.
709  */
710 static
711 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len)
712 {
713     if (!len) {
714         len = ntohs(ofmph->header.header.length);
715     }
716
717     /* xxx Should sanity-check for min/max length */
718     switch (ntohs(ofmph->type)) 
719     {
720         case OFMPT_CAPABILITY_REQUEST:
721             return recv_ofmp_capability_request(xid, ofmph, len);
722         case OFMPT_RESOURCES_REQUEST:
723             return recv_ofmp_resources_request(xid, ofmph, len);
724         case OFMPT_CONFIG_REQUEST:
725             return recv_ofmp_config_request(xid, ofmph, len);
726         case OFMPT_CONFIG_UPDATE:
727             return recv_ofmp_config_update(xid, ofmph, len);
728         case OFMPT_EXTENDED_DATA:
729             return recv_ofmp_extended_data(xid, ofmph, len);
730         default:
731             VLOG_WARN_RL(&rl, "unknown mgmt message: %d", 
732                     ntohs(ofmph->type));
733             return -EINVAL;
734     }
735 }
736
737 static int 
738 recv_nx_msg(uint32_t xid, const void *oh)
739 {
740     const struct nicira_header *nh = oh;
741
742     switch (ntohl(nh->subtype)) {
743
744     case NXT_MGMT:
745         return recv_ofmp(xid, (struct ofmp_header *)oh, 0);
746
747     default:
748         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, 
749                 oh, ntohs(nh->header.length));
750         return -EINVAL;
751     }
752 }
753
754 static int
755 recv_vendor(uint32_t xid, const void *oh)
756 {
757     const struct ofp_vendor_header *ovh = oh;
758
759     switch (ntohl(ovh->vendor))
760     {
761     case NX_VENDOR_ID:
762         return recv_nx_msg(xid, oh);
763
764     default:
765         VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
766         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR, 
767                 oh, ntohs(ovh->header.length));
768         return -EINVAL; 
769     }
770 }
771
772 static int
773 handle_msg(uint32_t xid, const void *msg, size_t length)
774 {
775     int (*handler)(uint32_t, const void *);
776     struct ofp_header *oh;
777     size_t min_size;
778
779     COVERAGE_INC(mgmt_received);
780
781     /* Check encapsulated length. */
782     oh = (struct ofp_header *) msg;
783     if (ntohs(oh->length) > length) {
784         return -EINVAL;
785     }
786     assert(oh->version == OFP_VERSION);
787
788     /* Figure out how to handle it. */
789     switch (oh->type) {
790     case OFPT_ECHO_REQUEST:
791         min_size = sizeof(struct ofp_header);
792         handler = recv_echo_request;
793         break;
794     case OFPT_ECHO_REPLY:
795         return 0;
796     case OFPT_FEATURES_REQUEST:
797         min_size = sizeof(struct ofp_header);
798         handler = recv_features_request;
799         break;
800     case OFPT_SET_CONFIG:
801         min_size = sizeof(struct ofp_switch_config);
802         handler = recv_set_config;
803         break;
804     case OFPT_VENDOR:
805         min_size = sizeof(struct ofp_vendor_header);
806         handler = recv_vendor;
807         break;
808     default:
809         VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
810         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
811                 msg, length);
812         return -EINVAL;
813     }
814
815     /* Handle it. */
816     if (length < min_size) {
817         return -EFAULT;
818     }
819     return handler(xid, msg);
820 }
821
822 void 
823 mgmt_run(void)
824 {
825     int i;
826
827     if (!mgmt_rconn) {
828         return;
829     }
830
831     rconn_run(mgmt_rconn);
832
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;
838
839         buffer = rconn_recv(mgmt_rconn);
840         if (!buffer) {
841             break;
842         }
843
844         if (buffer->size >= sizeof *oh) {
845             oh = buffer->data;
846             handle_msg(oh->xid, buffer->data, buffer->size);
847             ofpbuf_delete(buffer);
848         } else {
849             VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
850         }
851     }
852 }
853
854 void
855 mgmt_wait(void)
856 {
857     if (!mgmt_rconn) {
858         return;
859     }
860
861     rconn_run_wait(mgmt_rconn);
862     rconn_recv_wait(mgmt_rconn);
863 }
864
865 static uint64_t
866 pick_fallback_mgmt_id(void)
867 {
868     uint8_t ea[ETH_ADDR_LEN];
869     eth_addr_random(ea);
870     ea[0] = 0x00;               /* Set Nicira OUI. */
871     ea[1] = 0x23;
872     ea[2] = 0x20;
873     return eth_addr_to_uint64(ea);
874 }