ovn-controller: Explicitly pass the flow table from function to function.
[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 "physical.h"
46 #include "pipeline.h"
47
48 VLOG_DEFINE_THIS_MODULE(main);
49
50 static unixctl_cb_func ovn_controller_exit;
51
52 #define DEFAULT_BRIDGE_NAME "br-int"
53
54 static void parse_options(int argc, char *argv[]);
55 OVS_NO_RETURN static void usage(void);
56
57 static char *ovs_remote;
58 static char *ovnsb_remote;
59
60
61 static void
62 get_initial_snapshot(struct ovsdb_idl *idl)
63 {
64     while (1) {
65         ovsdb_idl_run(idl);
66         if (ovsdb_idl_has_ever_connected(idl)) {
67             return;
68         }
69         ovsdb_idl_wait(idl);
70         poll_block();
71     }
72 }
73
74 static const struct ovsrec_bridge *
75 get_bridge(struct controller_ctx *ctx, const char *name)
76 {
77     const struct ovsrec_bridge *br;
78
79     OVSREC_BRIDGE_FOR_EACH(br, ctx->ovs_idl) {
80         if (!strcmp(br->name, name)) {
81             return br;
82         }
83     }
84
85     return NULL;
86 }
87
88 /* Retrieve the OVN integration bridge from the "external-ids:ovn-bridge"
89  * key, the remote location from the "external-ids:ovn-remote" key, and
90  * the chassis name from the "external-ids:system-id" key in the
91  * Open_vSwitch table of the OVS database instance.
92  *
93  * xxx ovn-controller does not support changing any of these mid-run,
94  * xxx but that should be addressed later. */
95 static void
96 get_core_config(struct controller_ctx *ctx)
97 {
98     while (1) {
99         ovsdb_idl_run(ctx->ovs_idl);
100
101         const struct ovsrec_open_vswitch *cfg;
102         cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
103         if (!cfg) {
104             VLOG_ERR("No Open_vSwitch row defined.");
105             ovsdb_idl_destroy(ctx->ovs_idl);
106             exit(EXIT_FAILURE);
107         }
108
109         const struct ovsrec_bridge *br_int;
110         const char *remote, *system_id, *br_int_name;
111
112         br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
113         if (!br_int_name) {
114             br_int_name = DEFAULT_BRIDGE_NAME;
115         }
116         ctx->br_int_name = xstrdup(br_int_name);
117
118         br_int = get_bridge(ctx, ctx->br_int_name);
119         if (!br_int) {
120             VLOG_INFO("Integration bridge '%s' does not exist.  Waiting...",
121                       ctx->br_int_name);
122             goto try_again;
123         }
124
125         remote = smap_get(&cfg->external_ids, "ovn-remote");
126         if (!remote) {
127             VLOG_INFO("OVN OVSDB remote not specified.  Waiting...");
128             goto try_again;
129         }
130
131         system_id = smap_get(&cfg->external_ids, "system-id");
132         if (!system_id) {
133             VLOG_INFO("system-id not specified.  Waiting...");
134             goto try_again;
135         }
136
137         ovnsb_remote = xstrdup(remote);
138         ctx->chassis_id = xstrdup(system_id);
139         return;
140
141 try_again:
142         ovsdb_idl_wait(ctx->ovs_idl);
143         poll_block();
144     }
145
146 }
147
148 struct idl_loop {
149     struct ovsdb_idl *idl;
150     unsigned int skip_seqno;
151
152     struct ovsdb_idl_txn *committing_txn;
153     unsigned int precommit_seqno;
154
155     struct ovsdb_idl_txn *open_txn;
156 };
157
158 #define IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) }
159
160 static void
161 idl_loop_destroy(struct idl_loop *loop)
162 {
163     if (loop) {
164         ovsdb_idl_destroy(loop->idl);
165     }
166 }
167
168 static struct ovsdb_idl_txn *
169 idl_loop_run(struct idl_loop *loop)
170 {
171     ovsdb_idl_run(loop->idl);
172     loop->open_txn = (loop->committing_txn
173                       || ovsdb_idl_get_seqno(loop->idl) == loop->skip_seqno
174                       ? NULL
175                       : ovsdb_idl_txn_create(loop->idl));
176     return loop->open_txn;
177 }
178
179 static void
180 idl_loop_commit_and_wait(struct idl_loop *loop)
181 {
182     if (loop->open_txn) {
183         loop->committing_txn = loop->open_txn;
184         loop->open_txn = NULL;
185
186         loop->precommit_seqno = ovsdb_idl_get_seqno(loop->idl);
187     }
188
189     struct ovsdb_idl_txn *txn = loop->committing_txn;
190     if (txn) {
191         enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
192         switch (status) {
193         case TXN_INCOMPLETE:
194             break;
195
196         case TXN_TRY_AGAIN:
197             loop->skip_seqno = loop->precommit_seqno;
198             if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
199                 poll_immediate_wake();
200             }
201             /* Fall through. */
202         case TXN_UNCHANGED:
203         case TXN_ABORTED:
204         case TXN_SUCCESS:
205         case TXN_NOT_LOCKED:
206         case TXN_ERROR:
207             ovsdb_idl_txn_destroy(txn);
208             loop->committing_txn = NULL;
209             break;
210
211         case TXN_UNCOMMITTED:
212             OVS_NOT_REACHED();
213
214         }
215     }
216
217     ovsdb_idl_wait(loop->idl);
218 }
219
220 int
221 main(int argc, char *argv[])
222 {
223     struct unixctl_server *unixctl;
224     struct controller_ctx ctx = { .chassis_id = NULL };
225     bool exiting;
226     int retval;
227
228     ovs_cmdl_proctitle_init(argc, argv);
229     set_program_name(argv[0]);
230     parse_options(argc, argv);
231     fatal_ignore_sigpipe();
232
233     daemonize_start();
234
235     retval = unixctl_server_create(NULL, &unixctl);
236     if (retval) {
237         exit(EXIT_FAILURE);
238     }
239     unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
240
241     daemonize_complete();
242
243     ovsrec_init();
244     sbrec_init();
245
246     ofctrl_init();
247
248     /* Connect to OVS OVSDB instance.  We do not monitor all tables by
249      * default, so modules must register their interest explicitly.  */
250     ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
251
252     /* Register interest in "external_ids" column in "Open_vSwitch" table,
253      * since we'll need to get the OVN OVSDB remote. */
254     ovsdb_idl_add_table(ctx.ovs_idl, &ovsrec_table_open_vswitch);
255     ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
256
257     chassis_init(&ctx);
258     binding_init(&ctx);
259     physical_init(&ctx);
260     pipeline_init();
261
262     get_initial_snapshot(ctx.ovs_idl);
263
264     get_core_config(&ctx);
265
266     ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
267                                      true, true);
268     get_initial_snapshot(ctx.ovnsb_idl);
269
270     struct idl_loop ovnsb_idl_loop = IDL_LOOP_INITIALIZER(ctx.ovnsb_idl);
271     struct idl_loop ovs_idl_loop = IDL_LOOP_INITIALIZER(ctx.ovs_idl);
272
273     /* Main loop. */
274     exiting = false;
275     while (!exiting) {
276         ctx.ovnsb_idl_txn = idl_loop_run(&ovnsb_idl_loop);
277         ctx.ovs_idl_txn = idl_loop_run(&ovs_idl_loop);
278
279         /* xxx If run into any surprising changes, we exit.  We should
280          * xxx handle this more gracefully. */
281         ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
282         if (!ctx.br_int) {
283             VLOG_ERR("Integration bridge '%s' disappeared",
284                      ctx.br_int_name);
285             retval = EXIT_FAILURE;
286             goto exit;
287         }
288
289         chassis_run(&ctx);
290         binding_run(&ctx);
291
292         struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
293         pipeline_run(&ctx, &flow_table);
294         physical_run(&ctx, &flow_table);
295         ofctrl_run(&ctx, &flow_table);
296         hmap_destroy(&flow_table);
297
298         unixctl_server_run(unixctl);
299
300         unixctl_server_wait(unixctl);
301         if (exiting) {
302             poll_immediate_wake();
303         }
304
305         idl_loop_commit_and_wait(&ovnsb_idl_loop);
306         idl_loop_commit_and_wait(&ovs_idl_loop);
307
308         ofctrl_wait();
309         poll_block();
310     }
311
312     /* It's time to exit.  Clean up the databases. */
313     bool done = false;
314     while (!done) {
315         ctx.ovnsb_idl_txn = idl_loop_run(&ovnsb_idl_loop);
316         ctx.ovs_idl_txn = idl_loop_run(&ovs_idl_loop);
317
318         /* xxx If run into any surprising changes, we exit.  We should
319          * xxx handle this more gracefully. */
320         ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
321         if (!ctx.br_int) {
322             VLOG_ERR("Integration bridge '%s' disappeared",
323                      ctx.br_int_name);
324             retval = EXIT_FAILURE;
325             goto exit;
326         }
327
328         /* Run both the binding and chassis cleanup, even if one of them
329          * returns false.  We're done if both return true. */
330         done = binding_cleanup(&ctx);
331         done = chassis_cleanup(&ctx) && done;
332         if (done) {
333             poll_immediate_wake();
334         }
335
336         idl_loop_commit_and_wait(&ovnsb_idl_loop);
337         idl_loop_commit_and_wait(&ovs_idl_loop);
338         poll_block();
339     }
340
341 exit:
342     unixctl_server_destroy(unixctl);
343     pipeline_destroy(&ctx);
344     ofctrl_destroy();
345
346     idl_loop_destroy(&ovs_idl_loop);
347     idl_loop_destroy(&ovnsb_idl_loop);
348
349     free(ctx.br_int_name);
350     free(ctx.chassis_id);
351     free(ovnsb_remote);
352     free(ovs_remote);
353
354     exit(retval);
355 }
356
357 static void
358 parse_options(int argc, char *argv[])
359 {
360     enum {
361         OPT_PEER_CA_CERT = UCHAR_MAX + 1,
362         VLOG_OPTION_ENUMS,
363         DAEMON_OPTION_ENUMS
364     };
365
366     static struct option long_options[] = {
367         {"help", no_argument, NULL, 'h'},
368         {"version", no_argument, NULL, 'V'},
369         VLOG_LONG_OPTIONS,
370         DAEMON_LONG_OPTIONS,
371         STREAM_SSL_LONG_OPTIONS,
372         {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
373         {NULL, 0, NULL, 0}
374     };
375     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
376
377     for (;;) {
378         int c;
379
380         c = getopt_long(argc, argv, short_options, long_options, NULL);
381         if (c == -1) {
382             break;
383         }
384
385         switch (c) {
386         case 'h':
387             usage();
388
389         case 'V':
390             ovs_print_version(OFP13_VERSION, OFP13_VERSION);
391             exit(EXIT_SUCCESS);
392
393         VLOG_OPTION_HANDLERS
394         DAEMON_OPTION_HANDLERS
395         STREAM_SSL_OPTION_HANDLERS
396
397         case OPT_PEER_CA_CERT:
398             stream_ssl_set_peer_ca_cert_file(optarg);
399             break;
400
401         case '?':
402             exit(EXIT_FAILURE);
403
404         default:
405             abort();
406         }
407     }
408     free(short_options);
409
410     argc -= optind;
411     argv += optind;
412
413     if (argc == 0) {
414         ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
415     } else if (argc == 1) {
416         ovs_remote = xstrdup(argv[0]);
417     } else {
418         VLOG_FATAL("exactly zero or one non-option argument required; "
419                    "use --help for usage");
420     }
421 }
422
423 static void
424 usage(void)
425 {
426     printf("%s: OVN controller\n"
427            "usage %s [OPTIONS] [OVS-DATABASE]\n"
428            "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
429                program_name, program_name);
430     stream_usage("OVS-DATABASE", true, false, false);
431     daemon_usage();
432     vlog_usage();
433     printf("\nOther options:\n"
434            "  -h, --help              display this help message\n"
435            "  -V, --version           display version information\n");
436     exit(EXIT_SUCCESS);
437 }
438
439 static void
440 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
441              const char *argv[] OVS_UNUSED, void *exiting_)
442 {
443     bool *exiting = exiting_;
444     *exiting = true;
445
446     unixctl_command_reply(conn, NULL);
447 }