ovn-northd: Ability to detach on Windows.
[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_br_int(struct ovsdb_idl *ovs_idl)
62 {
63     const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
64     if (!cfg) {
65         return NULL;
66     }
67
68     const char *br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
69     if (!br_int_name) {
70         br_int_name = DEFAULT_BRIDGE_NAME;
71     }
72
73     const struct ovsrec_bridge *br;
74     OVSREC_BRIDGE_FOR_EACH (br, ovs_idl) {
75         if (!strcmp(br->name, br_int_name)) {
76             return br;
77         }
78     }
79
80     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
81     VLOG_WARN_RL(&rl, "%s: integration bridge does not exist", br_int_name);
82     return NULL;
83 }
84
85 static const char *
86 get_chassis_id(const struct ovsdb_idl *ovs_idl)
87 {
88     const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
89     return cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
90 }
91
92 /* Retrieves the OVN Southbound remote location from the
93  * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
94  *
95  * XXX ovn-controller does not support this changing mid-run, but that should
96  * be addressed later. */
97 static char *
98 get_ovnsb_remote(struct ovsdb_idl *ovs_idl)
99 {
100     while (1) {
101         ovsdb_idl_run(ovs_idl);
102
103         const struct ovsrec_open_vswitch *cfg
104             = ovsrec_open_vswitch_first(ovs_idl);
105         if (cfg) {
106             const char *remote = smap_get(&cfg->external_ids, "ovn-remote");
107             if (remote) {
108                 return xstrdup(remote);
109             }
110         }
111
112         VLOG_INFO("OVN OVSDB remote not specified.  Waiting...");
113         ovsdb_idl_wait(ovs_idl);
114         poll_block();
115     }
116 }
117
118 int
119 main(int argc, char *argv[])
120 {
121     struct unixctl_server *unixctl;
122     bool exiting;
123     int retval;
124
125     ovs_cmdl_proctitle_init(argc, argv);
126     set_program_name(argv[0]);
127     service_start(&argc, &argv);
128     parse_options(argc, argv);
129     fatal_ignore_sigpipe();
130
131     daemonize_start();
132
133     retval = unixctl_server_create(NULL, &unixctl);
134     if (retval) {
135         exit(EXIT_FAILURE);
136     }
137     unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
138
139     daemonize_complete();
140
141     ovsrec_init();
142     sbrec_init();
143
144     ofctrl_init();
145     lflow_init();
146
147     /* Connect to OVS OVSDB instance.  We do not monitor all tables by
148      * default, so modules must register their interest explicitly.  */
149     struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
150         ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true));
151     ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_open_vswitch);
152     ovsdb_idl_add_column(ovs_idl_loop.idl,
153                          &ovsrec_open_vswitch_col_external_ids);
154     chassis_register_ovs_idl(ovs_idl_loop.idl);
155     encaps_register_ovs_idl(ovs_idl_loop.idl);
156     binding_register_ovs_idl(ovs_idl_loop.idl);
157     physical_register_ovs_idl(ovs_idl_loop.idl);
158     ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl);
159
160     /* Connect to OVN SB database. */
161     char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
162     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
163         ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
164     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
165
166     /* Main loop. */
167     exiting = false;
168     while (!exiting) {
169         struct controller_ctx ctx = {
170             .ovs_idl = ovs_idl_loop.idl,
171             .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
172             .ovnsb_idl = ovnsb_idl_loop.idl,
173             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
174         };
175
176         const struct ovsrec_bridge *br_int = get_br_int(ctx.ovs_idl);
177         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
178
179         if (chassis_id) {
180             chassis_run(&ctx, chassis_id);
181             encaps_run(&ctx, br_int, chassis_id);
182             binding_run(&ctx, br_int, chassis_id);
183         }
184
185         if (br_int) {
186             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
187
188             struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
189             lflow_run(&ctx, &flow_table);
190             if (chassis_id) {
191                 physical_run(&ctx, mff_ovn_geneve,
192                              br_int, chassis_id, &flow_table);
193             }
194             ofctrl_put(&flow_table);
195             hmap_destroy(&flow_table);
196         }
197
198         unixctl_server_run(unixctl);
199
200         unixctl_server_wait(unixctl);
201         if (exiting) {
202             poll_immediate_wake();
203         }
204
205         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
206         ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
207
208         if (br_int) {
209             ofctrl_wait();
210         }
211         poll_block();
212         if (should_service_stop()) {
213             exiting = true;
214         }
215     }
216
217     /* It's time to exit.  Clean up the databases. */
218     bool done = false;
219     while (!done) {
220         struct controller_ctx ctx = {
221             .ovs_idl = ovs_idl_loop.idl,
222             .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
223             .ovnsb_idl = ovnsb_idl_loop.idl,
224             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
225         };
226
227         const struct ovsrec_bridge *br_int = get_br_int(ctx.ovs_idl);
228         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
229
230         /* Run all of the cleanup functions, even if one of them returns false.
231          * We're done if all of them return true. */
232         done = binding_cleanup(&ctx, chassis_id);
233         done = chassis_cleanup(&ctx, chassis_id) && done;
234         done = encaps_cleanup(&ctx, br_int) && done;
235         if (done) {
236             poll_immediate_wake();
237         }
238
239         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
240         ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
241         poll_block();
242     }
243
244     unixctl_server_destroy(unixctl);
245     lflow_destroy();
246     ofctrl_destroy();
247
248     ovsdb_idl_loop_destroy(&ovs_idl_loop);
249     ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
250
251     free(ovnsb_remote);
252     free(ovs_remote);
253     service_stop();
254
255     exit(retval);
256 }
257
258 static void
259 parse_options(int argc, char *argv[])
260 {
261     enum {
262         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
263         VLOG_OPTION_ENUMS,
264         DAEMON_OPTION_ENUMS
265     };
266
267     static struct option long_options[] = {
268         {"help", no_argument, NULL, 'h'},
269         {"version", no_argument, NULL, 'V'},
270         VLOG_LONG_OPTIONS,
271         DAEMON_LONG_OPTIONS,
272         STREAM_SSL_LONG_OPTIONS,
273         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
274         {NULL, 0, NULL, 0}
275     };
276     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
277
278     for (;;) {
279         int c;
280
281         c = getopt_long(argc, argv, short_options, long_options, NULL);
282         if (c == -1) {
283             break;
284         }
285
286         switch (c) {
287         case 'h':
288             usage();
289
290         case 'V':
291             ovs_print_version(OFP13_VERSION, OFP13_VERSION);
292             exit(EXIT_SUCCESS);
293
294         VLOG_OPTION_HANDLERS
295         DAEMON_OPTION_HANDLERS
296         STREAM_SSL_OPTION_HANDLERS
297
298         case OPT_PEER_CA_CERT:
299             stream_ssl_set_peer_ca_cert_file(optarg);
300             break;
301
302         case '?':
303             exit(EXIT_FAILURE);
304
305         default:
306             abort();
307         }
308     }
309     free(short_options);
310
311     argc -= optind;
312     argv += optind;
313
314     if (argc == 0) {
315         ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
316     } else if (argc == 1) {
317         ovs_remote = xstrdup(argv[0]);
318     } else {
319         VLOG_FATAL("exactly zero or one non-option argument required; "
320                    "use --help for usage");
321     }
322 }
323
324 static void
325 usage(void)
326 {
327     printf("%s: OVN controller\n"
328            "usage %s [OPTIONS] [OVS-DATABASE]\n"
329            "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
330                program_name, program_name);
331     stream_usage("OVS-DATABASE", true, false, false);
332     daemon_usage();
333     vlog_usage();
334     printf("\nOther options:\n"
335            "  -h, --help              display this help message\n"
336            "  -V, --version           display version information\n");
337     exit(EXIT_SUCCESS);
338 }
339
340 static void
341 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
342              const char *argv[] OVS_UNUSED, void *exiting_)
343 {
344     bool *exiting = exiting_;
345     *exiting = true;
346
347     unixctl_command_reply(conn, NULL);
348 }