Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[cascardo/ovs.git] / 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 "xtoxll.h"
51
52 #define THIS_MODULE VLM_mgmt
53 #include "vlog.h"
54
55 #define MAX_BACKOFF_DEFAULT 15
56 #define INACTIVITY_PROBE_DEFAULT 15
57
58 static struct svec mgmt_cfg;
59 static uint8_t cfg_cookie[CFG_COOKIE_LEN];
60 static struct rconn *mgmt_rconn;
61 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
62 static struct svec capabilities;
63 uint64_t mgmt_id;
64
65
66 #define TXQ_LIMIT 128         /* Max number of packets to queue for tx. */
67 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
68
69 static uint64_t pick_fallback_mgmt_id(void);
70 static void send_config_update(uint32_t xid, bool use_xid);
71 static void send_resources_update(uint32_t xid, bool use_xid);
72
73 void
74 mgmt_init(void)
75 {
76     txqlen = rconn_packet_counter_create();
77
78     svec_init(&mgmt_cfg);
79     svec_init(&capabilities);
80     svec_add_nocopy(&capabilities, 
81             xasprintf("com.nicira.mgmt.manager=true\n"));
82
83     mgmt_id = cfg_get_dpid(0, "mgmt.id");
84     if (!mgmt_id) {
85         /* Randomly generate a mgmt id */
86         mgmt_id = pick_fallback_mgmt_id();
87     }
88 }
89
90 #ifdef HAVE_OPENSSL
91 static bool
92 config_string_change(const char *key, char **valuep)
93 {
94     const char *value = cfg_get_string(0, "%s", key);
95     if (value && (!*valuep || strcmp(value, *valuep))) {
96         free(*valuep);
97         *valuep = xstrdup(value);
98         return true;
99     } else {
100         return false;
101     }
102 }
103
104 static void
105 mgmt_configure_ssl(void)
106 {
107     static char *private_key_file;
108     static char *certificate_file;
109     static char *cacert_file;
110
111     /* XXX SSL should be configurable separate from the bridges.
112      * XXX should be possible to de-configure SSL. */
113     if (config_string_change("ssl.private-key", &private_key_file)) {
114         vconn_ssl_set_private_key_file(private_key_file);
115     }
116
117     if (config_string_change("ssl.certificate", &certificate_file)) {
118         vconn_ssl_set_certificate_file(certificate_file);
119     }
120
121     if (config_string_change("ssl.ca-cert", &cacert_file)) {
122         vconn_ssl_set_ca_cert_file(cacert_file,
123                 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
124     }
125 }
126 #endif
127
128 void
129 mgmt_reconfigure(void)
130 {
131     struct svec new_cfg;
132     uint8_t new_cookie[CFG_COOKIE_LEN];
133     bool cfg_updated = false;
134     const char *controller_name;
135     int max_backoff;
136     int inactivity_probe;
137     int retval;
138
139     if (!cfg_has_section("mgmt")) {
140         if (mgmt_rconn) {
141             rconn_destroy(mgmt_rconn);
142             mgmt_rconn = NULL;
143         }
144         return;
145     }
146
147     /* If this is an established connection, send a resources update. */
148     /* xxx This is wasteful if there were no resource changes!!! */
149     if (mgmt_rconn) {
150         send_resources_update(0, false);
151     }
152
153     cfg_get_cookie(new_cookie);
154     if (memcmp(cfg_cookie, new_cookie, sizeof(cfg_cookie))) {
155         memcpy(cfg_cookie, new_cookie, sizeof(cfg_cookie));
156         cfg_updated = true;
157     }
158
159     svec_init(&new_cfg);
160     cfg_get_section(&new_cfg, "mgmt");
161     if (svec_equal(&mgmt_cfg, &new_cfg)) {
162         /* Reconnecting to the controller causes the config file to be
163          * resent automatically.  If we're not reconnecting and the
164          * config file has changed, we need to notify the controller of
165          * changes. */
166         if (cfg_updated && mgmt_rconn) {
167             send_config_update(0, false);
168         }
169         svec_destroy(&new_cfg);
170         return;
171     }
172
173     controller_name = cfg_get_string(0, "mgmt.controller");
174     if (!controller_name) {
175         VLOG_ERR("no controller specified for managment");
176         svec_destroy(&new_cfg);
177         return;
178     }
179
180     max_backoff = cfg_get_int(0, "mgmt.max-backoff");
181     if (max_backoff < 1) {
182         max_backoff = MAX_BACKOFF_DEFAULT;
183     } else if (max_backoff > 3600) {
184         max_backoff = 3600;
185     }
186
187     inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
188     if (inactivity_probe < 5) {
189         inactivity_probe = INACTIVITY_PROBE_DEFAULT;
190     }
191
192     /* xxx If this changes, we need to restart bridges to use new id,
193      * xxx but they need the id before the connect to controller, but we
194      * xxx need their dpids. */
195     /* Check if a different mgmt id has been assigned. */
196     if (cfg_has("mgmt.id")) {
197         uint64_t cfg_mgmt_id = cfg_get_dpid(0, "mgmt.id");
198         if (cfg_mgmt_id != mgmt_id) {
199             mgmt_id = cfg_mgmt_id;
200         }
201     }
202
203     svec_swap(&new_cfg, &mgmt_cfg);
204     svec_destroy(&new_cfg);
205
206 #ifdef HAVE_OPENSSL
207     /* Configure SSL. */
208     mgmt_configure_ssl();
209 #endif
210
211     if (mgmt_rconn) {
212         rconn_destroy(mgmt_rconn);
213         mgmt_rconn = NULL;
214     }
215     mgmt_rconn = rconn_create(inactivity_probe, max_backoff);
216     retval = rconn_connect(mgmt_rconn, controller_name);
217     if (retval == EAFNOSUPPORT) {
218         VLOG_ERR("no support for %s vconn", controller_name);
219     }
220 }
221
222 static int
223 send_openflow_buffer(struct ofpbuf *buffer)
224 {               
225     int retval;
226
227     if (!mgmt_rconn) {
228         VLOG_ERR("attempt to send openflow packet with no rconn\n");
229         return EINVAL;
230     }
231
232     update_openflow_length(buffer);
233     retval = rconn_send_with_limit(mgmt_rconn, buffer, txqlen, TXQ_LIMIT);
234     if (retval) {
235         VLOG_WARN_RL(&rl, "send to %s failed: %s",
236                      rconn_get_name(mgmt_rconn), strerror(retval));
237     }   
238     return retval;
239 }   
240     
241 static void
242 send_features_reply(uint32_t xid)
243 {
244     struct ofpbuf *buffer;
245     struct ofp_switch_features *ofr;
246
247     ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
248     ofr->datapath_id  = 0;
249     ofr->n_tables     = 0;
250     ofr->n_buffers    = 0;
251     ofr->capabilities = 0;
252     ofr->actions      = 0;
253     send_openflow_buffer(buffer);
254 }
255
256 static void *
257 make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
258         struct ofpbuf **bufferp)
259 {
260     struct ofmp_header *oh;
261
262     oh = make_openflow_xid(ofmp_len, OFPT_VENDOR, xid, bufferp);
263     oh->header.vendor = htonl(NX_VENDOR_ID);
264     oh->header.subtype = htonl(NXT_MGMT);
265     oh->type = htons(type);
266
267     return oh;
268 }
269
270 static void *
271 make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
272 {
273     struct ofmp_header *oh;
274
275     oh = make_openflow(ofmp_len, OFPT_VENDOR, bufferp);
276     oh->header.vendor = htonl(NX_VENDOR_ID);
277     oh->header.subtype = htonl(NXT_MGMT);
278     oh->type = htons(type);
279
280     return oh;
281 }
282
283 static void 
284 send_capability_reply(uint32_t xid)
285 {
286     int i;
287     struct ofpbuf *buffer;
288     struct ofmp_capability_reply *ofmpcr;
289
290     ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY, 
291             xid, &buffer);
292     ofmpcr->format = htonl(OFMPCOF_SIMPLE);
293     ofmpcr->mgmt_id = htonll(mgmt_id);
294     for (i=0; i<capabilities.n; i++) {
295         ofpbuf_put(buffer, capabilities.names[i], 
296                 strlen(capabilities.names[i]));
297     }
298     send_openflow_buffer(buffer);
299 }
300
301 static void 
302 send_resources_update(uint32_t xid, bool use_xid)
303 {
304     struct ofpbuf *buffer;
305     struct ofmp_resources_update *ofmpru;
306     struct ofmp_tlv *tlv;
307     struct svec br_list;
308     int i;
309
310     if (use_xid) {
311         ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, 
312                 xid, &buffer);
313     } else {
314         ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
315     }
316
317     svec_init(&br_list);
318     cfg_get_subsections(&br_list, "bridge");
319     for (i=0; i < br_list.n; i++) {
320         struct ofmptsr_dp *dp_tlv;
321         uint64_t dp_id = bridge_get_datapathid(br_list.names[i]);
322         if (!dp_id) {
323             VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist", 
324                     br_list.names[i]);
325             continue;
326         }
327         dp_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_tlv));
328         dp_tlv->type = htons(OFMPTSR_DP);
329         dp_tlv->len = htons(sizeof(*dp_tlv));
330
331         dp_tlv->dp_id = htonll(dp_id);
332         memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
333     }
334
335     /* Put end marker. */
336     tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
337     tlv->type = htons(OFMPTSR_END);
338     tlv->len = htons(sizeof(*tlv));
339     send_openflow_buffer(buffer);
340 }
341
342 static void 
343 send_config_update(uint32_t xid, bool use_xid)
344 {
345     struct ofpbuf *buffer;
346     struct ofmp_config_update *ofmpcu;
347
348     if (use_xid) {
349         ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, 
350                 xid, &buffer);
351     } else {
352         ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
353     }
354
355     ofmpcu->format = htonl(OFMPCOF_SIMPLE);
356     memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
357     cfg_buf_put(buffer);
358     send_openflow_buffer(buffer);
359 }
360
361 static void 
362 send_config_update_ack(uint32_t xid, bool success)
363 {
364     struct ofpbuf *buffer;
365     struct ofmp_config_update_ack *ofmpcua;
366
367     ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK, 
368             xid, &buffer);
369
370     ofmpcua->format = htonl(OFMPCOF_SIMPLE);
371     if (success) {
372         ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
373     }
374     cfg_get_cookie(ofmpcua->cookie);
375     send_openflow_buffer(buffer);
376 }
377
378 static void
379 send_ofmp_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
380             const void *data, size_t len)
381 {
382     struct ofpbuf *buffer;
383     struct ofmp_error_msg *oem;
384
385     oem = make_ofmp_xid(sizeof(*oem)+len, OFMPT_ERROR, xid, &buffer);
386     oem->type = htons(type);
387     oem->code = htons(code);
388     memcpy(oem->data, data, len);
389     send_openflow_buffer(buffer);
390 }
391
392 static void
393 send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
394             const void *data, size_t len)
395 {
396     struct ofpbuf *buffer;
397     struct ofp_error_msg *oem;
398
399     oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
400     oem->type = htons(type);
401     oem->code = htons(code);
402     memcpy(oem->data, data, len);
403     send_openflow_buffer(buffer);
404 }
405
406 static int
407 recv_echo_request(uint32_t xid UNUSED, const void *msg)
408 {
409     const struct ofp_header *rq = msg;
410     send_openflow_buffer(make_echo_reply(rq));
411     return 0;
412 }
413
414 static int
415 recv_features_request(uint32_t xid, const void *msg UNUSED)
416 {
417     send_features_reply(xid);
418     return 0;
419 }
420
421 static int
422 recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
423 {
424     /* Nothing to configure! */
425     return 0;
426 }
427
428 static int
429 recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph)
430 {
431     struct ofmp_capability_request *ofmpcr;
432
433     if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
434         /* xxx Send error */
435         return -EINVAL;
436     }
437
438     ofmpcr = (struct ofmp_capability_request *)ofmph;
439     if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
440         /* xxx Send error */
441         return -EINVAL;
442     }
443
444     send_capability_reply(xid);
445
446     return 0;
447 }
448
449 static int
450 recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED)
451 {
452     send_resources_update(xid, true);
453     return 0;
454 }
455
456 static int
457 recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph)
458 {
459     struct ofmp_config_request *ofmpcr;
460
461     if (htons(ofmph->header.header.length) != sizeof(*ofmpcr)) {
462         /* xxx Send error */
463         return -EINVAL;
464     }
465
466     ofmpcr = (struct ofmp_config_request *)ofmph;
467     if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
468         /* xxx Send error */
469         return -EINVAL;
470     }
471
472     send_config_update(xid, true);
473
474     return 0;
475 }
476
477 static int
478 recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph)
479 {
480     struct ofmp_config_update *ofmpcu;
481     int data_len;
482
483     data_len = htons(ofmph->header.header.length) - sizeof(*ofmpcu);
484     if (data_len <= sizeof(*ofmpcu)) {
485         /* xxx Send error. */
486         return -EINVAL;
487     }
488
489     ofmpcu = (struct ofmp_config_update *)ofmph;
490     if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
491         /* xxx Send error */
492         return -EINVAL;
493     }
494
495     /* Check if the supplied cookie matches our current understanding of
496      * it.  If they don't match, tell the controller and let it sort
497      * things out. */
498     if (cfg_lock(ofmpcu->cookie, 0)) {  
499         /* xxx cfg_lock can fail for other reasons, such as being
500          * xxx locked... */
501         VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
502         send_config_update_ack(xid, false);
503         return 0;
504     }
505
506     /* xxx We should probably do more sanity checking than this. */
507
508     cfg_write_data(ofmpcu->data, data_len);
509     cfg_unlock();
510
511     /* Send the ACK before running reconfigure, since our management
512      * connection settings may have changed. */
513     send_config_update_ack(xid, true);
514
515     reconfigure();
516
517
518     return 0;
519 }
520
521 static
522 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph)
523 {
524     /* xxx Should sanity-check for min/max length */
525     switch (ntohs(ofmph->type)) 
526     {
527         case OFMPT_CAPABILITY_REQUEST:
528             return recv_ofmp_capability_request(xid, ofmph);
529         case OFMPT_RESOURCES_REQUEST:
530             return recv_ofmp_resources_request(xid, ofmph);
531         case OFMPT_CONFIG_REQUEST:
532             return recv_ofmp_config_request(xid, ofmph);
533         case OFMPT_CONFIG_UPDATE:
534             return recv_ofmp_config_update(xid, ofmph);
535         default:
536             VLOG_WARN_RL(&rl, "unknown mgmt message: %d", 
537                     ntohs(ofmph->type));
538             return -EINVAL;
539     }
540 }
541
542 static int 
543 recv_nx_msg(uint32_t xid, const void *oh)
544 {
545     const struct nicira_header *nh = oh;
546
547     switch (ntohl(nh->subtype)) {
548
549     case NXT_MGMT:
550         return recv_ofmp(xid, (struct ofmp_header *)oh);
551
552     default:
553         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, 
554                 oh, htons(nh->header.length));
555         return -EINVAL;
556     }
557 }
558
559 static int
560 recv_vendor(uint32_t xid, const void *oh)
561 {
562     const struct ofp_vendor_header *ovh = oh;
563
564     switch (ntohl(ovh->vendor))
565     {
566     case NX_VENDOR_ID:
567         return recv_nx_msg(xid, oh);
568
569     default:
570         VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
571         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR, 
572                 oh, ntohs(ovh->header.length));
573         return -EINVAL; 
574     }
575 }
576
577 static int
578 handle_msg(uint32_t xid, const void *msg, size_t length)
579 {
580     int (*handler)(uint32_t, const void *);
581     struct ofp_header *oh;
582     size_t min_size;
583
584     COVERAGE_INC(mgmt_received);
585
586     /* Check encapsulated length. */
587     oh = (struct ofp_header *) msg;
588     if (ntohs(oh->length) > length) {
589         return -EINVAL;
590     }
591     assert(oh->version == OFP_VERSION);
592
593     /* Figure out how to handle it. */
594     switch (oh->type) {
595     case OFPT_ECHO_REQUEST:
596         min_size = sizeof(struct ofp_header);
597         handler = recv_echo_request;
598         break;
599     case OFPT_ECHO_REPLY:
600         return 0;
601     case OFPT_FEATURES_REQUEST:
602         min_size = sizeof(struct ofp_header);
603         handler = recv_features_request;
604         break;
605     case OFPT_SET_CONFIG:
606         min_size = sizeof(struct ofp_switch_config);
607         handler = recv_set_config;
608         break;
609     case OFPT_VENDOR:
610         min_size = sizeof(struct ofp_vendor_header);
611         handler = recv_vendor;
612         break;
613     default:
614         VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
615         send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
616                 msg, length);
617         return -EINVAL;
618     }
619
620     /* Handle it. */
621     if (length < min_size) {
622         return -EFAULT;
623     }
624     return handler(xid, msg);
625 }
626
627 void 
628 mgmt_run(void)
629 {
630     int i;
631
632     if (!mgmt_rconn) {
633         return;
634     }
635
636     rconn_run(mgmt_rconn);
637
638     /* Do some processing, but cap it at a reasonable amount so that
639      * other processing doesn't starve. */
640     for (i=0; i<50; i++) {
641         struct ofpbuf *buffer;
642         struct ofp_header *oh;
643
644         buffer = rconn_recv(mgmt_rconn);
645         if (!buffer) {
646             break;
647         }
648
649         if (buffer->size >= sizeof *oh) {
650             oh = buffer->data;
651             handle_msg(oh->xid, buffer->data, buffer->size);
652             ofpbuf_delete(buffer);
653         } else {
654             VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
655         }
656     }
657 }
658
659 void
660 mgmt_wait(void)
661 {
662     if (!mgmt_rconn) {
663         return;
664     }
665
666     rconn_run_wait(mgmt_rconn);
667     rconn_recv_wait(mgmt_rconn);
668 }
669
670 static uint64_t
671 pick_fallback_mgmt_id(void)
672 {
673     uint8_t ea[ETH_ADDR_LEN];
674     eth_addr_random(ea);
675     ea[0] = 0x00;               /* Set Nicira OUI. */
676     ea[1] = 0x23;
677     ea[2] = 0x20;
678     return eth_addr_to_uint64(ea);
679 }