smap: New macro SMAP_CONST1 for initializing immutable 1-member smaps.
[cascardo/ovs.git] / ovn / controller / ovn-controller.c
1 /* Copyright (c) 2015 Nicira, Inc.
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 "ovn-controller.h"
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "command-line.h"
27 #include "compiler.h"
28 #include "daemon.h"
29 #include "dirs.h"
30 #include "openvswitch/vconn.h"
31 #include "openvswitch/vlog.h"
32 #include "ovn/lib/ovn-sb-idl.h"
33 #include "poll-loop.h"
34 #include "fatal-signal.h"
35 #include "lib/vswitch-idl.h"
36 #include "smap.h"
37 #include "stream.h"
38 #include "stream-ssl.h"
39 #include "unixctl.h"
40 #include "util.h"
41
42 #include "ofctrl.h"
43 #include "binding.h"
44 #include "chassis.h"
45 #include "encaps.h"
46 #include "physical.h"
47 #include "lflow.h"
48
49 VLOG_DEFINE_THIS_MODULE(main);
50
51 static unixctl_cb_func ovn_controller_exit;
52
53 #define DEFAULT_BRIDGE_NAME "br-int"
54
55 static void parse_options(int argc, char *argv[]);
56 OVS_NO_RETURN static void usage(void);
57
58 static char *ovs_remote;
59
60 static const struct ovsrec_bridge *
61 get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)
62 {
63     const struct ovsrec_bridge *br;
64     OVSREC_BRIDGE_FOR_EACH (br, ovs_idl) {
65         if (!strcmp(br->name, br_name)) {
66             return br;
67         }
68     }
69     return NULL;
70 }
71
72 static const struct ovsrec_bridge *
73 create_br_int(struct controller_ctx *ctx,
74               const struct ovsrec_open_vswitch *cfg,
75               const char *bridge_name)
76 {
77     if (!ctx->ovs_idl_txn) {
78         return NULL;
79     }
80
81     ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
82             "ovn-controller: creating integration bridge '%s'", bridge_name);
83
84     struct ovsrec_interface *iface;
85     iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
86     ovsrec_interface_set_name(iface, bridge_name);
87     ovsrec_interface_set_type(iface, "internal");
88
89     struct ovsrec_port *port;
90     port = ovsrec_port_insert(ctx->ovs_idl_txn);
91     ovsrec_port_set_name(port, bridge_name);
92     ovsrec_port_set_interfaces(port, &iface, 1);
93
94     struct ovsrec_bridge *bridge;
95     bridge = ovsrec_bridge_insert(ctx->ovs_idl_txn);
96     ovsrec_bridge_set_name(bridge, bridge_name);
97     ovsrec_bridge_set_fail_mode(bridge, "secure");
98     const struct smap oc = SMAP_CONST1(&oc, "disable-in-band", "true");
99     ovsrec_bridge_set_other_config(bridge, &oc);
100     ovsrec_bridge_set_ports(bridge, &port, 1);
101
102     struct ovsrec_bridge **bridges;
103     size_t bytes = sizeof *bridges * cfg->n_bridges;
104     bridges = xmalloc(bytes + sizeof *bridges);
105     memcpy(bridges, cfg->bridges, bytes);
106     bridges[cfg->n_bridges] = bridge;
107     ovsrec_open_vswitch_verify_bridges(cfg);
108     ovsrec_open_vswitch_set_bridges(cfg, bridges, cfg->n_bridges + 1);
109
110     return bridge;
111 }
112
113 static const struct ovsrec_bridge *
114 get_br_int(struct controller_ctx *ctx)
115 {
116     const struct ovsrec_open_vswitch *cfg;
117     cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
118     if (!cfg) {
119         return NULL;
120     }
121
122     const char *br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
123     if (!br_int_name) {
124         br_int_name = DEFAULT_BRIDGE_NAME;
125     }
126
127     const struct ovsrec_bridge *br;
128     br = get_bridge(ctx->ovs_idl, br_int_name);
129     if (!br) {
130         return create_br_int(ctx, cfg, br_int_name);
131     }
132     return br;
133 }
134
135 static const char *
136 get_chassis_id(const struct ovsdb_idl *ovs_idl)
137 {
138     const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
139     return cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
140 }
141
142 static char *
143 patch_port_name(const struct ovsrec_bridge *b1, const struct ovsrec_bridge *b2)
144 {
145     return xasprintf("patch-%s-to-%s", b1->name, b2->name);
146 }
147
148 /*
149  * Return true if the port is a patch port from b1 to b2
150  */
151 static bool
152 match_patch_port(const struct ovsrec_port *port,
153                  const struct ovsrec_bridge *b1,
154                  const struct ovsrec_bridge *b2)
155 {
156     struct ovsrec_interface *iface;
157     size_t i;
158     char *peer_port_name;
159     bool res = false;
160
161     peer_port_name = patch_port_name(b2, b1);
162
163     for (i = 0; i < port->n_interfaces; i++) {
164         iface = port->interfaces[i];
165         if (strcmp(iface->type, "patch")) {
166             continue;
167         }
168         const char *peer;
169         peer = smap_get(&iface->options, "peer");
170         if (peer && !strcmp(peer, peer_port_name)) {
171             res = true;
172             break;
173         }
174     }
175
176     free(peer_port_name);
177
178     return res;
179 }
180
181 static void
182 create_patch_port(struct controller_ctx *ctx,
183                   const char *network,
184                   const struct ovsrec_bridge *b1,
185                   const struct ovsrec_bridge *b2)
186 {
187     if (!ctx->ovs_idl_txn) {
188         return;
189     }
190
191     char *port_name = patch_port_name(b1, b2);
192     char *peer_port_name = patch_port_name(b2, b1);
193
194     ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
195             "ovn-controller: creating patch port '%s' from '%s' to '%s'",
196             port_name, b1->name, b2->name);
197
198     struct ovsrec_interface *iface;
199     iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
200     ovsrec_interface_set_name(iface, port_name);
201     ovsrec_interface_set_type(iface, "patch");
202     const struct smap options = SMAP_CONST1(&options, "peer", peer_port_name);
203     ovsrec_interface_set_options(iface, &options);
204
205     struct ovsrec_port *port;
206     port = ovsrec_port_insert(ctx->ovs_idl_txn);
207     ovsrec_port_set_name(port, port_name);
208     ovsrec_port_set_interfaces(port, &iface, 1);
209     const struct smap ids = SMAP_CONST1(&ids, "ovn-patch-port", network);
210     ovsrec_port_set_external_ids(port, &ids);
211
212     struct ovsrec_port **ports;
213     ports = xmalloc(sizeof *ports * (b1->n_ports + 1));
214     memcpy(ports, b1->ports, sizeof *ports * b1->n_ports);
215     ports[b1->n_ports] = port;
216     ovsrec_bridge_verify_ports(b1);
217     ovsrec_bridge_set_ports(b1, ports, b1->n_ports + 1);
218
219     free(ports);
220     free(port_name);
221     free(peer_port_name);
222 }
223
224 static void
225 create_patch_ports(struct controller_ctx *ctx,
226                    const char *network,
227                    struct shash *existing_ports,
228                    const struct ovsrec_bridge *b1,
229                    const struct ovsrec_bridge *b2)
230 {
231     size_t i;
232
233     for (i = 0; i < b1->n_ports; i++) {
234         if (match_patch_port(b1->ports[i], b1, b2)) {
235             /* Patch port already exists on b1 */
236             shash_find_and_delete(existing_ports, b1->ports[i]->name);
237             break;
238         }
239     }
240     if (i == b1->n_ports) {
241         create_patch_port(ctx, network, b1, b2);
242     }
243 }
244
245 static void
246 init_existing_ports(struct controller_ctx *ctx,
247                     struct shash *existing_ports)
248 {
249     const struct ovsrec_port *port;
250
251     OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
252         if (smap_get(&port->external_ids, "ovn-patch-port")) {
253             shash_add(existing_ports, port->name, port);
254         }
255     }
256 }
257
258 static void
259 remove_port(struct controller_ctx *ctx,
260             const struct ovsrec_port *port)
261 {
262     const struct ovsrec_bridge *bridge;
263
264     /* We know the port we want to delete, but we have to find the bridge its on
265      * to do so.  Note this only runs on a config change that should be pretty
266      * rare. */
267     OVSREC_BRIDGE_FOR_EACH (bridge, ctx->ovs_idl) {
268         size_t i;
269         for (i = 0; i < bridge->n_ports; i++) {
270             if (bridge->ports[i] != port) {
271                 continue;
272             }
273             struct ovsrec_port **new_ports;
274             new_ports = xmemdup(bridge->ports,
275                     sizeof *new_ports * (bridge->n_ports - 1));
276             if (i != bridge->n_ports - 1) {
277                 /* Removed port was not last */
278                 new_ports[i] = bridge->ports[bridge->n_ports - 1];
279             }
280             ovsrec_bridge_verify_ports(bridge);
281             ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1);
282             free(new_ports);
283             ovsrec_port_delete(port);
284             return;
285         }
286     }
287 }
288
289 static void
290 parse_bridge_mappings(struct controller_ctx *ctx,
291                       const struct ovsrec_bridge *br_int,
292                       const char *mappings_cfg)
293 {
294     struct shash existing_ports = SHASH_INITIALIZER(&existing_ports);
295     init_existing_ports(ctx, &existing_ports);
296
297     char *cur, *next, *start;
298     next = start = xstrdup(mappings_cfg);
299     while ((cur = strsep(&next, ",")) && *cur) {
300         char *network, *bridge = cur;
301         const struct ovsrec_bridge *ovs_bridge;
302
303         network = strsep(&bridge, ":");
304         if (!bridge || !*network || !*bridge) {
305             VLOG_ERR("Invalid ovn-bridge-mappings configuration: '%s'",
306                     mappings_cfg);
307             break;
308         }
309
310         ovs_bridge = get_bridge(ctx->ovs_idl, bridge);
311         if (!ovs_bridge) {
312             VLOG_WARN("Bridge '%s' not found for network '%s'",
313                     bridge, network);
314             continue;
315         }
316
317         create_patch_ports(ctx, network, &existing_ports, br_int, ovs_bridge);
318         create_patch_ports(ctx, network, &existing_ports, ovs_bridge, br_int);
319     }
320     free(start);
321
322     /* Any ports left in existing_ports are related to configuration that has
323      * been removed, so we should delete the ports now. */
324     struct shash_node *port_node, *port_next_node;
325     SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) {
326         struct ovsrec_port *port = port_node->data;
327         shash_delete(&existing_ports, port_node);
328         remove_port(ctx, port);
329     }
330     shash_destroy(&existing_ports);
331 }
332
333 static void
334 init_bridge_mappings(struct controller_ctx *ctx,
335                      const struct ovsrec_bridge *br_int)
336 {
337     const char *mappings_cfg = "";
338     const struct ovsrec_open_vswitch *cfg;
339
340     cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
341     if (cfg) {
342         mappings_cfg = smap_get(&cfg->external_ids, "ovn-bridge-mappings");
343         if (!mappings_cfg) {
344             mappings_cfg = "";
345         }
346     }
347     parse_bridge_mappings(ctx, br_int, mappings_cfg);
348 }
349
350 /* Retrieves the OVN Southbound remote location from the
351  * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
352  *
353  * XXX ovn-controller does not support this changing mid-run, but that should
354  * be addressed later. */
355 static char *
356 get_ovnsb_remote(struct ovsdb_idl *ovs_idl)
357 {
358     while (1) {
359         ovsdb_idl_run(ovs_idl);
360
361         const struct ovsrec_open_vswitch *cfg
362             = ovsrec_open_vswitch_first(ovs_idl);
363         if (cfg) {
364             const char *remote = smap_get(&cfg->external_ids, "ovn-remote");
365             if (remote) {
366                 return xstrdup(remote);
367             }
368         }
369
370         VLOG_INFO("OVN OVSDB remote not specified.  Waiting...");
371         ovsdb_idl_wait(ovs_idl);
372         poll_block();
373     }
374 }
375
376 int
377 main(int argc, char *argv[])
378 {
379     struct unixctl_server *unixctl;
380     bool exiting;
381     int retval;
382
383     ovs_cmdl_proctitle_init(argc, argv);
384     set_program_name(argv[0]);
385     service_start(&argc, &argv);
386     parse_options(argc, argv);
387     fatal_ignore_sigpipe();
388
389     daemonize_start();
390
391     retval = unixctl_server_create(NULL, &unixctl);
392     if (retval) {
393         exit(EXIT_FAILURE);
394     }
395     unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
396
397     daemonize_complete();
398
399     ovsrec_init();
400     sbrec_init();
401
402     ofctrl_init();
403     lflow_init();
404
405     /* Connect to OVS OVSDB instance.  We do not monitor all tables by
406      * default, so modules must register their interest explicitly.  */
407     struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
408         ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true));
409     ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_open_vswitch);
410     ovsdb_idl_add_column(ovs_idl_loop.idl,
411                          &ovsrec_open_vswitch_col_external_ids);
412     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_open_vswitch_col_bridges);
413     ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_interface);
414     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_name);
415     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_type);
416     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_options);
417     ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_port);
418     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_name);
419     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_interfaces);
420     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_external_ids);
421     ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_bridge);
422     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_ports);
423     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_name);
424     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_fail_mode);
425     ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_other_config);
426     chassis_register_ovs_idl(ovs_idl_loop.idl);
427     encaps_register_ovs_idl(ovs_idl_loop.idl);
428     binding_register_ovs_idl(ovs_idl_loop.idl);
429     physical_register_ovs_idl(ovs_idl_loop.idl);
430     ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl);
431
432     /* Connect to OVN SB database. */
433     char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
434     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
435         ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
436     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
437
438     /* Main loop. */
439     exiting = false;
440     while (!exiting) {
441         struct controller_ctx ctx = {
442             .ovs_idl = ovs_idl_loop.idl,
443             .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
444             .ovnsb_idl = ovnsb_idl_loop.idl,
445             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
446         };
447
448         const struct ovsrec_bridge *br_int = get_br_int(&ctx);
449         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
450
451         /* Map bridges to local nets from ovn-bridge-mappings */
452         if (br_int) {
453             init_bridge_mappings(&ctx, br_int);
454         }
455
456         if (chassis_id) {
457             chassis_run(&ctx, chassis_id);
458             encaps_run(&ctx, br_int, chassis_id);
459             binding_run(&ctx, br_int, chassis_id);
460         }
461
462         if (br_int) {
463             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
464
465             struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
466             lflow_run(&ctx, &flow_table);
467             if (chassis_id) {
468                 physical_run(&ctx, mff_ovn_geneve,
469                              br_int, chassis_id, &flow_table);
470             }
471             ofctrl_put(&flow_table);
472             hmap_destroy(&flow_table);
473         }
474
475         unixctl_server_run(unixctl);
476
477         unixctl_server_wait(unixctl);
478         if (exiting) {
479             poll_immediate_wake();
480         }
481
482         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
483         ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
484
485         if (br_int) {
486             ofctrl_wait();
487         }
488         poll_block();
489         if (should_service_stop()) {
490             exiting = true;
491         }
492     }
493
494     /* It's time to exit.  Clean up the databases. */
495     bool done = false;
496     while (!done) {
497         struct controller_ctx ctx = {
498             .ovs_idl = ovs_idl_loop.idl,
499             .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
500             .ovnsb_idl = ovnsb_idl_loop.idl,
501             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
502         };
503
504         const struct ovsrec_bridge *br_int = get_br_int(&ctx);
505         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
506
507         /* Run all of the cleanup functions, even if one of them returns false.
508          * We're done if all of them return true. */
509         done = binding_cleanup(&ctx, chassis_id);
510         done = chassis_cleanup(&ctx, chassis_id) && done;
511         done = encaps_cleanup(&ctx, br_int) && done;
512         if (done) {
513             poll_immediate_wake();
514         }
515
516         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
517         ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
518         poll_block();
519     }
520
521     unixctl_server_destroy(unixctl);
522     lflow_destroy();
523     ofctrl_destroy();
524
525     ovsdb_idl_loop_destroy(&ovs_idl_loop);
526     ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
527
528     free(ovnsb_remote);
529     free(ovs_remote);
530     service_stop();
531
532     exit(retval);
533 }
534
535 static void
536 parse_options(int argc, char *argv[])
537 {
538     enum {
539         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
540         OPT_BOOTSTRAP_CA_CERT,
541         VLOG_OPTION_ENUMS,
542         DAEMON_OPTION_ENUMS
543     };
544
545     static struct option long_options[] = {
546         {"help", no_argument, NULL, 'h'},
547         {"version", no_argument, NULL, 'V'},
548         VLOG_LONG_OPTIONS,
549         DAEMON_LONG_OPTIONS,
550         STREAM_SSL_LONG_OPTIONS,
551         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
552         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
553         {NULL, 0, NULL, 0}
554     };
555     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
556
557     for (;;) {
558         int c;
559
560         c = getopt_long(argc, argv, short_options, long_options, NULL);
561         if (c == -1) {
562             break;
563         }
564
565         switch (c) {
566         case 'h':
567             usage();
568
569         case 'V':
570             ovs_print_version(OFP13_VERSION, OFP13_VERSION);
571             exit(EXIT_SUCCESS);
572
573         VLOG_OPTION_HANDLERS
574         DAEMON_OPTION_HANDLERS
575         STREAM_SSL_OPTION_HANDLERS
576
577         case OPT_PEER_CA_CERT:
578             stream_ssl_set_peer_ca_cert_file(optarg);
579             break;
580
581         case OPT_BOOTSTRAP_CA_CERT:
582             stream_ssl_set_ca_cert_file(optarg, true);
583             break;
584
585         case '?':
586             exit(EXIT_FAILURE);
587
588         default:
589             abort();
590         }
591     }
592     free(short_options);
593
594     argc -= optind;
595     argv += optind;
596
597     if (argc == 0) {
598         ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
599     } else if (argc == 1) {
600         ovs_remote = xstrdup(argv[0]);
601     } else {
602         VLOG_FATAL("exactly zero or one non-option argument required; "
603                    "use --help for usage");
604     }
605 }
606
607 static void
608 usage(void)
609 {
610     printf("%s: OVN controller\n"
611            "usage %s [OPTIONS] [OVS-DATABASE]\n"
612            "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
613                program_name, program_name);
614     stream_usage("OVS-DATABASE", true, false, false);
615     daemon_usage();
616     vlog_usage();
617     printf("\nOther options:\n"
618            "  -h, --help              display this help message\n"
619            "  -V, --version           display version information\n");
620     exit(EXIT_SUCCESS);
621 }
622
623 static void
624 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
625              const char *argv[] OVS_UNUSED, void *exiting_)
626 {
627     bool *exiting = exiting_;
628     *exiting = true;
629
630     unixctl_command_reply(conn, NULL);
631 }