1 /* Copyright (c) 2015 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include "command-line.h"
28 #include "openvswitch/vconn.h"
29 #include "openvswitch/vlog.h"
30 #include "ovn/lib/ovn-sb-idl.h"
31 #include "poll-loop.h"
32 #include "fatal-signal.h"
33 #include "lib/vswitch-idl.h"
36 #include "stream-ssl.h"
40 #include "ovn-controller.h"
44 VLOG_DEFINE_THIS_MODULE(main);
46 static unixctl_cb_func ovn_controller_exit;
48 #define DEFAULT_BRIDGE_NAME "br-int"
50 static void parse_options(int argc, char *argv[]);
51 OVS_NO_RETURN static void usage(void);
53 static char *ovs_remote;
54 static char *ovnsb_remote;
58 get_initial_snapshot(struct ovsdb_idl *idl)
62 if (ovsdb_idl_has_ever_connected(idl)) {
70 static const struct ovsrec_bridge *
71 get_bridge(struct controller_ctx *ctx, const char *name)
73 const struct ovsrec_bridge *br;
75 OVSREC_BRIDGE_FOR_EACH(br, ctx->ovs_idl) {
76 if (!strcmp(br->name, name)) {
84 /* Retrieve the OVN integration bridge from the "external-ids:ovn-bridge"
85 * key, the remote location from the "external-ids:ovn-remote" key, and
86 * the chassis name from the "external-ids:system-id" key in the
87 * Open_vSwitch table of the OVS database instance. */
89 get_core_config(struct controller_ctx *ctx)
91 const struct ovsrec_open_vswitch *cfg;
93 cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
95 VLOG_ERR("No Open_vSwitch row defined.");
96 ovsdb_idl_destroy(ctx->ovs_idl);
101 const struct ovsrec_bridge *br_int;
102 const char *remote, *system_id;
104 ovsdb_idl_run(ctx->ovs_idl);
106 ctx->br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
107 if (!ctx->br_int_name) {
108 ctx->br_int_name = DEFAULT_BRIDGE_NAME;
111 br_int = get_bridge(ctx, ctx->br_int_name);
113 VLOG_INFO("Integration bridge '%s' does not exist. Waiting...",
118 /* xxx This does not support changing OVN Southbound OVSDB mid-run. */
119 remote = smap_get(&cfg->external_ids, "ovn-remote");
121 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
125 system_id = smap_get(&cfg->external_ids, "system-id");
127 VLOG_INFO("system-id not specified. Waiting...");
131 ovnsb_remote = xstrdup(remote);
132 ctx->chassis_name = xstrdup(system_id);
136 ovsdb_idl_wait(ctx->ovs_idl);
143 main(int argc, char *argv[])
145 struct unixctl_server *unixctl;
146 struct controller_ctx ctx = { .chassis_name = NULL };
150 ovs_cmdl_proctitle_init(argc, argv);
151 set_program_name(argv[0]);
152 parse_options(argc, argv);
153 fatal_ignore_sigpipe();
157 retval = unixctl_server_create(NULL, &unixctl);
161 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
163 daemonize_complete();
168 /* Connect to OVS OVSDB instance. We do not monitor all tables by
169 * default, so modules must register their interest explicitly. */
170 ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
172 /* Register interest in "external_ids" column in "Open_vSwitch" table,
173 * since we'll need to get the OVN OVSDB remote. */
174 ovsdb_idl_add_table(ctx.ovs_idl, &ovsrec_table_open_vswitch);
175 ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
180 get_initial_snapshot(ctx.ovs_idl);
182 get_core_config(&ctx);
184 ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
187 get_initial_snapshot(ctx.ovnsb_idl);
191 ovsdb_idl_run(ctx.ovs_idl);
192 ovsdb_idl_run(ctx.ovnsb_idl);
194 /* xxx If run into any surprising changes, we exit. We should
195 * xxx handle this more gracefully. */
196 ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
198 VLOG_ERR("Integration bridge '%s' disappeared",
200 retval = EXIT_FAILURE;
204 if (!ovsdb_idl_is_alive(ctx.ovnsb_idl)) {
205 int retval = ovsdb_idl_get_last_error(ctx.ovnsb_idl);
206 VLOG_ERR("%s: database connection failed (%s)",
207 ovnsb_remote, ovs_retval_to_string(retval));
208 retval = EXIT_FAILURE;
212 if (!ovsdb_idl_is_alive(ctx.ovs_idl)) {
213 int retval = ovsdb_idl_get_last_error(ctx.ovs_idl);
214 VLOG_ERR("%s: database connection failed (%s)",
215 ovs_remote, ovs_retval_to_string(retval));
216 retval = EXIT_FAILURE;
222 unixctl_server_run(unixctl);
224 unixctl_server_wait(unixctl);
226 poll_immediate_wake();
229 ovsdb_idl_wait(ctx.ovs_idl);
230 ovsdb_idl_wait(ctx.ovnsb_idl);
234 unixctl_server_destroy(unixctl);
235 bindings_destroy(&ctx);
236 chassis_destroy(&ctx);
238 ovsdb_idl_destroy(ctx.ovs_idl);
239 ovsdb_idl_destroy(ctx.ovnsb_idl);
245 parse_options(int argc, char *argv[])
248 OPT_PEER_CA_CERT = UCHAR_MAX + 1,
253 static struct option long_options[] = {
254 {"help", no_argument, NULL, 'h'},
255 {"version", no_argument, NULL, 'V'},
258 STREAM_SSL_LONG_OPTIONS,
259 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
262 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
267 c = getopt_long(argc, argv, short_options, long_options, NULL);
277 ovs_print_version(OFP13_VERSION, OFP13_VERSION);
281 DAEMON_OPTION_HANDLERS
282 STREAM_SSL_OPTION_HANDLERS
284 case OPT_PEER_CA_CERT:
285 stream_ssl_set_peer_ca_cert_file(optarg);
301 ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
302 } else if (argc == 1) {
303 ovs_remote = argv[0];
305 VLOG_FATAL("exactly zero or one non-option argument required; "
306 "use --help for usage");
313 printf("%s: OVN controller\n"
314 "usage %s [OPTIONS] [OVS-DATABASE]\n"
315 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
316 program_name, program_name);
317 stream_usage("OVS-DATABASE", true, false, false);
320 printf("\nOther options:\n"
321 " -h, --help display this help message\n"
322 " -V, --version display version information\n");
327 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
328 const char *argv[] OVS_UNUSED, void *exiting_)
330 bool *exiting = exiting_;
333 unixctl_command_reply(conn, NULL);