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/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 static void parse_options(int argc, char *argv[]);
49 OVS_NO_RETURN static void usage(void);
51 static char *ovs_remote;
52 static char *ovnsb_remote;
56 get_initial_snapshot(struct ovsdb_idl *idl)
60 if (ovsdb_idl_has_ever_connected(idl)) {
68 /* Retrieve the OVN remote location from the "external-ids:ovn-remote"
69 * key and the chassis name from the "external-ids:system-id" key in the
70 * Open_vSwitch table of the OVS database instance. */
72 get_core_config(struct controller_ctx *ctx)
74 const struct ovsrec_open_vswitch *cfg;
76 cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
78 VLOG_ERR("No Open_vSwitch row defined.");
79 ovsdb_idl_destroy(ctx->ovs_idl);
84 const char *remote, *system_id;
86 ovsdb_idl_run(ctx->ovs_idl);
88 /* xxx This does not support changing OVN Southbound OVSDB mid-run. */
89 remote = smap_get(&cfg->external_ids, "ovn-remote");
91 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
95 system_id = smap_get(&cfg->external_ids, "system-id");
97 VLOG_INFO("system-id not specified. Waiting...");
101 ovnsb_remote = xstrdup(remote);
102 ctx->chassis_name = xstrdup(system_id);
106 ovsdb_idl_wait(ctx->ovs_idl);
113 main(int argc, char *argv[])
115 struct unixctl_server *unixctl;
116 struct controller_ctx ctx = { .chassis_name = NULL };
120 ovs_cmdl_proctitle_init(argc, argv);
121 set_program_name(argv[0]);
122 parse_options(argc, argv);
123 fatal_ignore_sigpipe();
127 retval = unixctl_server_create(NULL, &unixctl);
131 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
133 daemonize_complete();
138 /* Connect to OVS OVSDB instance. We do not monitor all tables by
139 * default, so modules must register their interest explicitly. */
140 ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
142 /* Register interest in "external_ids" column in "Open_vSwitch" table,
143 * since we'll need to get the OVN OVSDB remote. */
144 ovsdb_idl_add_table(ctx.ovs_idl, &ovsrec_table_open_vswitch);
145 ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
150 get_initial_snapshot(ctx.ovs_idl);
152 get_core_config(&ctx);
154 ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
157 get_initial_snapshot(ctx.ovnsb_idl);
161 ovsdb_idl_run(ctx.ovs_idl);
162 ovsdb_idl_run(ctx.ovnsb_idl);
164 if (!ovsdb_idl_is_alive(ctx.ovnsb_idl)) {
165 int retval = ovsdb_idl_get_last_error(ctx.ovnsb_idl);
166 VLOG_ERR("%s: database connection failed (%s)",
167 ovnsb_remote, ovs_retval_to_string(retval));
168 retval = EXIT_FAILURE;
172 if (!ovsdb_idl_is_alive(ctx.ovs_idl)) {
173 int retval = ovsdb_idl_get_last_error(ctx.ovs_idl);
174 VLOG_ERR("%s: database connection failed (%s)",
175 ovs_remote, ovs_retval_to_string(retval));
176 retval = EXIT_FAILURE;
182 unixctl_server_run(unixctl);
184 unixctl_server_wait(unixctl);
186 poll_immediate_wake();
189 ovsdb_idl_wait(ctx.ovs_idl);
190 ovsdb_idl_wait(ctx.ovnsb_idl);
194 unixctl_server_destroy(unixctl);
195 bindings_destroy(&ctx);
196 chassis_destroy(&ctx);
198 ovsdb_idl_destroy(ctx.ovs_idl);
199 ovsdb_idl_destroy(ctx.ovnsb_idl);
205 parse_options(int argc, char *argv[])
208 OPT_PEER_CA_CERT = UCHAR_MAX + 1,
213 static struct option long_options[] = {
214 {"help", no_argument, NULL, 'h'},
215 {"version", no_argument, NULL, 'V'},
218 STREAM_SSL_LONG_OPTIONS,
219 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
222 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
227 c = getopt_long(argc, argv, short_options, long_options, NULL);
237 ovs_print_version(OFP13_VERSION, OFP13_VERSION);
241 DAEMON_OPTION_HANDLERS
242 STREAM_SSL_OPTION_HANDLERS
244 case OPT_PEER_CA_CERT:
245 stream_ssl_set_peer_ca_cert_file(optarg);
261 ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
262 } else if (argc == 1) {
263 ovs_remote = argv[0];
265 VLOG_FATAL("exactly zero or one non-option argument required; "
266 "use --help for usage");
273 printf("%s: OVN controller\n"
274 "usage %s [OPTIONS] [OVS-DATABASE]\n"
275 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
276 program_name, program_name);
277 stream_usage("OVS-DATABASE", true, false, false);
280 printf("\nOther options:\n"
281 " -h, --help display this help message\n"
282 " -V, --version display version information\n");
287 ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
288 const char *argv[] OVS_UNUSED, void *exiting_)
290 bool *exiting = exiting_;
293 unixctl_command_reply(conn, NULL);