8da640fed263392493a2a998cffc93525c7cff7a
[sliver-openvswitch.git] / vswitchd / mgmt.c
1 /* Copyright (c) 2009 Nicira Networks
2  *
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #include <config.h>
17
18 #include <arpa/inet.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25
26 #include "bridge.h"
27 #include "cfg.h"
28 #include "coverage.h"
29 #include "list.h"
30 #include "mgmt.h"
31 #include "openflow/nicira-ext.h"
32 #include "openflow/openflow.h"
33 #include "openflow/openflow-mgmt.h"
34 #include "ofpbuf.h"
35 #include "ovs-vswitchd.h"
36 #include "packets.h"
37 #include "rconn.h"
38 #include "svec.h"
39 #include "vconn.h"
40 #include "vconn-ssl.h"
41 #include "xenserver.h"
42 #include "xtoxll.h"
43
44 #define THIS_MODULE VLM_mgmt
45 #include "vlog.h"
46
47 #define MAX_BACKOFF_DEFAULT 15
48 #define INACTIVITY_PROBE_DEFAULT 15
49
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;
58 uint64_t mgmt_id;
59
60
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. */
63
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);
68
69 void
70 mgmt_init(void)
71 {
72     txqlen = rconn_packet_counter_create();
73
74     svec_init(&mgmt_cfg);
75     svec_init(&capabilities);
76     svec_add_nocopy(&capabilities, 
77             xasprintf("com.nicira.mgmt.manager=true\n"));
78
79     mgmt_id = cfg_get_dpid(0, "mgmt.id");
80     if (!mgmt_id) {
81         /* Randomly generate a mgmt id */
82         mgmt_id = pick_fallback_mgmt_id();
83     }
84
85     ofpbuf_init(&ext_data_buffer, 0);
86 }
87
88 #ifdef HAVE_OPENSSL
89 static bool
90 config_string_change(const char *key, char **valuep)
91 {
92     const char *value = cfg_get_string(0, "%s", key);
93     if (value && (!*valuep || strcmp(value, *valuep))) {
94         free(*valuep);
95         *valuep = xstrdup(value);
96         return true;
97     } else {
98         return false;
99     }
100 }
101
102 static void
103 mgmt_configure_ssl(void)
104 {
105     static char *private_key_file;
106     static char *certificate_file;
107     static char *cacert_file;
108     struct stat s;
109
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);
114     }
115
116     if (config_string_change("ssl.certificate", &certificate_file)) {
117         vconn_ssl_set_certificate_file(certificate_file);
118     }
119
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"));
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         svec_clear(&mgmt_cfg);
146         if (mgmt_rconn) {
147             rconn_destroy(mgmt_rconn);
148             mgmt_rconn = NULL;
149         }
150         return;
151     }
152
153     /* If this is an established connection, send a resources update. */
154     /* xxx This is wasteful if there were no resource changes!!! */
155     if (mgmt_rconn) {
156         send_resources_update(0, false);
157     }
158
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));
162         cfg_updated = true;
163     }
164
165     svec_init(&new_cfg);
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
171          * changes. */
172         if (cfg_updated && mgmt_rconn) {
173             send_config_update(0, false);
174         }
175         svec_destroy(&new_cfg);
176         return;
177     }
178
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);
183         return;
184     }
185
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) {
190         max_backoff = 3600;
191     }
192
193     inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
194     if (inactivity_probe < 5) {
195         inactivity_probe = INACTIVITY_PROBE_DEFAULT;
196     }
197
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;
206         }
207     }
208
209     svec_swap(&new_cfg, &mgmt_cfg);
210     svec_destroy(&new_cfg);
211
212 #ifdef HAVE_OPENSSL
213     /* Configure SSL. */
214     mgmt_configure_ssl();
215 #endif
216
217     if (mgmt_rconn) {
218         rconn_destroy(mgmt_rconn);
219         mgmt_rconn = NULL;
220     }
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);
225     }
226
227     /* Reset the extended message buffer when we create a new
228      * management connection. */
229     ofpbuf_clear(&ext_data_buffer);
230 }
231
232 static void *
233 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
234         struct ofpbuf **bufferp)
235 {
236     struct ofmp_header *oh;
237
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);
242
243     return oh;
244 }
245
246 static void *
247 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
248 {
249     struct ofmp_header *oh;
250
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);
255
256     return oh;
257 }
258
259 static int
260 send_openflow_buffer(struct ofpbuf *buffer)
261 {               
262     int retval;
263
264     if (!mgmt_rconn) {
265         VLOG_ERR("attempt to send openflow packet with no rconn\n");
266         return EINVAL;
267     }
268
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) {
272         return EAGAIN;
273     }
274
275     /* OpenFlow messages use a 16-bit length field, so messages over 64K
276      * must be broken into multiple pieces. 
277      */
278     if (buffer->size <= 65535) {
279         update_openflow_length(buffer);
280         retval = rconn_send(mgmt_rconn, buffer, txqlen);
281         if (retval) {
282             VLOG_WARN_RL(&rl, "send to %s failed: %s",
283                          rconn_get_name(mgmt_rconn), strerror(retval));
284         }   
285         return retval;
286     } else {
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;
291         
292         /* Mark the OpenFlow header with a zero length to indicate some
293          * funkiness. 
294          */
295         header->header.header.length = 0;
296
297         while (remain > 0) {
298             struct ofpbuf *new_buffer;
299             struct ofmp_extended_data *oed;
300             size_t new_len = MIN(65535 - sizeof *oed, remain);
301
302             oed = make_ofmp_xid(sizeof *oed, OFMPT_EXTENDED_DATA, xid, 
303                     &new_buffer);
304             oed->type = header->type;
305
306             if (remain > new_len) {
307                 oed->flags |= OFMPEDF_MORE_DATA;
308             }
309
310             /* Copy the entire original message, including the OpenFlow
311              * header, since management protocol structure definitions
312              * include these headers.
313              */
314             ofpbuf_put(new_buffer, ptr, new_len);
315
316             update_openflow_length(new_buffer);
317             retval = rconn_send(mgmt_rconn, new_buffer, txqlen);
318             if (retval) {
319                 VLOG_WARN_RL(&rl, "send to %s failed: %s",
320                              rconn_get_name(mgmt_rconn), strerror(retval));
321                 ofpbuf_delete(buffer);
322                 return retval;
323             }   
324
325             remain -= new_len;
326             ptr += new_len;
327         }
328
329         ofpbuf_delete(buffer);
330         return 0;
331     }
332 }   
333     
334 static void
335 send_features_reply(uint32_t xid)
336 {
337     struct ofpbuf *buffer;
338     struct ofp_switch_features *ofr;
339
340     ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
341     ofr->datapath_id  = 0;
342     ofr->n_tables     = 0;
343     ofr->n_buffers    = 0;
344     ofr->capabilities = 0;
345     ofr->actions      = 0;
346     send_openflow_buffer(buffer);
347 }
348
349 static void 
350 send_capability_reply(uint32_t xid)
351 {
352     int i;
353     struct ofpbuf *buffer;
354     struct ofmp_capability_reply *ofmpcr;
355
356     ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY, 
357             xid, &buffer);
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]));
363     }
364     send_openflow_buffer(buffer);
365 }
366
367 static void 
368 send_resources_update(uint32_t xid, bool use_xid)
369 {
370     struct ofpbuf *buffer;
371     struct ofmp_resources_update *ofmpru;
372     struct ofmp_tlv *tlv;
373     struct svec br_list;
374     struct svec port_list;
375     const char *host_uuid;
376     int i;
377
378     if (use_xid) {
379         ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, 
380                 xid, &buffer);
381     } else {
382         ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
383     }
384
385     /* On XenServer systems, each host has its own UUID, which we provide
386      * to the controller. 
387      */ 
388     host_uuid = xenserver_get_host_uuid();
389     if (host_uuid) {
390         struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
391
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);
397     }
398
399     svec_init(&br_list);
400     cfg_get_subsections(&br_list, "bridge");
401     for (i=0; i < br_list.n; i++) {
402         struct ofmptsr_dp *dp_tlv;
403         uint64_t dp_id;
404         int n_uuid;
405
406         dp_id = bridge_get_datapathid(br_list.names[i]);
407         if (!dp_id) {
408             VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist", 
409                     br_list.names[i]);
410             continue;
411         }
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));
415
416         dp_tlv->dp_id = htonll(dp_id);
417         memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
418
419         /* On XenServer systems, each network has one or more UUIDs
420          * associated with it, which we provide to the controller. 
421          */
422         n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
423         if (n_uuid) {
424             struct ofmptsr_dp_uuid *dp_uuid_tlv;
425             size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
426             int j;
427
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);
432
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]);
436
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.
440                  */
441                 if (dp_uuid) {
442                     ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
443                 } else {
444                     ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
445                 }
446             }
447         }
448     }
449     svec_destroy(&br_list);
450
451     /* On XenServer systems, extended information about virtual interfaces 
452      * (VIFs) is available, which is needed by the controller. 
453      */ 
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;
458         uint64_t vif_mac;
459         struct ofmptsr_vif *vif_tlv;
460
461         vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
462         if (!vif_uuid) {
463             continue;
464         }
465
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));
469
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));
472
473         vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
474         if (vm_uuid) {
475             memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
476         } else {
477             /* In case the vif disappeared underneath us. */
478             memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
479         }
480
481         net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
482         if (net_uuid) {
483             memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
484         } else {
485             /* In case the vif disappeared underneath us. */
486             memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
487         }
488
489         vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
490         vif_tlv->vif_mac = htonll(vif_mac);
491     }
492     svec_destroy(&port_list);
493
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);
499 }
500
501 static void 
502 send_config_update(uint32_t xid, bool use_xid)
503 {
504     struct ofpbuf *buffer;
505     struct ofmp_config_update *ofmpcu;
506
507     if (use_xid) {
508         ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, 
509                 xid, &buffer);
510     } else {
511         ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
512     }
513
514     ofmpcu->format = htonl(OFMPCOF_SIMPLE);
515     memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
516     cfg_buf_put(buffer);
517     send_openflow_buffer(buffer);
518 }
519
520 static void 
521 send_config_update_ack(uint32_t xid, bool success)
522 {
523     struct ofpbuf *buffer;
524     struct ofmp_config_update_ack *ofmpcua;
525
526     ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK, 
527             xid, &buffer);
528
529     ofmpcua->format = htonl(OFMPCOF_SIMPLE);
530     if (success) {
531         ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
532     }
533     cfg_get_cookie(ofmpcua->cookie);
534     send_openflow_buffer(buffer);
535 }
536
537 static void
538 send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
539             const void *data, size_t len)
540 {
541     struct ofpbuf *buffer;
542     struct ofp_error_msg *oem;
543
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);
549 }
550
551 static int
552 recv_echo_request(uint32_t xid UNUSED, const void *msg)
553 {
554     const struct ofp_header *rq = msg;
555     send_openflow_buffer(make_echo_reply(rq));
556     return 0;
557 }
558
559 static int
560 recv_features_request(uint32_t xid, const void *msg UNUSED)
561 {
562     send_features_reply(xid);
563     return 0;
564 }
565
566 static int
567 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
568 {
569     /* Nothing to configure! */
570     return 0;
571 }
572
573 static int
574 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph,
575         size_t len)
576 {
577     struct ofmp_capability_request *ofmpcr;
578
579     if (len != sizeof(*ofmpcr)) {
580         /* xxx Send error */
581         return -EINVAL;
582     }
583
584     ofmpcr = (struct ofmp_capability_request *)ofmph;
585     if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
586         /* xxx Send error */
587         return -EINVAL;
588     }
589
590     send_capability_reply(xid);
591
592     return 0;
593 }
594
595 static int
596 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED, 
597         size_t len UNUSED)
598 {
599     send_resources_update(xid, true);
600     return 0;
601 }
602
603 static int
604 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph, 
605         size_t len)
606 {
607     struct ofmp_config_request *ofmpcr;
608
609     if (len != sizeof(*ofmpcr)) {
610         /* xxx Send error */
611         return -EINVAL;
612     }
613
614     ofmpcr = (struct ofmp_config_request *)ofmph;
615     if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
616         /* xxx Send error */
617         return -EINVAL;
618     }
619
620     send_config_update(xid, true);
621
622     return 0;
623 }
624
625 static int
626 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph,
627         size_t len)
628 {
629     struct ofmp_config_update *ofmpcu;
630     int data_len;
631
632     data_len = len - sizeof(*ofmpcu);
633     if (data_len <= sizeof(*ofmpcu)) {
634         /* xxx Send error. */
635         return -EINVAL;
636     }
637
638     ofmpcu = (struct ofmp_config_update *)ofmph;
639     if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
640         /* xxx Send error */
641         return -EINVAL;
642     }
643
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
646      * things out. */
647     if (cfg_lock(ofmpcu->cookie, 0)) {  
648         /* xxx cfg_lock can fail for other reasons, such as being
649          * xxx locked... */
650         VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
651
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");
658         }
659         send_config_update_ack(xid, false);
660         return 0;
661     }
662
663     /* xxx We should probably do more sanity checking than this. */
664
665     cfg_write_data(ofmpcu->data, data_len);
666     cfg_unlock();
667
668     /* Send the ACK before running reconfigure, since our management
669      * connection settings may have changed. */
670     send_config_update_ack(xid, true);
671
672     need_reconfigure = true;
673
674     return 0;
675 }
676
677 static int
678 recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
679         size_t len)
680 {
681     int data_len;
682     struct ofmp_extended_data *ofmped;
683
684     if (len <= sizeof(*ofmped)) {
685         /* xxx Send error. */
686         return -EINVAL;
687     }
688
689     ext_data_xid = xid;
690     ofmped = (struct ofmp_extended_data *)ofmph;
691
692     data_len = len - sizeof(*ofmped);
693     ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
694
695     if (!(ofmped->flags & OFMPEDF_MORE_DATA)) {
696         struct ofmp_header *new_oh;
697         int error;
698
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);
702         if (!new_oh) {
703             VLOG_WARN_RL(&rl, "received short embedded message: %zu\n",
704                     ext_data_buffer.size);
705             return -EINVAL;
706         }
707
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");
714             return -EINVAL;
715         }
716         new_oh->header.header.xid = ext_data_xid;
717         new_oh->header.header.length = 0;
718
719         error = recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
720         ofpbuf_clear(&ext_data_buffer);
721
722         return error;
723     }
724
725     return 0;
726 }
727
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 
734  * ignored.
735  */
736 static
737 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len)
738 {
739     if (!len) {
740         len = ntohs(ofmph->header.header.length);
741     }
742
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);
747     }
748
749     /* xxx Should sanity-check for min/max length */
750     switch (ntohs(ofmph->type)) 
751     {
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);
762         default:
763             VLOG_WARN_RL(&rl, "unknown mgmt message: %d", 
764                     ntohs(ofmph->type));
765             return -EINVAL;
766     }
767 }
768
769 static int 
770 recv_nx_msg(uint32_t xid, const void *oh)
771 {
772     const struct nicira_header *nh = oh;
773
774     switch (ntohl(nh->subtype)) {
775
776     case NXT_MGMT:
777         return recv_ofmp(xid, (struct ofmp_header *)oh, 0);
778
779     default:
780         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, 
781                 oh, ntohs(nh->header.length));
782         return -EINVAL;
783     }
784 }
785
786 static int
787 recv_vendor(uint32_t xid, const void *oh)
788 {
789     const struct ofp_vendor_header *ovh = oh;
790
791     switch (ntohl(ovh->vendor))
792     {
793     case NX_VENDOR_ID:
794         return recv_nx_msg(xid, oh);
795
796     default:
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));
800         return -EINVAL; 
801     }
802 }
803
804 static int
805 handle_msg(uint32_t xid, const void *msg, size_t length)
806 {
807     int (*handler)(uint32_t, const void *);
808     struct ofp_header *oh;
809     size_t min_size;
810
811     COVERAGE_INC(mgmt_received);
812
813     /* Check encapsulated length. */
814     oh = (struct ofp_header *) msg;
815     if (ntohs(oh->length) > length) {
816         return -EINVAL;
817     }
818     assert(oh->version == OFP_VERSION);
819
820     /* Figure out how to handle it. */
821     switch (oh->type) {
822     case OFPT_ECHO_REQUEST:
823         min_size = sizeof(struct ofp_header);
824         handler = recv_echo_request;
825         break;
826     case OFPT_ECHO_REPLY:
827         return 0;
828     case OFPT_FEATURES_REQUEST:
829         min_size = sizeof(struct ofp_header);
830         handler = recv_features_request;
831         break;
832     case OFPT_SET_CONFIG:
833         min_size = sizeof(struct ofp_switch_config);
834         handler = recv_set_config;
835         break;
836     case OFPT_VENDOR:
837         min_size = sizeof(struct ofp_vendor_header);
838         handler = recv_vendor;
839         break;
840     default:
841         VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
842         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
843                 msg, length);
844         return -EINVAL;
845     }
846
847     /* Handle it. */
848     if (length < min_size) {
849         return -EFAULT;
850     }
851     return handler(xid, msg);
852 }
853
854 bool 
855 mgmt_run(void)
856 {
857     int i;
858
859     if (!mgmt_rconn) {
860         return false;
861     }
862
863     need_reconfigure = false;
864     rconn_run(mgmt_rconn);
865
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;
871
872         buffer = rconn_recv(mgmt_rconn);
873         if (!buffer) {
874             break;
875         }
876
877         if (buffer->size >= sizeof *oh) {
878             oh = buffer->data;
879             handle_msg(oh->xid, buffer->data, buffer->size);
880             ofpbuf_delete(buffer);
881         } else {
882             VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
883         }
884     }
885
886     return need_reconfigure;
887 }
888
889 void
890 mgmt_wait(void)
891 {
892     if (!mgmt_rconn) {
893         return;
894     }
895
896     rconn_run_wait(mgmt_rconn);
897     rconn_recv_wait(mgmt_rconn);
898 }
899
900 static uint64_t
901 pick_fallback_mgmt_id(void)
902 {
903     uint8_t ea[ETH_ADDR_LEN];
904     eth_addr_random(ea);
905     ea[0] = 0x00;               /* Set Nicira OUI. */
906     ea[1] = 0x23;
907     ea[2] = 0x20;
908     return eth_addr_to_uint64(ea);
909 }