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.
18 #include "ovn-controller.h"
26 #include "command-line.h"
30 #include "openvswitch/vconn.h"
31 #include "openvswitch/vlog.h"
32 #include "ovn/lib/ovn-sb-idl.h"
33 #include "poll-loop.h"
34 #include "fatal-signal.h"
35 #include "lib/vswitch-idl.h"
38 #include "stream-ssl.h"
49 VLOG_DEFINE_THIS_MODULE(main
);
51 static unixctl_cb_func ovn_controller_exit
;
53 #define DEFAULT_BRIDGE_NAME "br-int"
55 static void parse_options(int argc
, char *argv
[]);
56 OVS_NO_RETURN
static void usage(void);
58 static char *ovs_remote
;
61 get_initial_snapshot(struct ovsdb_idl
*idl
)
65 if (ovsdb_idl_has_ever_connected(idl
)) {
73 static const struct ovsrec_bridge
*
74 get_br_int(struct ovsdb_idl
*ovs_idl
)
76 const struct ovsrec_open_vswitch
*cfg
= ovsrec_open_vswitch_first(ovs_idl
);
81 const char *br_int_name
= smap_get(&cfg
->external_ids
, "ovn-bridge");
83 br_int_name
= DEFAULT_BRIDGE_NAME
;
86 const struct ovsrec_bridge
*br
;
87 OVSREC_BRIDGE_FOR_EACH (br
, ovs_idl
) {
88 if (!strcmp(br
->name
, br_int_name
)) {
93 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
94 VLOG_WARN_RL(&rl
, "%s: integration bridge does not exist", br_int_name
);
99 get_chassis_id(const struct ovsdb_idl
*ovs_idl
)
101 const struct ovsrec_open_vswitch
*cfg
= ovsrec_open_vswitch_first(ovs_idl
);
102 return cfg
? smap_get(&cfg
->external_ids
, "system-id") : NULL
;
105 /* Retrieves the OVN Southbound remote location from the
106 * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
108 * XXX ovn-controller does not support this changing mid-run, but that should
109 * be addressed later. */
111 get_ovnsb_remote(struct ovsdb_idl
*ovs_idl
)
114 ovsdb_idl_run(ovs_idl
);
116 const struct ovsrec_open_vswitch
*cfg
117 = ovsrec_open_vswitch_first(ovs_idl
);
119 const char *remote
= smap_get(&cfg
->external_ids
, "ovn-remote");
121 return xstrdup(remote
);
125 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
126 ovsdb_idl_wait(ovs_idl
);
132 struct ovsdb_idl
*idl
;
133 unsigned int skip_seqno
;
135 struct ovsdb_idl_txn
*committing_txn
;
136 unsigned int precommit_seqno
;
138 struct ovsdb_idl_txn
*open_txn
;
141 #define IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) }
144 idl_loop_destroy(struct idl_loop
*loop
)
147 ovsdb_idl_destroy(loop
->idl
);
151 static struct ovsdb_idl_txn
*
152 idl_loop_run(struct idl_loop
*loop
)
154 ovsdb_idl_run(loop
->idl
);
155 loop
->open_txn
= (loop
->committing_txn
156 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
158 : ovsdb_idl_txn_create(loop
->idl
));
159 return loop
->open_txn
;
163 idl_loop_commit_and_wait(struct idl_loop
*loop
)
165 if (loop
->open_txn
) {
166 loop
->committing_txn
= loop
->open_txn
;
167 loop
->open_txn
= NULL
;
169 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
172 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
174 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
175 if (status
!= TXN_INCOMPLETE
) {
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();
188 /* If the database has already changed since we started the
189 * commit, re-evaluate it immediately to avoid missing a change
191 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->precommit_seqno
) {
192 poll_immediate_wake();
202 case TXN_UNCOMMITTED
:
207 ovsdb_idl_txn_destroy(txn
);
208 loop
->committing_txn
= NULL
;
212 ovsdb_idl_wait(loop
->idl
);
216 main(int argc
, char *argv
[])
218 struct unixctl_server
*unixctl
;
219 struct controller_ctx ctx
= { .ovs_idl
= NULL
};
223 ovs_cmdl_proctitle_init(argc
, argv
);
224 set_program_name(argv
[0]);
225 parse_options(argc
, argv
);
226 fatal_ignore_sigpipe();
230 retval
= unixctl_server_create(NULL
, &unixctl
);
234 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit
, &exiting
);
236 daemonize_complete();
244 /* Connect to OVS OVSDB instance. We do not monitor all tables by
245 * default, so modules must register their interest explicitly. */
246 ctx
.ovs_idl
= ovsdb_idl_create(ovs_remote
, &ovsrec_idl_class
, false, true);
247 ovsdb_idl_add_table(ctx
.ovs_idl
, &ovsrec_table_open_vswitch
);
248 ovsdb_idl_add_column(ctx
.ovs_idl
, &ovsrec_open_vswitch_col_external_ids
);
249 chassis_register_ovs_idl(ctx
.ovs_idl
);
250 encaps_register_ovs_idl(ctx
.ovs_idl
);
251 binding_register_ovs_idl(ctx
.ovs_idl
);
252 physical_register_ovs_idl(ctx
.ovs_idl
);
254 get_initial_snapshot(ctx
.ovs_idl
);
256 char *ovnsb_remote
= get_ovnsb_remote(ctx
.ovs_idl
);
257 ctx
.ovnsb_idl
= ovsdb_idl_create(ovnsb_remote
, &sbrec_idl_class
,
259 get_initial_snapshot(ctx
.ovnsb_idl
);
261 struct idl_loop ovnsb_idl_loop
= IDL_LOOP_INITIALIZER(ctx
.ovnsb_idl
);
262 struct idl_loop ovs_idl_loop
= IDL_LOOP_INITIALIZER(ctx
.ovs_idl
);
267 ctx
.ovnsb_idl_txn
= idl_loop_run(&ovnsb_idl_loop
);
268 ctx
.ovs_idl_txn
= idl_loop_run(&ovs_idl_loop
);
270 const struct ovsrec_bridge
*br_int
= get_br_int(ctx
.ovs_idl
);
271 const char *chassis_id
= get_chassis_id(ctx
.ovs_idl
);
274 chassis_run(&ctx
, chassis_id
);
275 encaps_run(&ctx
, br_int
, chassis_id
);
276 binding_run(&ctx
, br_int
, chassis_id
);
280 struct hmap flow_table
= HMAP_INITIALIZER(&flow_table
);
281 pipeline_run(&ctx
, &flow_table
);
283 physical_run(&ctx
, br_int
, chassis_id
, &flow_table
);
285 ofctrl_run(br_int
, &flow_table
);
286 hmap_destroy(&flow_table
);
289 unixctl_server_run(unixctl
);
291 unixctl_server_wait(unixctl
);
293 poll_immediate_wake();
296 idl_loop_commit_and_wait(&ovnsb_idl_loop
);
297 idl_loop_commit_and_wait(&ovs_idl_loop
);
305 /* It's time to exit. Clean up the databases. */
308 ctx
.ovnsb_idl_txn
= idl_loop_run(&ovnsb_idl_loop
);
309 ctx
.ovs_idl_txn
= idl_loop_run(&ovs_idl_loop
);
311 const struct ovsrec_bridge
*br_int
= get_br_int(ctx
.ovs_idl
);
312 const char *chassis_id
= get_chassis_id(ctx
.ovs_idl
);
314 /* Run all of the cleanup functions, even if one of them returns false.
315 * We're done if all of them return true. */
316 done
= binding_cleanup(&ctx
, chassis_id
);
317 done
= chassis_cleanup(&ctx
, chassis_id
) && done
;
318 done
= encaps_cleanup(&ctx
, br_int
) && done
;
320 poll_immediate_wake();
323 idl_loop_commit_and_wait(&ovnsb_idl_loop
);
324 idl_loop_commit_and_wait(&ovs_idl_loop
);
328 unixctl_server_destroy(unixctl
);
332 idl_loop_destroy(&ovs_idl_loop
);
333 idl_loop_destroy(&ovnsb_idl_loop
);
342 parse_options(int argc
, char *argv
[])
345 OPT_PEER_CA_CERT
= UCHAR_MAX
+ 1,
350 static struct option long_options
[] = {
351 {"help", no_argument
, NULL
, 'h'},
352 {"version", no_argument
, NULL
, 'V'},
355 STREAM_SSL_LONG_OPTIONS
,
356 {"peer-ca-cert", required_argument
, NULL
, OPT_PEER_CA_CERT
},
359 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
364 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
374 ovs_print_version(OFP13_VERSION
, OFP13_VERSION
);
378 DAEMON_OPTION_HANDLERS
379 STREAM_SSL_OPTION_HANDLERS
381 case OPT_PEER_CA_CERT
:
382 stream_ssl_set_peer_ca_cert_file(optarg
);
398 ovs_remote
= xasprintf("unix:%s/db.sock", ovs_rundir());
399 } else if (argc
== 1) {
400 ovs_remote
= xstrdup(argv
[0]);
402 VLOG_FATAL("exactly zero or one non-option argument required; "
403 "use --help for usage");
410 printf("%s: OVN controller\n"
411 "usage %s [OPTIONS] [OVS-DATABASE]\n"
412 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
413 program_name
, program_name
);
414 stream_usage("OVS-DATABASE", true, false, false);
417 printf("\nOther options:\n"
418 " -h, --help display this help message\n"
419 " -V, --version display version information\n");
424 ovn_controller_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
425 const char *argv
[] OVS_UNUSED
, void *exiting_
)
427 bool *exiting
= exiting_
;
430 unixctl_command_reply(conn
, NULL
);