]> git.proxmox.com Git - ovs.git/blame - ovn/controller/ovn-controller.c
ofproto: Consider datapath_type when looking for internal ports.
[ovs.git] / ovn / controller / ovn-controller.c
CommitLineData
6335d074 1/* Copyright (c) 2015, 2016 Nicira, Inc.
717c7fc5
JP
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
bce7cf45
BP
26#include "binding.h"
27#include "chassis.h"
717c7fc5
JP
28#include "command-line.h"
29#include "compiler.h"
30#include "daemon.h"
31#include "dirs.h"
3e8a2ad1 32#include "openvswitch/dynamic-string.h"
bce7cf45
BP
33#include "encaps.h"
34#include "fatal-signal.h"
ee89ea7b 35#include "openvswitch/hmap.h"
bce7cf45
BP
36#include "lflow.h"
37#include "lib/vswitch-idl.h"
38#include "lport.h"
39#include "ofctrl.h"
717c7fc5
JP
40#include "openvswitch/vconn.h"
41#include "openvswitch/vlog.h"
8b2ed684 42#include "ovn/actions.h"
e3df8838 43#include "ovn/lib/ovn-sb-idl.h"
3bd4ae23 44#include "ovn/lib/ovn-util.h"
bce7cf45
BP
45#include "patch.h"
46#include "physical.h"
47#include "pinctrl.h"
717c7fc5 48#include "poll-loop.h"
064d7f84
BW
49#include "lib/bitmap.h"
50#include "lib/hash.h"
717c7fc5 51#include "smap.h"
a478c4ef 52#include "sset.h"
717c7fc5 53#include "stream-ssl.h"
bce7cf45 54#include "stream.h"
717c7fc5
JP
55#include "unixctl.h"
56#include "util.h"
57
717c7fc5
JP
58VLOG_DEFINE_THIS_MODULE(main);
59
60static unixctl_cb_func ovn_controller_exit;
78aab811 61static unixctl_cb_func ct_zone_list;
717c7fc5 62
c758b109 63#define DEFAULT_BRIDGE_NAME "br-int"
715038b6 64#define DEFAULT_PROBE_INTERVAL_MSEC 5000
c758b109 65
715038b6 66static void update_probe_interval(struct controller_ctx *);
717c7fc5
JP
67static void parse_options(int argc, char *argv[]);
68OVS_NO_RETURN static void usage(void);
69
70static char *ovs_remote;
717c7fc5 71
e4426e34
BP
72struct local_datapath *
73get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
74{
75 struct hmap_node *node = hmap_first_with_hash(local_datapaths, tunnel_key);
76 return (node
77 ? CONTAINER_OF(node, struct local_datapath, hmap_node)
78 : NULL);
79}
80
81struct patched_datapath *
82get_patched_datapath(const struct hmap *patched_datapaths, uint32_t tunnel_key)
83{
84 struct hmap_node *node = hmap_first_with_hash(patched_datapaths,
85 tunnel_key);
86 return (node
87 ? CONTAINER_OF(node, struct patched_datapath, hmap_node)
88 : NULL);
89}
90
2ddf7558
BP
91const struct sbrec_chassis *
92get_chassis(struct ovsdb_idl *ovnsb_idl, const char *chassis_id)
93{
94 const struct sbrec_chassis *chassis_rec;
95
96 SBREC_CHASSIS_FOR_EACH(chassis_rec, ovnsb_idl) {
97 if (!strcmp(chassis_rec->name, chassis_id)) {
98 break;
99 }
100 }
101
102 return chassis_rec;
103}
104
bf388125
JP
105uint32_t
106get_tunnel_type(const char *name)
107{
108 if (!strcmp(name, "geneve")) {
109 return GENEVE;
110 } else if (!strcmp(name, "stt")) {
111 return STT;
112 } else if (!strcmp(name, "vxlan")) {
113 return VXLAN;
114 }
115
116 return 0;
117}
118
a1d210a6 119const struct ovsrec_bridge *
7e0d3eed
RB
120get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)
121{
122 const struct ovsrec_bridge *br;
123 OVSREC_BRIDGE_FOR_EACH (br, ovs_idl) {
124 if (!strcmp(br->name, br_name)) {
125 return br;
126 }
127 }
128 return NULL;
129}
130
c758b109 131static const struct ovsrec_bridge *
e43fc07c
RB
132create_br_int(struct controller_ctx *ctx,
133 const struct ovsrec_open_vswitch *cfg,
134 const char *bridge_name)
c758b109 135{
e43fc07c
RB
136 if (!ctx->ovs_idl_txn) {
137 return NULL;
138 }
139
140 ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
141 "ovn-controller: creating integration bridge '%s'", bridge_name);
142
143 struct ovsrec_interface *iface;
144 iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
145 ovsrec_interface_set_name(iface, bridge_name);
146 ovsrec_interface_set_type(iface, "internal");
147
148 struct ovsrec_port *port;
149 port = ovsrec_port_insert(ctx->ovs_idl_txn);
150 ovsrec_port_set_name(port, bridge_name);
151 ovsrec_port_set_interfaces(port, &iface, 1);
152
153 struct ovsrec_bridge *bridge;
154 bridge = ovsrec_bridge_insert(ctx->ovs_idl_txn);
155 ovsrec_bridge_set_name(bridge, bridge_name);
156 ovsrec_bridge_set_fail_mode(bridge, "secure");
aaf881c6
BP
157 const struct smap oc = SMAP_CONST1(&oc, "disable-in-band", "true");
158 ovsrec_bridge_set_other_config(bridge, &oc);
e43fc07c
RB
159 ovsrec_bridge_set_ports(bridge, &port, 1);
160
161 struct ovsrec_bridge **bridges;
162 size_t bytes = sizeof *bridges * cfg->n_bridges;
163 bridges = xmalloc(bytes + sizeof *bridges);
164 memcpy(bridges, cfg->bridges, bytes);
165 bridges[cfg->n_bridges] = bridge;
166 ovsrec_open_vswitch_verify_bridges(cfg);
167 ovsrec_open_vswitch_set_bridges(cfg, bridges, cfg->n_bridges + 1);
168
169 return bridge;
170}
171
172static const struct ovsrec_bridge *
173get_br_int(struct controller_ctx *ctx)
174{
175 const struct ovsrec_open_vswitch *cfg;
176 cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
9e8fa2b6
BP
177 if (!cfg) {
178 return NULL;
179 }
c758b109 180
f99f67bd
BP
181 const char *br_int_name = smap_get_def(&cfg->external_ids, "ovn-bridge",
182 DEFAULT_BRIDGE_NAME);
9e8fa2b6
BP
183
184 const struct ovsrec_bridge *br;
e43fc07c
RB
185 br = get_bridge(ctx->ovs_idl, br_int_name);
186 if (!br) {
187 return create_br_int(ctx, cfg, br_int_name);
c758b109 188 }
e43fc07c 189 return br;
c758b109
JP
190}
191
30a4256f
BP
192static const char *
193get_chassis_id(const struct ovsdb_idl *ovs_idl)
194{
195 const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
14e2ba58
RB
196 const char *chassis_id = cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
197
198 if (!chassis_id) {
199 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
200 VLOG_WARN_RL(&rl, "'system-id' in Open_vSwitch database is missing.");
201 }
202
203 return chassis_id;
30a4256f
BP
204}
205
9e8fa2b6
BP
206/* Retrieves the OVN Southbound remote location from the
207 * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
ba88f959 208 *
9e8fa2b6
BP
209 * XXX ovn-controller does not support this changing mid-run, but that should
210 * be addressed later. */
211static char *
212get_ovnsb_remote(struct ovsdb_idl *ovs_idl)
717c7fc5 213{
9326534c 214 while (1) {
9e8fa2b6
BP
215 ovsdb_idl_run(ovs_idl);
216
217 const struct ovsrec_open_vswitch *cfg
218 = ovsrec_open_vswitch_first(ovs_idl);
219 if (cfg) {
220 const char *remote = smap_get(&cfg->external_ids, "ovn-remote");
221 if (remote) {
222 return xstrdup(remote);
223 }
717c7fc5
JP
224 }
225
9e8fa2b6
BP
226 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
227 ovsdb_idl_wait(ovs_idl);
717c7fc5
JP
228 poll_block();
229 }
717c7fc5
JP
230}
231
a478c4ef 232static void
3bd4ae23
GS
233update_ct_zones(struct sset *lports, struct hmap *patched_datapaths,
234 struct simap *ct_zones, unsigned long *ct_zone_bitmap)
a478c4ef
GS
235{
236 struct simap_node *ct_zone, *ct_zone_next;
a478c4ef 237 int scan_start = 1;
3bd4ae23
GS
238 struct patched_datapath *pd;
239 const char *user;
240 struct sset all_users = SSET_INITIALIZER(&all_users);
a478c4ef 241
3bd4ae23
GS
242 SSET_FOR_EACH(user, lports) {
243 sset_add(&all_users, user);
244 }
245
246 /* Local patched datapath (gateway routers) need zones assigned. */
247 HMAP_FOR_EACH(pd, hmap_node, patched_datapaths) {
248 if (!pd->local) {
249 continue;
250 }
a478c4ef 251
34114cf8
GS
252 char *dnat = alloc_nat_zone_key(pd->key, "dnat");
253 char *snat = alloc_nat_zone_key(pd->key, "snat");
3bd4ae23
GS
254 sset_add(&all_users, dnat);
255 sset_add(&all_users, snat);
256 free(dnat);
257 free(snat);
258 }
259
260 /* Delete zones that do not exist in above sset. */
a478c4ef 261 SIMAP_FOR_EACH_SAFE(ct_zone, ct_zone_next, ct_zones) {
3bd4ae23 262 if (!sset_contains(&all_users, ct_zone->name)) {
a478c4ef
GS
263 bitmap_set0(ct_zone_bitmap, ct_zone->data);
264 simap_delete(ct_zones, ct_zone);
265 }
266 }
267
3bd4ae23
GS
268 /* xxx This is wasteful to assign a zone to each port--even if no
269 * xxx security policy is applied. */
270
271 /* Assign a unique zone id for each logical port and two zones
272 * to a gateway router. */
273 SSET_FOR_EACH(user, &all_users) {
a478c4ef
GS
274 size_t zone;
275
3bd4ae23 276 if (simap_contains(ct_zones, user)) {
a478c4ef
GS
277 continue;
278 }
279
280 /* We assume that there are 64K zones and that we own them all. */
281 zone = bitmap_scan(ct_zone_bitmap, 0, scan_start, MAX_CT_ZONES + 1);
282 if (zone == MAX_CT_ZONES + 1) {
283 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
284 VLOG_WARN_RL(&rl, "exhausted all ct zones");
285 return;
286 }
287 scan_start = zone + 1;
288
289 bitmap_set1(ct_zone_bitmap, zone);
3bd4ae23 290 simap_put(ct_zones, user, zone);
a478c4ef
GS
291
292 /* xxx We should erase any old entries for this
293 * xxx zone, but we need a generic interface to the conntrack
294 * xxx table. */
295 }
3bd4ae23
GS
296
297 sset_destroy(&all_users);
a478c4ef
GS
298}
299
fa183acc
BP
300static int64_t
301get_nb_cfg(struct ovsdb_idl *idl)
302{
303 const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl);
304 return sb ? sb->nb_cfg : 0;
305}
306
263064ae
RM
307/* Contains "struct local_datapath" nodes whose hash values are the
308 * tunnel_key of datapaths with at least one local port binding. */
309static struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
310static struct hmap patched_datapaths = HMAP_INITIALIZER(&patched_datapaths);
311
4470328b
RM
312static struct lport_index lports;
313static struct mcgroup_index mcgroups;
314
c5f346a5
BS
315/* Contains the names of all logical ports currently bound to the chassis
316 * managed by this instance of ovn-controller. The contents are managed
317 * in binding.c, but consumed elsewhere. */
318static struct sset all_lports = SSET_INITIALIZER(&all_lports);
319
717c7fc5
JP
320int
321main(int argc, char *argv[])
322{
323 struct unixctl_server *unixctl;
717c7fc5
JP
324 bool exiting;
325 int retval;
326
327 ovs_cmdl_proctitle_init(argc, argv);
328 set_program_name(argv[0]);
485f0696 329 service_start(&argc, &argv);
717c7fc5
JP
330 parse_options(argc, argv);
331 fatal_ignore_sigpipe();
332
e91b927d 333 daemonize_start(false);
717c7fc5
JP
334
335 retval = unixctl_server_create(NULL, &unixctl);
336 if (retval) {
337 exit(EXIT_FAILURE);
338 }
339 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
340
467085fd
GS
341 /* Initialize group ids for loadbalancing. */
342 struct group_table group_table;
343 group_table.group_ids = bitmap_allocate(MAX_OVN_GROUPS);
344 bitmap_set1(group_table.group_ids, 0); /* Group id 0 is invalid. */
345 hmap_init(&group_table.desired_groups);
346 hmap_init(&group_table.existing_groups);
347
717c7fc5
JP
348 daemonize_complete();
349
350 ovsrec_init();
351 sbrec_init();
352
b4e87a48 353 ofctrl_init();
27732ac4 354 pinctrl_init();
48605550 355 lflow_init();
b4e87a48 356
4470328b
RM
357 lport_index_init(&lports);
358 mcgroup_index_init(&mcgroups);
359
717c7fc5
JP
360 /* Connect to OVS OVSDB instance. We do not monitor all tables by
361 * default, so modules must register their interest explicitly. */
a548a764 362 struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
710164bc
BP
363 ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true));
364 ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_open_vswitch);
365 ovsdb_idl_add_column(ovs_idl_loop.idl,
366 &ovsrec_open_vswitch_col_external_ids);
e43fc07c 367 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_open_vswitch_col_bridges);
7e0d3eed
RB
368 ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_interface);
369 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_name);
370 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_type);
371 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_options);
372 ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_port);
373 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_name);
374 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_interfaces);
375 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_port_col_external_ids);
376 ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_bridge);
377 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_ports);
e43fc07c
RB
378 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_name);
379 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_fail_mode);
380 ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_bridge_col_other_config);
710164bc
BP
381 chassis_register_ovs_idl(ovs_idl_loop.idl);
382 encaps_register_ovs_idl(ovs_idl_loop.idl);
383 binding_register_ovs_idl(ovs_idl_loop.idl);
384 physical_register_ovs_idl(ovs_idl_loop.idl);
a660eac8 385 ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl);
710164bc
BP
386
387 /* Connect to OVN SB database. */
388 char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
a548a764 389 struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
710164bc 390 ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
fa183acc 391 ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg);
1d45d5a9
RM
392
393 /* Track the southbound idl. */
394 ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
395
a660eac8 396 ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
f1fd7657 397
78aab811
JP
398 /* Initialize connection tracking zones. */
399 struct simap ct_zones = SIMAP_INITIALIZER(&ct_zones);
400 unsigned long ct_zone_bitmap[BITMAP_N_LONGS(MAX_CT_ZONES)];
9275d010 401 memset(ct_zone_bitmap, 0, sizeof ct_zone_bitmap);
78aab811
JP
402 bitmap_set1(ct_zone_bitmap, 0); /* Zone 0 is reserved. */
403 unixctl_command_register("ct-zone-list", "", 0, 0,
404 ct_zone_list, &ct_zones);
405
f1fd7657 406 /* Main loop. */
717c7fc5
JP
407 exiting = false;
408 while (!exiting) {
1b62572d
RM
409 /* Check OVN SB database. */
410 char *new_ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
411 if (strcmp(ovnsb_remote, new_ovnsb_remote)) {
412 free(ovnsb_remote);
413 ovnsb_remote = new_ovnsb_remote;
414 ovsdb_idl_set_remote(ovnsb_idl_loop.idl, ovnsb_remote, true);
263064ae 415 binding_reset_processing();
4470328b
RM
416 lport_index_clear(&lports);
417 mcgroup_index_clear(&mcgroups);
1b62572d
RM
418 } else {
419 free(new_ovnsb_remote);
420 }
421
710164bc
BP
422 struct controller_ctx ctx = {
423 .ovs_idl = ovs_idl_loop.idl,
a548a764 424 .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
710164bc 425 .ovnsb_idl = ovnsb_idl_loop.idl,
a548a764 426 .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
710164bc 427 };
717c7fc5 428
715038b6
NG
429 update_probe_interval(&ctx);
430
e43fc07c 431 const struct ovsrec_bridge *br_int = get_br_int(&ctx);
30a4256f 432 const char *chassis_id = get_chassis_id(ctx.ovs_idl);
c758b109 433
fa183acc 434 const struct sbrec_chassis *chassis = NULL;
30a4256f 435 if (chassis_id) {
fa183acc 436 chassis = chassis_run(&ctx, chassis_id);
30a4256f 437 encaps_run(&ctx, br_int, chassis_id);
c5f346a5
BS
438 binding_run(&ctx, br_int, chassis_id, &local_datapaths,
439 &all_lports);
30a4256f 440 }
761fd08f 441
c1645003
GS
442 if (br_int && chassis_id) {
443 patch_run(&ctx, br_int, chassis_id, &local_datapaths,
444 &patched_datapaths);
e90aeb57 445
4470328b
RM
446 lport_index_fill(&lports, ctx.ovnsb_idl);
447 mcgroup_index_fill(&mcgroups, ctx.ovnsb_idl);
bce7cf45 448
5868eb24 449 enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
1b05a9d3 450
0ee8aaf6 451 pinctrl_run(&ctx, &lports, br_int, chassis_id, &local_datapaths);
3bd4ae23
GS
452 update_ct_zones(&all_lports, &patched_datapaths, &ct_zones,
453 ct_zone_bitmap);
27732ac4 454
bce7cf45 455 lflow_run(&ctx, &lports, &mcgroups, &local_datapaths,
fdbdb595 456 &patched_datapaths, &group_table, &ct_zones);
2a368016 457
458 physical_run(&ctx, mff_ovn_geneve,
459 br_int, chassis_id, &ct_zones,
460 &local_datapaths, &patched_datapaths);
461
fa183acc
BP
462 ofctrl_put(&group_table, get_nb_cfg(ctx.ovnsb_idl));
463 if (ctx.ovnsb_idl_txn) {
464 int64_t cur_cfg = ofctrl_get_cur_cfg();
465 if (cur_cfg && cur_cfg != chassis->nb_cfg) {
466 sbrec_chassis_set_nb_cfg(chassis, cur_cfg);
467 }
468 }
37c7a694 469 }
761fd08f 470
717c7fc5
JP
471 unixctl_server_run(unixctl);
472
473 unixctl_server_wait(unixctl);
474 if (exiting) {
475 poll_immediate_wake();
476 }
477
37c7a694
BP
478 if (br_int) {
479 ofctrl_wait();
0bac7164 480 pinctrl_wait(&ctx);
37c7a694 481 }
0bac7164
BP
482 ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
483 ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
1d45d5a9 484 ovsdb_idl_track_clear(ovnsb_idl_loop.idl);
717c7fc5 485 poll_block();
485f0696
GS
486 if (should_service_stop()) {
487 exiting = true;
488 }
717c7fc5
JP
489 }
490
f1fd7657
BP
491 /* It's time to exit. Clean up the databases. */
492 bool done = false;
493 while (!done) {
710164bc
BP
494 struct controller_ctx ctx = {
495 .ovs_idl = ovs_idl_loop.idl,
a548a764 496 .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
710164bc 497 .ovnsb_idl = ovnsb_idl_loop.idl,
a548a764 498 .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
710164bc 499 };
f1fd7657 500
e43fc07c 501 const struct ovsrec_bridge *br_int = get_br_int(&ctx);
30a4256f 502 const char *chassis_id = get_chassis_id(ctx.ovs_idl);
f1fd7657 503
deab5e67
BP
504 /* Run all of the cleanup functions, even if one of them returns false.
505 * We're done if all of them return true. */
4acc496e
BP
506 done = binding_cleanup(&ctx, chassis_id);
507 done = chassis_cleanup(&ctx, chassis_id) && done;
deab5e67 508 done = encaps_cleanup(&ctx, br_int) && done;
f1fd7657
BP
509 if (done) {
510 poll_immediate_wake();
511 }
512
a548a764
AW
513 ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
514 ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
f1fd7657
BP
515 poll_block();
516 }
517
717c7fc5 518 unixctl_server_destroy(unixctl);
48605550 519 lflow_destroy();
b4e87a48 520 ofctrl_destroy();
27732ac4 521 pinctrl_destroy();
717c7fc5 522
78aab811
JP
523 simap_destroy(&ct_zones);
524
467085fd
GS
525 bitmap_free(group_table.group_ids);
526 hmap_destroy(&group_table.desired_groups);
527
528 struct group_info *installed, *next_group;
529 HMAP_FOR_EACH_SAFE(installed, next_group, hmap_node,
530 &group_table.existing_groups) {
531 hmap_remove(&group_table.existing_groups, &installed->hmap_node);
532 ds_destroy(&installed->group);
533 free(installed);
534 }
535 hmap_destroy(&group_table.existing_groups);
536
a548a764
AW
537 ovsdb_idl_loop_destroy(&ovs_idl_loop);
538 ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
717c7fc5 539
07c747d0
RB
540 free(ovnsb_remote);
541 free(ovs_remote);
485f0696 542 service_stop();
71bf929e 543
717c7fc5
JP
544 exit(retval);
545}
546
547static void
548parse_options(int argc, char *argv[])
549{
550 enum {
551 OPT_PEER_CA_CERT = UCHAR_MAX + 1,
419eed61 552 OPT_BOOTSTRAP_CA_CERT,
717c7fc5
JP
553 VLOG_OPTION_ENUMS,
554 DAEMON_OPTION_ENUMS
555 };
556
557 static struct option long_options[] = {
558 {"help", no_argument, NULL, 'h'},
559 {"version", no_argument, NULL, 'V'},
560 VLOG_LONG_OPTIONS,
561 DAEMON_LONG_OPTIONS,
562 STREAM_SSL_LONG_OPTIONS,
563 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
419eed61 564 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
717c7fc5
JP
565 {NULL, 0, NULL, 0}
566 };
567 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
568
569 for (;;) {
570 int c;
571
572 c = getopt_long(argc, argv, short_options, long_options, NULL);
573 if (c == -1) {
574 break;
575 }
576
577 switch (c) {
578 case 'h':
579 usage();
580
581 case 'V':
582 ovs_print_version(OFP13_VERSION, OFP13_VERSION);
583 exit(EXIT_SUCCESS);
584
585 VLOG_OPTION_HANDLERS
586 DAEMON_OPTION_HANDLERS
587 STREAM_SSL_OPTION_HANDLERS
588
589 case OPT_PEER_CA_CERT:
590 stream_ssl_set_peer_ca_cert_file(optarg);
591 break;
592
419eed61
GS
593 case OPT_BOOTSTRAP_CA_CERT:
594 stream_ssl_set_ca_cert_file(optarg, true);
595 break;
596
717c7fc5
JP
597 case '?':
598 exit(EXIT_FAILURE);
599
600 default:
601 abort();
602 }
603 }
604 free(short_options);
605
606 argc -= optind;
607 argv += optind;
608
609 if (argc == 0) {
610 ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
611 } else if (argc == 1) {
07c747d0 612 ovs_remote = xstrdup(argv[0]);
717c7fc5
JP
613 } else {
614 VLOG_FATAL("exactly zero or one non-option argument required; "
615 "use --help for usage");
616 }
617}
618
619static void
620usage(void)
621{
622 printf("%s: OVN controller\n"
623 "usage %s [OPTIONS] [OVS-DATABASE]\n"
624 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
625 program_name, program_name);
626 stream_usage("OVS-DATABASE", true, false, false);
627 daemon_usage();
628 vlog_usage();
629 printf("\nOther options:\n"
630 " -h, --help display this help message\n"
631 " -V, --version display version information\n");
632 exit(EXIT_SUCCESS);
633}
634
635static void
636ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
637 const char *argv[] OVS_UNUSED, void *exiting_)
638{
639 bool *exiting = exiting_;
640 *exiting = true;
641
642 unixctl_command_reply(conn, NULL);
643}
78aab811
JP
644
645static void
646ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
647 const char *argv[] OVS_UNUSED, void *ct_zones_)
648{
649 struct simap *ct_zones = ct_zones_;
650 struct ds ds = DS_EMPTY_INITIALIZER;
651 struct simap_node *zone;
652
653 SIMAP_FOR_EACH(zone, ct_zones) {
654 ds_put_format(&ds, "%s %d\n", zone->name, zone->data);
655 }
656
657 unixctl_command_reply(conn, ds_cstr(&ds));
658 ds_destroy(&ds);
659}
715038b6
NG
660
661/* Get the desired SB probe timer from the OVS database and configure it into
662 * the SB database. */
663static void
664update_probe_interval(struct controller_ctx *ctx)
665{
666 const struct ovsrec_open_vswitch *cfg
667 = ovsrec_open_vswitch_first(ctx->ovs_idl);
668 int interval = (cfg
669 ? smap_get_int(&cfg->external_ids,
670 "ovn-remote-probe-interval",
671 DEFAULT_PROBE_INTERVAL_MSEC)
672 : DEFAULT_PROBE_INTERVAL_MSEC);
673 ovsdb_idl_set_probe_interval(ctx->ovnsb_idl, interval);
674}