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