summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Pettit <jpettit@nicira.com>2015-04-09 00:52:43 -0700
committerJustin Pettit <jpettit@nicira.com>2015-04-12 10:11:06 -0700
commit717c7fc508044d08210c686c1e8576c29a108f86 (patch)
tree9de562dadd84cc76008a3f71653fb19d9d4068f5
parenta0149f4776b6a7e607cba6fb5134e0db1a0d7616 (diff)
downloadopenvswitch-717c7fc508044d08210c686c1e8576c29a108f86.tar.gz
ovn: Introduce ovn-controller.
Add new ovn-controller daemon that runs locally on transport nodes. This initial version registers itself in the Chassis table and registers logical ports to the appropriate rows in the Bindings table. Signed-off-by: Justin Pettit <jpettit@nicira.com> Acked-by: Russell Bryant <rbryant@redhat.com>
-rw-r--r--Makefile.am1
-rw-r--r--ovn/.gitignore1
-rw-r--r--ovn/TODO19
-rw-r--r--ovn/automake.mk4
-rw-r--r--ovn/controller/.gitignore2
-rw-r--r--ovn/controller/automake.mk11
-rw-r--r--ovn/controller/bindings.c179
-rw-r--r--ovn/controller/bindings.h26
-rw-r--r--ovn/controller/chassis.c157
-rw-r--r--ovn/controller/chassis.h25
-rw-r--r--ovn/controller/ovn-controller.8.xml114
-rw-r--r--ovn/controller/ovn-controller.c294
-rw-r--r--ovn/controller/ovn-controller.h26
-rw-r--r--ovn/ovn-controller.8.in41
-rwxr-xr-xtutorial/ovs-sandbox14
15 files changed, 850 insertions, 64 deletions
diff --git a/Makefile.am b/Makefile.am
index 699a580ef..16d8e8d9e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -371,3 +371,4 @@ include vtep/automake.mk
include datapath-windows/automake.mk
include datapath-windows/include/automake.mk
include ovn/automake.mk
+include ovn/controller/automake.mk
diff --git a/ovn/.gitignore b/ovn/.gitignore
index 9ddcbb8ee..cbd65a1fb 100644
--- a/ovn/.gitignore
+++ b/ovn/.gitignore
@@ -1,5 +1,4 @@
/ovn-architecture.7
-/ovn-controller.8
/ovn-nb.5
/ovn-nb.gv
/ovn-nb.pic
diff --git a/ovn/TODO b/ovn/TODO
index 7bd89dfca..7a2260658 100644
--- a/ovn/TODO
+++ b/ovn/TODO
@@ -129,17 +129,6 @@
** Interaction with Open_vSwitch and OVN databases:
-*** Monitor VIFs attached to the integration bridge in Open_vSwitch.
-
- In response to changes, add or remove corresponding rows in
- Bindings table in OVN.
-
-*** Populate Chassis row in OVN at startup. Maintain Chassis row over time.
-
- (Warn if any other Chassis claims the same IP address.)
-
-*** Remove Chassis and Bindings rows from OVN on exit.
-
*** Monitor Chassis table in OVN.
Populate Port records for tunnels to other chassis into
@@ -155,14 +144,6 @@
Default: VXLAN? Geneve?
-*** Location of Open_vSwitch database.
-
- We can probably use the same default as ovs-vsctl.
-
-*** Location of OVN Southbound database.
-
- Probably no useful default.
-
*** SSL configuration.
Can probably get this from Open_vSwitch database.
diff --git a/ovn/automake.mk b/ovn/automake.mk
index 180352e52..6388fdc63 100644
--- a/ovn/automake.mk
+++ b/ovn/automake.mk
@@ -66,8 +66,8 @@ ovn/ovn-nb.5: \
$(srcdir)/ovn/ovn-nb.xml > $@.tmp && \
mv $@.tmp $@
-man_MANS += ovn/ovn-controller.8 ovn/ovn-architecture.7 ovn/ovn-nbctl.8
-EXTRA_DIST += ovn/ovn-controller.8.in ovn/ovn-architecture.7.xml ovn/ovn-nbctl.8.xml
+man_MANS += ovn/ovn-architecture.7 ovn/ovn-nbctl.8
+EXTRA_DIST += ovn/ovn-architecture.7.xml ovn/ovn-nbctl.8.xml
SUFFIXES += .xml
%: %.xml
diff --git a/ovn/controller/.gitignore b/ovn/controller/.gitignore
new file mode 100644
index 000000000..4199a3741
--- /dev/null
+++ b/ovn/controller/.gitignore
@@ -0,0 +1,2 @@
+/ovn-controller
+/ovn-controller.8
diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
new file mode 100644
index 000000000..7274cbdb5
--- /dev/null
+++ b/ovn/controller/automake.mk
@@ -0,0 +1,11 @@
+bin_PROGRAMS += ovn/controller/ovn-controller
+ovn_controller_ovn_controller_SOURCES = \
+ ovn/controller/bindings.c \
+ ovn/controller/bindings.h \
+ ovn/controller/chassis.c \
+ ovn/controller/chassis.h \
+ ovn/controller/ovn-controller.c \
+ ovn/controller/ovn-controller.h
+ovn_controller_ovn_controller_LDADD = ovn/libovn.la lib/libopenvswitch.la
+man_MANS += ovn/controller/ovn-controller.8
+EXTRA_DIST += ovn/controller/ovn-controller.8.xml
diff --git a/ovn/controller/bindings.c b/ovn/controller/bindings.c
new file mode 100644
index 000000000..bea4c38a4
--- /dev/null
+++ b/ovn/controller/bindings.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "bindings.h"
+
+#include "lib/sset.h"
+#include "lib/util.h"
+#include "lib/vswitch-idl.h"
+#include "openvswitch/vlog.h"
+#include "ovn/ovn-sb-idl.h"
+#include "ovn-controller.h"
+
+VLOG_DEFINE_THIS_MODULE(bindings);
+
+#define DEFAULT_BRIDGE_NAME "br-int"
+
+void
+bindings_init(struct controller_ctx *ctx)
+{
+ ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_bridges);
+
+ ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_name);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports);
+
+ ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_name);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_interfaces);
+
+ ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_interface);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_name);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
+}
+
+static void
+get_local_iface_ids(struct controller_ctx *ctx, struct sset *lports)
+{
+ const struct ovsrec_open_vswitch *cfg;
+ const struct ovsrec_bridge *bridge_rec;
+ const char *bridge_name;
+ int i;
+
+ cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
+ if (!cfg) {
+ VLOG_INFO("No Open_vSwitch row defined.");
+ return;
+ }
+
+ bridge_name = smap_get(&cfg->external_ids, "ovn-bridge");
+ if (!bridge_name) {
+ bridge_name = DEFAULT_BRIDGE_NAME;
+ }
+
+ OVSREC_BRIDGE_FOR_EACH(bridge_rec, ctx->ovs_idl) {
+ if (!strcmp(bridge_rec->name, bridge_name)) {
+ break;
+ }
+ }
+
+ if (!bridge_rec) {
+ VLOG_INFO("Could not find bridge '%s'", bridge_name);
+ return;
+ }
+
+ for (i = 0; i < bridge_rec->n_ports; i++) {
+ const struct ovsrec_port *port_rec = bridge_rec->ports[i];
+ const char *iface_id;
+ int j;
+
+ if (!strcmp(port_rec->name, bridge_rec->name)) {
+ continue;
+ }
+
+ for (j = 0; j < port_rec->n_interfaces; j++) {
+ const struct ovsrec_interface *iface_rec;
+
+ iface_rec = port_rec->interfaces[j];
+ iface_id = smap_get(&iface_rec->external_ids, "iface-id");
+ if (!iface_id) {
+ VLOG_DBG("Could not find iface-id for '%s'", iface_rec->name);
+ continue;
+ }
+ sset_add(lports, iface_id);
+ }
+ }
+}
+
+void
+bindings_run(struct controller_ctx *ctx)
+{
+ const struct sbrec_bindings *bindings_rec;
+ struct ovsdb_idl_txn *txn;
+ struct sset lports;
+ const char *name;
+ int retval;
+
+ sset_init(&lports);
+ get_local_iface_ids(ctx, &lports);
+
+ txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
+ ovsdb_idl_txn_add_comment(txn,
+ "ovn-controller: updating bindings for '%s'",
+ ctx->chassis_name);
+
+ SBREC_BINDINGS_FOR_EACH(bindings_rec, ctx->ovnsb_idl) {
+ if (sset_find_and_delete(&lports, bindings_rec->logical_port)) {
+ if (!strcmp(bindings_rec->chassis, ctx->chassis_name)) {
+ continue;
+ }
+ if (bindings_rec->chassis[0]) {
+ VLOG_INFO("Changing chassis for lport %s from %s to %s",
+ bindings_rec->logical_port, bindings_rec->chassis,
+ ctx->chassis_name);
+ }
+ sbrec_bindings_set_chassis(bindings_rec, ctx->chassis_name);
+ } else if (!strcmp(bindings_rec->chassis, ctx->chassis_name)) {
+ sbrec_bindings_set_chassis(bindings_rec, "");
+ }
+ }
+
+ retval = ovsdb_idl_txn_commit_block(txn);
+ if (retval == TXN_ERROR) {
+ VLOG_INFO("Problem committing bindings information: %s",
+ ovsdb_idl_txn_status_to_string(retval));
+ }
+
+ ovsdb_idl_txn_destroy(txn);
+
+ SSET_FOR_EACH (name, &lports) {
+ VLOG_DBG("No binding record for lport %s", name);
+ }
+ sset_destroy(&lports);
+}
+
+void
+bindings_destroy(struct controller_ctx *ctx)
+{
+ int retval = TXN_TRY_AGAIN;
+
+ ovs_assert(ctx->ovnsb_idl);
+
+ while (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
+ const struct sbrec_bindings *bindings_rec;
+ struct ovsdb_idl_txn *txn;
+
+ txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
+ ovsdb_idl_txn_add_comment(txn,
+ "ovn-controller: removing all bindings for '%s'",
+ ctx->chassis_name);
+
+ SBREC_BINDINGS_FOR_EACH(bindings_rec, ctx->ovnsb_idl) {
+ if (!strcmp(bindings_rec->chassis, ctx->chassis_name)) {
+ sbrec_bindings_set_chassis(bindings_rec, "");
+ }
+ }
+
+ retval = ovsdb_idl_txn_commit_block(txn);
+ if (retval == TXN_ERROR) {
+ VLOG_INFO("Problem removing bindings: %s",
+ ovsdb_idl_txn_status_to_string(retval));
+ }
+
+ ovsdb_idl_txn_destroy(txn);
+ }
+}
diff --git a/ovn/controller/bindings.h b/ovn/controller/bindings.h
new file mode 100644
index 000000000..07681cd84
--- /dev/null
+++ b/ovn/controller/bindings.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef OVN_BINDINGS_H
+#define OVN_BINDINGS_H 1
+
+struct controller_ctx;
+
+void bindings_init(struct controller_ctx *);
+void bindings_run(struct controller_ctx *);
+void bindings_destroy(struct controller_ctx *);
+
+#endif /* ovn/bindings.h */
diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c
new file mode 100644
index 000000000..2d6e5e60c
--- /dev/null
+++ b/ovn/controller/chassis.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "chassis.h"
+
+#include "lib/poll-loop.h"
+#include "lib/util.h"
+#include "lib/vswitch-idl.h"
+#include "openvswitch/vlog.h"
+#include "ovn/ovn-sb-idl.h"
+#include "ovn-controller.h"
+
+VLOG_DEFINE_THIS_MODULE(chassis);
+
+void
+chassis_init(struct controller_ctx *ctx)
+{
+ ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch);
+ ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_external_ids);
+}
+
+static void
+register_chassis(struct controller_ctx *ctx,
+ const struct sbrec_chassis *chassis_rec,
+ const char *encap_type, const char *encap_ip)
+{
+ struct sbrec_encap *encap_rec;
+ int retval = TXN_TRY_AGAIN;
+ struct ovsdb_idl_txn *txn;
+
+ txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
+ ovsdb_idl_txn_add_comment(txn,
+ "ovn-controller: registering chassis '%s'",
+ ctx->chassis_name);
+
+ if (!chassis_rec) {
+ chassis_rec = sbrec_chassis_insert(txn);
+ sbrec_chassis_set_name(chassis_rec, ctx->chassis_name);
+ }
+
+ encap_rec = sbrec_encap_insert(txn);
+
+ sbrec_encap_set_type(encap_rec, encap_type);
+ sbrec_encap_set_ip(encap_rec, encap_ip);
+
+ sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1);
+
+ retval = ovsdb_idl_txn_commit_block(txn);
+ if (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
+ VLOG_INFO("Problem registering chassis: %s",
+ ovsdb_idl_txn_status_to_string(retval));
+ poll_immediate_wake();
+ }
+ ovsdb_idl_txn_destroy(txn);
+}
+
+void
+chassis_run(struct controller_ctx *ctx)
+{
+ const struct sbrec_chassis *chassis_rec;
+ const struct ovsrec_open_vswitch *cfg;
+ const char *encap_type, *encap_ip;
+ static bool inited = false;
+
+ SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) {
+ if (!strcmp(chassis_rec->name, ctx->chassis_name)) {
+ break;
+ }
+ }
+
+ /* xxx Need to support more than one encap. Also need to support
+ * xxx encap options. */
+ cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
+ if (!cfg) {
+ VLOG_INFO("No Open_vSwitch row defined.");
+ return;
+ }
+
+ encap_type = smap_get(&cfg->external_ids, "ovn-encap-type");
+ encap_ip = smap_get(&cfg->external_ids, "ovn-encap-ip");
+ if (!encap_type || !encap_ip) {
+ VLOG_INFO("Need to specify an encap type and ip");
+ return;
+ }
+
+ if (chassis_rec) {
+ int i;
+
+ for (i = 0; i < chassis_rec->n_encaps; i++) {
+ if (!strcmp(chassis_rec->encaps[i]->type, encap_type)
+ && !strcmp(chassis_rec->encaps[i]->ip, encap_ip)) {
+ /* Nothing changed. */
+ inited = true;
+ return;
+ } else if (!inited) {
+ VLOG_WARN("Chassis config changing on startup, make sure "
+ "multiple chassis are not configured : %s/%s->%s/%s",
+ chassis_rec->encaps[i]->type,
+ chassis_rec->encaps[i]->ip,
+ encap_type, encap_ip);
+ }
+
+ }
+ }
+
+ register_chassis(ctx, chassis_rec, encap_type, encap_ip);
+ inited = true;
+}
+
+void
+chassis_destroy(struct controller_ctx *ctx)
+{
+ int retval = TXN_TRY_AGAIN;
+
+ ovs_assert(ctx->ovnsb_idl);
+
+ while (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
+ const struct sbrec_chassis *chassis_rec;
+ struct ovsdb_idl_txn *txn;
+
+ SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) {
+ if (!strcmp(chassis_rec->name, ctx->chassis_name)) {
+ break;
+ }
+ }
+
+ if (!chassis_rec) {
+ return;
+ }
+
+ txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
+ ovsdb_idl_txn_add_comment(txn,
+ "ovn-controller: unregistering chassis '%s'",
+ ctx->chassis_name);
+ sbrec_chassis_delete(chassis_rec);
+
+ retval = ovsdb_idl_txn_commit_block(txn);
+ if (retval == TXN_ERROR) {
+ VLOG_INFO("Problem unregistering chassis: %s",
+ ovsdb_idl_txn_status_to_string(retval));
+ }
+ ovsdb_idl_txn_destroy(txn);
+ }
+}
diff --git a/ovn/controller/chassis.h b/ovn/controller/chassis.h
new file mode 100644
index 000000000..aee701b7c
--- /dev/null
+++ b/ovn/controller/chassis.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_CHASSIS_H
+#define OVN_CHASSIS_H 1
+
+struct controller_ctx;
+
+void chassis_init(struct controller_ctx *);
+void chassis_run(struct controller_ctx *);
+void chassis_destroy(struct controller_ctx *);
+
+#endif /* ovn/chassis.h */
diff --git a/ovn/controller/ovn-controller.8.xml b/ovn/controller/ovn-controller.8.xml
new file mode 100644
index 000000000..ca7fa4302
--- /dev/null
+++ b/ovn/controller/ovn-controller.8.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manpage program="ovn-controller" section="8" title="ovn-controller">
+ <h1>Name</h1>
+ <p>ovn-controller -- Open Virtual Network local controller</p>
+
+ <h1>Synopsis</h1>
+ <p><code>ovn-controller</code> [<var>options</var>] [<var>ovs-database</var>]</p>
+
+ <h1>Description</h1>
+ <p>
+ <code>ovn-controller</code> is the local controller daemon for
+ OVN, the Open Virtual Network. It connects up to the OVN
+ Southbound database (see <code>ovn-sb</code>(5)) over the OVSDB
+ protocol, and down to the Open vSwitch database (see
+ <code>ovs-vswitchd.conf.db</code>(5)) over the OVSDB protocol and
+ to <code>ovs-vswitchd</code>(8) via OpenFlow. Each hypervisor and
+ software gateway in an OVN deployment runs its own independent
+ copy of <code>ovn-controller</code>; thus,
+ <code>ovn-controller</code>'s downward connections are
+ machine-local and do not run over a physical network.
+ </p>
+
+ <h1>Configuration</h1>
+ <p>
+ <code>ovn-controller</code> retrieves most of its configuration
+ information from the local Open vSwitch's ovsdb-server instance.
+ The default is the <code>db.sock</code> in local Open vSwitch's
+ "run" directory. <var>ovs-database</var> must take one of the
+ following forms:
+ </p>
+ <ul>
+ <li>
+ <p>
+ <code>ssl:<var>ip</var>:<var>port</var></code>
+ </p>
+ <p>
+ The specified SSL <var>port</var> on the host at the given
+ <var>ip</var>, which must be expressed as an IP address (not a DNS
+ name) in IPv4 or IPv6 address format. If <var>ip</var> is an IPv6
+ address, then wrap <var>ip</var> with square brackets, e.g.:
+ <code>ssl:[::1]:6640</code>. The <code>--private-key</code>,
+ <code>--certificate</code>, and <code>--ca-cert</code> options are
+ mandatory when this form is used.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>tcp:<var>ip</var>:<var>port</var></code>
+ </p>
+ <p>
+ Connect to the given TCP <var>port</var> on <var>ip</var>, where
+ <var>ip</var> can be IPv4 or IPv6 address. If <var>ip</var> is an
+ IPv6 address, then wrap <var>ip</var> with square brackets, e.g.:
+ <code>tcp:[::1]:6640</code>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>unix:<var>file</var></code>
+ </p>
+ <p>
+ On POSIX, connect to the Unix domain server socket named
+ <var>file</var>.
+ </p>
+ <p>
+ On Windows, connect to a localhost TCP port whose value is written
+ in <var>file</var>.
+ </p>
+ </li>
+ </ul>
+ <p>
+ <code>ovn-controller</code> assumes it gets configuration
+ information from the following keys in the <code>Open_vSwitch</code>
+ table of the local OVS instance:
+ <ul>
+ <li>
+ <p>
+ <code>external_ids:system-id</code> specifies the chassis
+ name to use in the Chassis table.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>external_ids:ovn-bridge</code> specifies the
+ integration bridge to which logical ports are attached.
+ The default is <code>br-int</code>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>external_ids:ovn-remote</code> specifies the OVN
+ database that this system should connect to for its
+ configuration.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>external_ids:ovn-encap-type</code> specifies the
+ encapsulation type that a chassis should use to connect to
+ this node. Examples include <code>geneve</code>,
+ <code>vxlan</code>, and <code>stt</code>.
+ </p>
+ </li>
+ <li>
+ <p>
+ <code>external_ids:ovn-encap-ip</code> specifies the IP
+ address that a chassis should use to connect to this node
+ using encapsulation type specified by
+ <code>external_ids:ovn-encap-ip</code>.
+ </p>
+ </li>
+ </ul>
+ </p>
+</manpage>
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
new file mode 100644
index 000000000..35ab6ed81
--- /dev/null
+++ b/ovn/controller/ovn-controller.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "command-line.h"
+#include "compiler.h"
+#include "daemon.h"
+#include "dirs.h"
+#include "openvswitch/vconn.h"
+#include "openvswitch/vlog.h"
+#include "ovn/ovn-sb-idl.h"
+#include "poll-loop.h"
+#include "fatal-signal.h"
+#include "lib/vswitch-idl.h"
+#include "smap.h"
+#include "stream.h"
+#include "stream-ssl.h"
+#include "unixctl.h"
+#include "util.h"
+
+#include "ovn-controller.h"
+#include "bindings.h"
+#include "chassis.h"
+
+VLOG_DEFINE_THIS_MODULE(main);
+
+static unixctl_cb_func ovn_controller_exit;
+
+static void parse_options(int argc, char *argv[]);
+OVS_NO_RETURN static void usage(void);
+
+static char *ovs_remote;
+static char *ovnsb_remote;
+
+
+static void
+get_initial_snapshot(struct ovsdb_idl *idl)
+{
+ while (1) {
+ ovsdb_idl_run(idl);
+ if (ovsdb_idl_has_ever_connected(idl)) {
+ return;
+ }
+ ovsdb_idl_wait(idl);
+ poll_block();
+ }
+}
+
+/* Retrieve the OVN remote location from the "external-ids:ovn-remote"
+ * key and the chassis name from the "external-ids:system-id" key in the
+ * Open_vSwitch table of the OVS database instance. */
+static void
+get_core_config(struct controller_ctx *ctx)
+{
+ const struct ovsrec_open_vswitch *cfg;
+
+ cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
+ if (!cfg) {
+ VLOG_ERR("No Open_vSwitch row defined.");
+ ovsdb_idl_destroy(ctx->ovs_idl);
+ exit(EXIT_FAILURE);
+ }
+
+ while (1) {
+ const char *remote, *system_id;
+
+ ovsdb_idl_run(ctx->ovs_idl);
+
+ /* xxx This does not support changing OVN Southbound OVSDB mid-run. */
+ remote = smap_get(&cfg->external_ids, "ovn-remote");
+ if (!remote) {
+ VLOG_INFO("OVN OVSDB remote not specified. Waiting...");
+ goto try_again;
+ }
+
+ system_id = smap_get(&cfg->external_ids, "system-id");
+ if (!system_id) {
+ VLOG_INFO("system-id not specified. Waiting...");
+ goto try_again;
+ }
+
+ ovnsb_remote = xstrdup(remote);
+ ctx->chassis_name = xstrdup(system_id);
+ return;
+
+try_again:
+ ovsdb_idl_wait(ctx->ovs_idl);
+ poll_block();
+ }
+
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct unixctl_server *unixctl;
+ struct controller_ctx ctx = { .chassis_name = NULL };
+ bool exiting;
+ int retval;
+
+ ovs_cmdl_proctitle_init(argc, argv);
+ set_program_name(argv[0]);
+ parse_options(argc, argv);
+ fatal_ignore_sigpipe();
+
+ daemonize_start();
+
+ retval = unixctl_server_create(NULL, &unixctl);
+ if (retval) {
+ exit(EXIT_FAILURE);
+ }
+ unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
+
+ daemonize_complete();
+
+ ovsrec_init();
+ sbrec_init();
+
+ /* Connect to OVS OVSDB instance. We do not monitor all tables by
+ * default, so modules must register their interest explicitly. */
+ ctx.ovs_idl = ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true);
+
+ /* Register interest in "external_ids" column in "Open_vSwitch" table,
+ * since we'll need to get the OVN OVSDB remote. */
+ ovsdb_idl_add_table(ctx.ovs_idl, &ovsrec_table_open_vswitch);
+ ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
+
+ chassis_init(&ctx);
+ bindings_init(&ctx);
+
+ get_initial_snapshot(ctx.ovs_idl);
+
+ get_core_config(&ctx);
+
+ ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
+ true, true);
+
+ get_initial_snapshot(ctx.ovnsb_idl);
+
+ exiting = false;
+ while (!exiting) {
+ ovsdb_idl_run(ctx.ovs_idl);
+ ovsdb_idl_run(ctx.ovnsb_idl);
+
+ if (!ovsdb_idl_is_alive(ctx.ovnsb_idl)) {
+ int retval = ovsdb_idl_get_last_error(ctx.ovnsb_idl);
+ VLOG_ERR("%s: database connection failed (%s)",
+ ovnsb_remote, ovs_retval_to_string(retval));
+ retval = EXIT_FAILURE;
+ break;
+ }
+
+ if (!ovsdb_idl_is_alive(ctx.ovs_idl)) {
+ int retval = ovsdb_idl_get_last_error(ctx.ovs_idl);
+ VLOG_ERR("%s: database connection failed (%s)",
+ ovs_remote, ovs_retval_to_string(retval));
+ retval = EXIT_FAILURE;
+ break;
+ }
+
+ chassis_run(&ctx);
+ bindings_run(&ctx);
+ unixctl_server_run(unixctl);
+
+ unixctl_server_wait(unixctl);
+ if (exiting) {
+ poll_immediate_wake();
+ }
+
+ ovsdb_idl_wait(ctx.ovs_idl);
+ ovsdb_idl_wait(ctx.ovnsb_idl);
+ poll_block();
+ }
+
+ unixctl_server_destroy(unixctl);
+ bindings_destroy(&ctx);
+ chassis_destroy(&ctx);
+
+ ovsdb_idl_destroy(ctx.ovs_idl);
+ ovsdb_idl_destroy(ctx.ovnsb_idl);
+
+ exit(retval);
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+ enum {
+ OPT_PEER_CA_CERT = UCHAR_MAX + 1,
+ VLOG_OPTION_ENUMS,
+ DAEMON_OPTION_ENUMS
+ };
+
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ VLOG_LONG_OPTIONS,
+ DAEMON_LONG_OPTIONS,
+ STREAM_SSL_LONG_OPTIONS,
+ {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
+ {NULL, 0, NULL, 0}
+ };
+ char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
+
+ for (;;) {
+ int c;
+
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'h':
+ usage();
+
+ case 'V':
+ ovs_print_version(OFP13_VERSION, OFP13_VERSION);
+ exit(EXIT_SUCCESS);
+
+ VLOG_OPTION_HANDLERS
+ DAEMON_OPTION_HANDLERS
+ STREAM_SSL_OPTION_HANDLERS
+
+ case OPT_PEER_CA_CERT:
+ stream_ssl_set_peer_ca_cert_file(optarg);
+ break;
+
+ case '?':
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+ free(short_options);
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ ovs_remote = xasprintf("unix:%s/db.sock", ovs_rundir());
+ } else if (argc == 1) {
+ ovs_remote = argv[0];
+ } else {
+ VLOG_FATAL("exactly zero or one non-option argument required; "
+ "use --help for usage");
+ }
+}
+
+static void
+usage(void)
+{
+ printf("%s: OVN controller\n"
+ "usage %s [OPTIONS] [OVS-DATABASE]\n"
+ "where OVS-DATABASE is a socket on which the OVS OVSDB server is listening.\n",
+ program_name, program_name);
+ stream_usage("OVS-DATABASE", true, false, false);
+ daemon_usage();
+ vlog_usage();
+ printf("\nOther options:\n"
+ " -h, --help display this help message\n"
+ " -V, --version display version information\n");
+ exit(EXIT_SUCCESS);
+}
+
+static void
+ovn_controller_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *exiting_)
+{
+ bool *exiting = exiting_;
+ *exiting = true;
+
+ unixctl_command_reply(conn, NULL);
+}
diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h
new file mode 100644
index 000000000..c701edcce
--- /dev/null
+++ b/ovn/controller/ovn-controller.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef OVN_CONTROLLER_H
+#define OVN_CONTROLLER_H 1
+
+struct controller_ctx {
+ char *chassis_name;
+ struct ovsdb_idl *ovnsb_idl;
+ struct ovsdb_idl *ovs_idl;
+};
+
+#endif /* ovn/ovn-controller.h */
diff --git a/ovn/ovn-controller.8.in b/ovn/ovn-controller.8.in
deleted file mode 100644
index 22c18e815..000000000
--- a/ovn/ovn-controller.8.in
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" -*- nroff -*-
-.de IQ
-. br
-. ns
-. IP "\\$1"
-..
-.TH ovn\-controller 8 "@VERSION@" "Open vSwitch" "Open vSwitch Manual"
-.ds PN ovn\-controller
-.
-.SH NAME
-ovn\-controller \- OVN local controller
-.
-.SH SYNOPSIS
-\fBovn\-controller\fR [\fIoptions\fR]
-.
-.SH DESCRIPTION
-\fBovn\-controller\fR is the local controller daemon for OVN, the Open
-Virtual Network. It connects up to the OVN Southbound database (see
-\fBovn\-sb\fR(5)) over the OVSDB protocol, and down to the Open
-vSwitch database (see \fBovs-vswitchd.conf.db\fR(5)) over the OVSDB
-protocol and to \fBovs\-vswitchd\fR(8) via OpenFlow. Each hypervisor
-and software gateway in an OVN deployment runs its own independent
-copy of \fBovn\-controller\fR; thus, \fBovn\-controller\fR's
-southbound connections are machine-local and do not run over a
-physical network.
-.PP
-XXX this is completely skeletal.
-.
-.SH OPTIONS
-.SS "Public Key Infrastructure Options"
-.so lib/ssl.man
-.so lib/ssl-peer-ca-cert.man
-.ds DD
-.so lib/daemon.man
-.so lib/vlog.man
-.so lib/unixctl.man
-.so lib/common.man
-.
-.SH "SEE ALSO"
-.
-\fBovn\-architecture\fR(7)
diff --git a/tutorial/ovs-sandbox b/tutorial/ovs-sandbox
index c299de073..9e8ead004 100755
--- a/tutorial/ovs-sandbox
+++ b/tutorial/ovs-sandbox
@@ -45,6 +45,7 @@ rungdb() {
gdb_vswitchd=false
gdb_ovsdb=false
gdb_ovn_nbd=false
+gdb_ovn_controller=false
builddir=
srcdir=
schema=
@@ -94,6 +95,7 @@ These options force ovs-sandbox to use an installed Open vSwitch:
-g, --gdb-vswitchd run ovs-vswitchd under gdb
-d, --gdb-ovsdb run ovsdb-server under gdb
--gdb-ovn-nbd run ovn-nbd under gdb
+ --gdb-ovn-controller run ovn-controller under gdb
-S, --schema=FILE use FILE as vswitch.ovsschema
-o, --ovn enable OVN
@@ -139,6 +141,9 @@ EOF
--gdb-ovn-nbd)
gdb_ovn_nbd=true
;;
+ --gdb-ovn-controller)
+ gdb_ovn_controller=true
+ ;;
-o|--ovn)
ovn=true
;;
@@ -212,7 +217,7 @@ if $built; then
fi
PATH=$builddir/ovsdb:$builddir/vswitchd:$builddir/utilities:$PATH
if $ovn; then
- PATH=$builddir/ovn:$PATH
+ PATH=$builddir/ovn:$builddir/ovn/controller:$PATH
fi
export PATH
else
@@ -279,7 +284,14 @@ rungdb $gdb_vswitchd ovs-vswitchd --detach --no-chdir --pidfile -vconsole:off --
--enable-dummy=override -vvconn -vnetdev_dummy
if $ovn; then
+ ovs-vsctl set open . external-ids:system-id=56b18105-5706-46ef-80c4-ff20979ab068
+ ovs-vsctl set open . external-ids:ovn-remote=unix:"$sandbox"/db.sock
+ ovs-vsctl set open . external-ids:ovn-encap-type=vxlan
+ ovs-vsctl set open . external-ids:ovn-encap-ip=127.0.0.1
+ ovs-vsctl add-br br-int
+
rungdb $gdb_ovn_nbd ovn-nbd --detach --no-chdir --pidfile -vconsole:off --log-file
+ rungdb $gdb_ovn_controller ovn-controller --detach --no-chdir --pidfile -vconsole:off --log-file
fi
cat <<EOF