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 * xxx ovn-controller does not support changing any of these mid-run,
90 * xxx but that should be addressed later. */
92 get_core_config(struct controller_ctx *ctx)
94 const struct ovsrec_open_vswitch *cfg;
96 cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
98 VLOG_ERR("No Open_vSwitch row defined.");
99 ovsdb_idl_destroy(ctx->ovs_idl);
104 const struct ovsrec_bridge *br_int;
105 const char *remote, *system_id, *br_int_name;
107 ovsdb_idl_run(ctx->ovs_idl);
109 br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
111 br_int_name = DEFAULT_BRIDGE_NAME;
113 ctx->br_int_name = xstrdup(br_int_name);
115 br_int = get_bridge(ctx, ctx->br_int_name);
117 VLOG_INFO("Integration bridge '%s' does not exist. Waiting...",
122 remote = smap_get(&cfg->external_ids, "ovn-remote");
124 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
128 system_id = smap_get(&cfg->external_ids, "system-id");
130 VLOG_INFO("system-id not specified. Waiting...");
134 ovnsb_remote = xstrdup(remote);
135 ctx->chassis_id = xstrdup(system_id);
139 ovsdb_idl_wait(ctx->ovs_idl);
146 main(int argc, char *argv[])
148 struct unixctl_server *unixctl;
149 struct controller_ctx ctx = { .chassis_id = NULL };
153 ovs_cmdl_proctitle_init(argc, argv);
154 set_program_name(argv[0]);
155 parse_options(argc, argv);
156 fatal_ignore_sigpipe();
160 retval = unixctl_server_create(NULL, &unixctl);
164 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
166 daemonize_complete();
171 /* Connect to OVS OVSDB instance. We do not monitor all tables by
172 * default, so modules must register their interest explicitly. */
173 ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
175 /* Register interest in "external_ids" column in "Open_vSwitch" table,
176 * since we'll need to get the OVN OVSDB remote. */
177 ovsdb_idl_add_table(ctx.ovs_idl, &ovsrec_table_open_vswitch);
178 ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
183 get_initial_snapshot(ctx.ovs_idl);
185 get_core_config(&ctx);
187 ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
190 get_initial_snapshot(ctx.ovnsb_idl);
194 ovsdb_idl_run(ctx.ovs_idl);
195 ovsdb_idl_run(ctx.ovnsb_idl);
197 /* xxx If run into any surprising changes, we exit. We should
198 * xxx handle this more gracefully. */
199 ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
201 VLOG_ERR("Integration bridge '%s' disappeared",
203 retval = EXIT_FAILURE;
207 if (!ovsdb_idl_is_alive(ctx.ovnsb_idl)) {
208 int retval = ovsdb_idl_get_last_error(ctx.ovnsb_idl);
209 VLOG_ERR("%s: database connection failed (%s)",
210 ovnsb_remote, ovs_retval_to_string(retval));
211 retval = EXIT_FAILURE;
215 if (!ovsdb_idl_is_alive(ctx.ovs_idl)) {
216 int retval = ovsdb_idl_get_last_error(ctx.ovs_idl);
217 VLOG_ERR("%s: database connection failed (%s)",
218 ovs_remote, ovs_retval_to_string(retval));
219 retval = EXIT_FAILURE;
225 unixctl_server_run(unixctl);
227 unixctl_server_wait(unixctl);
229 poll_immediate_wake();
232 ovsdb_idl_wait(ctx.ovs_idl);
233 ovsdb_idl_wait(ctx.ovnsb_idl);
237 unixctl_server_destroy(unixctl);
238 bindings_destroy(&ctx);
239 chassis_destroy(&ctx);
241 ovsdb_idl_destroy(ctx.ovs_idl);
242 ovsdb_idl_destroy(ctx.ovnsb_idl);
244 free(ctx.br_int_name);
245 free(ctx.chassis_id);
253 parse_options(int argc, char *argv[])
256 OPT_PEER_CA_CERT = UCHAR_MAX + 1,
261 static struct option long_options[] = {
262 {"help", no_argument, NULL, 'h'},
263 {"version", no_argument, NULL, 'V'},
266 STREAM_SSL_LONG_OPTIONS,
267 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
270 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
275 c = getopt_long(argc, argv, short_options, long_options, NULL);
285 ovs_print_version(OFP13_VERSION, OFP13_VERSION);
289 DAEMON_OPTION_HANDLERS
290 STREAM_SSL_OPTION_HANDLERS
292 case OPT_PEER_CA_CERT:
293 stream_ssl_set_peer_ca_cert_file(optarg);
309 ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
310 } else if (argc == 1) {
311 ovs_remote = xstrdup(argv[0]);
313 VLOG_FATAL("exactly zero or one non-option argument required; "
314 "use --help for usage");
321 printf("%s: OVN controller\n"
322 "usage %s [OPTIONS] [OVS-DATABASE]\n"
323 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
324 program_name, program_name);
325 stream_usage("OVS-DATABASE", true, false, false);
328 printf("\nOther options:\n"
329 " -h, --help display this help message\n"
330 " -V, --version display version information\n");
335 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
336 const char *argv[] OVS_UNUSED, void *exiting_)
338 bool *exiting = exiting_;
341 unixctl_command_reply(conn, NULL);