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