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"
48 VLOG_DEFINE_THIS_MODULE(main
);
50 static unixctl_cb_func ovn_controller_exit
;
52 #define DEFAULT_BRIDGE_NAME "br-int"
54 static void parse_options(int argc
, char *argv
[]);
55 OVS_NO_RETURN
static void usage(void);
57 static char *ovs_remote
;
58 static char *ovnsb_remote
;
62 get_initial_snapshot(struct ovsdb_idl
*idl
)
66 if (ovsdb_idl_has_ever_connected(idl
)) {
74 static const struct ovsrec_bridge
*
75 get_bridge(struct controller_ctx
*ctx
, const char *name
)
77 const struct ovsrec_bridge
*br
;
79 OVSREC_BRIDGE_FOR_EACH(br
, ctx
->ovs_idl
) {
80 if (!strcmp(br
->name
, name
)) {
88 /* Retrieve the OVN integration bridge from the "external-ids:ovn-bridge"
89 * key, the remote location from the "external-ids:ovn-remote" key, and
90 * the chassis name from the "external-ids:system-id" key in the
91 * Open_vSwitch table of the OVS database instance.
93 * xxx ovn-controller does not support changing any of these mid-run,
94 * xxx but that should be addressed later. */
96 get_core_config(struct controller_ctx
*ctx
)
99 ovsdb_idl_run(ctx
->ovs_idl
);
101 const struct ovsrec_open_vswitch
*cfg
;
102 cfg
= ovsrec_open_vswitch_first(ctx
->ovs_idl
);
104 VLOG_ERR("No Open_vSwitch row defined.");
105 ovsdb_idl_destroy(ctx
->ovs_idl
);
109 const struct ovsrec_bridge
*br_int
;
110 const char *remote
, *system_id
, *br_int_name
;
112 br_int_name
= smap_get(&cfg
->external_ids
, "ovn-bridge");
114 br_int_name
= DEFAULT_BRIDGE_NAME
;
116 ctx
->br_int_name
= xstrdup(br_int_name
);
118 br_int
= get_bridge(ctx
, ctx
->br_int_name
);
120 VLOG_INFO("Integration bridge '%s' does not exist. Waiting...",
125 remote
= smap_get(&cfg
->external_ids
, "ovn-remote");
127 VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
131 system_id
= smap_get(&cfg
->external_ids
, "system-id");
133 VLOG_INFO("system-id not specified. Waiting...");
137 ovnsb_remote
= xstrdup(remote
);
138 ctx
->chassis_id
= xstrdup(system_id
);
142 ovsdb_idl_wait(ctx
->ovs_idl
);
149 struct ovsdb_idl
*idl
;
150 unsigned int skip_seqno
;
152 struct ovsdb_idl_txn
*committing_txn
;
153 unsigned int precommit_seqno
;
155 struct ovsdb_idl_txn
*open_txn
;
158 #define IDL_LOOP_INITIALIZER(IDL) { .idl = (IDL) }
161 idl_loop_destroy(struct idl_loop
*loop
)
164 ovsdb_idl_destroy(loop
->idl
);
168 static struct ovsdb_idl_txn
*
169 idl_loop_run(struct idl_loop
*loop
)
171 ovsdb_idl_run(loop
->idl
);
172 loop
->open_txn
= (loop
->committing_txn
173 || ovsdb_idl_get_seqno(loop
->idl
) == loop
->skip_seqno
175 : ovsdb_idl_txn_create(loop
->idl
));
176 return loop
->open_txn
;
180 idl_loop_commit_and_wait(struct idl_loop
*loop
)
182 if (loop
->open_txn
) {
183 loop
->committing_txn
= loop
->open_txn
;
184 loop
->open_txn
= NULL
;
186 loop
->precommit_seqno
= ovsdb_idl_get_seqno(loop
->idl
);
189 struct ovsdb_idl_txn
*txn
= loop
->committing_txn
;
191 enum ovsdb_idl_txn_status status
= ovsdb_idl_txn_commit(txn
);
197 loop
->skip_seqno
= loop
->precommit_seqno
;
198 if (ovsdb_idl_get_seqno(loop
->idl
) != loop
->skip_seqno
) {
199 poll_immediate_wake();
207 ovsdb_idl_txn_destroy(txn
);
208 loop
->committing_txn
= NULL
;
211 case TXN_UNCOMMITTED
:
217 ovsdb_idl_wait(loop
->idl
);
221 main(int argc
, char *argv
[])
223 struct unixctl_server
*unixctl
;
224 struct controller_ctx ctx
= { .chassis_id
= NULL
};
228 ovs_cmdl_proctitle_init(argc
, argv
);
229 set_program_name(argv
[0]);
230 parse_options(argc
, argv
);
231 fatal_ignore_sigpipe();
235 retval
= unixctl_server_create(NULL
, &unixctl
);
239 unixctl_command_register("exit", "", 0, 0, ovn_controller_exit
, &exiting
);
241 daemonize_complete();
248 /* Connect to OVS OVSDB instance. We do not monitor all tables by
249 * default, so modules must register their interest explicitly. */
250 ctx
.ovs_idl
= ovsdb_idl_create(ovs_remote
, &ovsrec_idl_class
, false, true);
252 /* Register interest in "external_ids" column in "Open_vSwitch" table,
253 * since we'll need to get the OVN OVSDB remote. */
254 ovsdb_idl_add_table(ctx
.ovs_idl
, &ovsrec_table_open_vswitch
);
255 ovsdb_idl_add_column(ctx
.ovs_idl
, &ovsrec_open_vswitch_col_external_ids
);
262 get_initial_snapshot(ctx
.ovs_idl
);
264 get_core_config(&ctx
);
266 ctx
.ovnsb_idl
= ovsdb_idl_create(ovnsb_remote
, &sbrec_idl_class
,
268 get_initial_snapshot(ctx
.ovnsb_idl
);
270 struct idl_loop ovnsb_idl_loop
= IDL_LOOP_INITIALIZER(ctx
.ovnsb_idl
);
271 struct idl_loop ovs_idl_loop
= IDL_LOOP_INITIALIZER(ctx
.ovs_idl
);
276 ctx
.ovnsb_idl_txn
= idl_loop_run(&ovnsb_idl_loop
);
277 ctx
.ovs_idl_txn
= idl_loop_run(&ovs_idl_loop
);
279 /* xxx If run into any surprising changes, we exit. We should
280 * xxx handle this more gracefully. */
281 ctx
.br_int
= get_bridge(&ctx
, ctx
.br_int_name
);
283 VLOG_ERR("Integration bridge '%s' disappeared",
285 retval
= EXIT_FAILURE
;
292 struct hmap flow_table
= HMAP_INITIALIZER(&flow_table
);
293 pipeline_run(&ctx
, &flow_table
);
294 physical_run(&ctx
, &flow_table
);
295 ofctrl_run(&ctx
, &flow_table
);
296 hmap_destroy(&flow_table
);
298 unixctl_server_run(unixctl
);
300 unixctl_server_wait(unixctl
);
302 poll_immediate_wake();
305 idl_loop_commit_and_wait(&ovnsb_idl_loop
);
306 idl_loop_commit_and_wait(&ovs_idl_loop
);
312 /* It's time to exit. Clean up the databases. */
315 ctx
.ovnsb_idl_txn
= idl_loop_run(&ovnsb_idl_loop
);
316 ctx
.ovs_idl_txn
= idl_loop_run(&ovs_idl_loop
);
318 /* xxx If run into any surprising changes, we exit. We should
319 * xxx handle this more gracefully. */
320 ctx
.br_int
= get_bridge(&ctx
, ctx
.br_int_name
);
322 VLOG_ERR("Integration bridge '%s' disappeared",
324 retval
= EXIT_FAILURE
;
328 /* Run both the binding and chassis cleanup, even if one of them
329 * returns false. We're done if both return true. */
330 done
= binding_cleanup(&ctx
);
331 done
= chassis_cleanup(&ctx
) && done
;
333 poll_immediate_wake();
336 idl_loop_commit_and_wait(&ovnsb_idl_loop
);
337 idl_loop_commit_and_wait(&ovs_idl_loop
);
342 unixctl_server_destroy(unixctl
);
343 pipeline_destroy(&ctx
);
346 idl_loop_destroy(&ovs_idl_loop
);
347 idl_loop_destroy(&ovnsb_idl_loop
);
349 free(ctx
.br_int_name
);
350 free(ctx
.chassis_id
);
358 parse_options(int argc
, char *argv
[])
361 OPT_PEER_CA_CERT
= UCHAR_MAX
+ 1,
366 static struct option long_options
[] = {
367 {"help", no_argument
, NULL
, 'h'},
368 {"version", no_argument
, NULL
, 'V'},
371 STREAM_SSL_LONG_OPTIONS
,
372 {"peer-ca-cert", required_argument
, NULL
, OPT_PEER_CA_CERT
},
375 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
380 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
390 ovs_print_version(OFP13_VERSION
, OFP13_VERSION
);
394 DAEMON_OPTION_HANDLERS
395 STREAM_SSL_OPTION_HANDLERS
397 case OPT_PEER_CA_CERT
:
398 stream_ssl_set_peer_ca_cert_file(optarg
);
414 ovs_remote
= xasprintf("unix:%s/db.sock", ovs_rundir());
415 } else if (argc
== 1) {
416 ovs_remote
= xstrdup(argv
[0]);
418 VLOG_FATAL("exactly zero or one non-option argument required; "
419 "use --help for usage");
426 printf("%s: OVN controller\n"
427 "usage %s [OPTIONS] [OVS-DATABASE]\n"
428 "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
429 program_name
, program_name
);
430 stream_usage("OVS-DATABASE", true, false, false);
433 printf("\nOther options:\n"
434 " -h, --help display this help message\n"
435 " -V, --version display version information\n");
440 ovn_controller_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
441 const char *argv
[] OVS_UNUSED
, void *exiting_
)
443 bool *exiting
= exiting_
;
446 unixctl_command_reply(conn
, NULL
);