]> git.proxmox.com Git - mirror_ovs.git/blob - vswitchd/mgmt.c
Rename "secchan" to "ofproto" (library) and "ovs-openflowd" (program).
[mirror_ovs.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 uint64_t mgmt_id;
58
59
60 #define TXQ_LIMIT 128 /* Max number of packets to queue for tx. */
61 struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
62
63 static uint64_t pick_fallback_mgmt_id(void);
64 static void send_config_update(uint32_t xid, bool use_xid);
65 static void send_resources_update(uint32_t xid, bool use_xid);
66 static int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len);
67
68 void
69 mgmt_init(void)
70 {
71 txqlen = rconn_packet_counter_create();
72
73 svec_init(&mgmt_cfg);
74 svec_init(&capabilities);
75 svec_add_nocopy(&capabilities,
76 xasprintf("com.nicira.mgmt.manager=true\n"));
77
78 mgmt_id = cfg_get_dpid(0, "mgmt.id");
79 if (!mgmt_id) {
80 /* Randomly generate a mgmt id */
81 mgmt_id = pick_fallback_mgmt_id();
82 }
83
84 ofpbuf_init(&ext_data_buffer, 0);
85 }
86
87 #ifdef HAVE_OPENSSL
88 static bool
89 config_string_change(const char *key, char **valuep)
90 {
91 const char *value = cfg_get_string(0, "%s", key);
92 if (value && (!*valuep || strcmp(value, *valuep))) {
93 free(*valuep);
94 *valuep = xstrdup(value);
95 return true;
96 } else {
97 return false;
98 }
99 }
100
101 static void
102 mgmt_configure_ssl(void)
103 {
104 static char *private_key_file;
105 static char *certificate_file;
106 static char *cacert_file;
107 struct stat s;
108
109 /* XXX SSL should be configurable separate from the bridges.
110 * XXX should be possible to de-configure SSL. */
111 if (config_string_change("ssl.private-key", &private_key_file)) {
112 vconn_ssl_set_private_key_file(private_key_file);
113 }
114
115 if (config_string_change("ssl.certificate", &certificate_file)) {
116 vconn_ssl_set_certificate_file(certificate_file);
117 }
118
119 /* We assume that even if the filename hasn't changed, if the CA cert
120 * file has been removed, that we want to move back into
121 * boot-strapping mode. This opens a small security hole, because
122 * the old certificate will still be trusted until vSwitch is
123 * restarted. We may want to address this in vconn's SSL library. */
124 if (config_string_change("ssl.ca-cert", &cacert_file)
125 || (stat(cacert_file, &s) && errno == ENOENT)) {
126 vconn_ssl_set_ca_cert_file(cacert_file,
127 cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
128 }
129 }
130 #endif
131
132 void
133 mgmt_reconfigure(void)
134 {
135 struct svec new_cfg;
136 uint8_t new_cookie[CFG_COOKIE_LEN];
137 bool cfg_updated = false;
138 const char *controller_name;
139 int max_backoff;
140 int inactivity_probe;
141 int retval;
142
143 if (!cfg_has_section("mgmt")) {
144 svec_clear(&mgmt_cfg);
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 need_reconfigure = true;
671
672 return 0;
673 }
674
675 static int
676 recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
677 size_t len)
678 {
679 size_t data_len;
680 struct ofmp_extended_data *ofmped;
681 uint8_t *ptr;
682
683 data_len = len - sizeof(*ofmped);
684 if (data_len <= sizeof(*ofmped)) {
685 /* xxx Send error. */
686 return -EINVAL;
687 }
688
689 ofmped = (struct ofmp_extended_data *)ofmph;
690
691 ptr = ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
692
693 if (!ofmped->flags & OFMPEDF_MORE_DATA) {
694 recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
695 ofpbuf_clear(&ext_data_buffer);
696 }
697
698 return 0;
699 }
700
701 /* Handles receiving a management message. Generally, this function
702 * will be called 'len' set to zero, and the length will be derived by
703 * the OpenFlow header. With the extended data message, management
704 * messages are not constrained by OpenFlow's 64K message length limit.
705 * The extended data handler calls this function with the 'len' set to
706 * the total message length and the OpenFlow header's length field is
707 * ignored.
708 */
709 static
710 int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len)
711 {
712 if (!len) {
713 len = ntohs(ofmph->header.header.length);
714 }
715
716 /* xxx Should sanity-check for min/max length */
717 switch (ntohs(ofmph->type))
718 {
719 case OFMPT_CAPABILITY_REQUEST:
720 return recv_ofmp_capability_request(xid, ofmph, len);
721 case OFMPT_RESOURCES_REQUEST:
722 return recv_ofmp_resources_request(xid, ofmph, len);
723 case OFMPT_CONFIG_REQUEST:
724 return recv_ofmp_config_request(xid, ofmph, len);
725 case OFMPT_CONFIG_UPDATE:
726 return recv_ofmp_config_update(xid, ofmph, len);
727 case OFMPT_EXTENDED_DATA:
728 return recv_ofmp_extended_data(xid, ofmph, len);
729 default:
730 VLOG_WARN_RL(&rl, "unknown mgmt message: %d",
731 ntohs(ofmph->type));
732 return -EINVAL;
733 }
734 }
735
736 static int
737 recv_nx_msg(uint32_t xid, const void *oh)
738 {
739 const struct nicira_header *nh = oh;
740
741 switch (ntohl(nh->subtype)) {
742
743 case NXT_MGMT:
744 return recv_ofmp(xid, (struct ofmp_header *)oh, 0);
745
746 default:
747 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE,
748 oh, ntohs(nh->header.length));
749 return -EINVAL;
750 }
751 }
752
753 static int
754 recv_vendor(uint32_t xid, const void *oh)
755 {
756 const struct ofp_vendor_header *ovh = oh;
757
758 switch (ntohl(ovh->vendor))
759 {
760 case NX_VENDOR_ID:
761 return recv_nx_msg(xid, oh);
762
763 default:
764 VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
765 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR,
766 oh, ntohs(ovh->header.length));
767 return -EINVAL;
768 }
769 }
770
771 static int
772 handle_msg(uint32_t xid, const void *msg, size_t length)
773 {
774 int (*handler)(uint32_t, const void *);
775 struct ofp_header *oh;
776 size_t min_size;
777
778 COVERAGE_INC(mgmt_received);
779
780 /* Check encapsulated length. */
781 oh = (struct ofp_header *) msg;
782 if (ntohs(oh->length) > length) {
783 return -EINVAL;
784 }
785 assert(oh->version == OFP_VERSION);
786
787 /* Figure out how to handle it. */
788 switch (oh->type) {
789 case OFPT_ECHO_REQUEST:
790 min_size = sizeof(struct ofp_header);
791 handler = recv_echo_request;
792 break;
793 case OFPT_ECHO_REPLY:
794 return 0;
795 case OFPT_FEATURES_REQUEST:
796 min_size = sizeof(struct ofp_header);
797 handler = recv_features_request;
798 break;
799 case OFPT_SET_CONFIG:
800 min_size = sizeof(struct ofp_switch_config);
801 handler = recv_set_config;
802 break;
803 case OFPT_VENDOR:
804 min_size = sizeof(struct ofp_vendor_header);
805 handler = recv_vendor;
806 break;
807 default:
808 VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
809 send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
810 msg, length);
811 return -EINVAL;
812 }
813
814 /* Handle it. */
815 if (length < min_size) {
816 return -EFAULT;
817 }
818 return handler(xid, msg);
819 }
820
821 bool
822 mgmt_run(void)
823 {
824 int i;
825
826 if (!mgmt_rconn) {
827 return false;
828 }
829
830 need_reconfigure = false;
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 return need_reconfigure;
854 }
855
856 void
857 mgmt_wait(void)
858 {
859 if (!mgmt_rconn) {
860 return;
861 }
862
863 rconn_run_wait(mgmt_rconn);
864 rconn_recv_wait(mgmt_rconn);
865 }
866
867 static uint64_t
868 pick_fallback_mgmt_id(void)
869 {
870 uint8_t ea[ETH_ADDR_LEN];
871 eth_addr_random(ea);
872 ea[0] = 0x00; /* Set Nicira OUI. */
873 ea[1] = 0x23;
874 ea[2] = 0x20;
875 return eth_addr_to_uint64(ea);
876 }