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 <jpet...@nicira.com> --- v1->v2: Feedback from Ben. --- Makefile.am | 1 + ovn/.gitignore | 1 - ovn/TODO | 19 --- ovn/automake.mk | 4 +- ovn/controller/.gitignore | 2 + ovn/controller/automake.mk | 11 ++ ovn/controller/bindings.c | 175 ++++++++++++++++++++ ovn/controller/bindings.h | 26 +++ ovn/controller/chassis.c | 153 ++++++++++++++++++ ovn/controller/chassis.h | 25 +++ ovn/controller/ovn-controller.8.xml | 115 +++++++++++++ ovn/controller/ovn-controller.c | 303 +++++++++++++++++++++++++++++++++++ ovn/controller/ovn-controller.h | 26 +++ ovn/ovn-controller.8.in | 41 ----- tutorial/ovs-sandbox | 14 ++- 15 files changed, 852 insertions(+), 64 deletions(-) create mode 100644 ovn/controller/.gitignore create mode 100644 ovn/controller/automake.mk create mode 100644 ovn/controller/bindings.c create mode 100644 ovn/controller/bindings.h create mode 100644 ovn/controller/chassis.c create mode 100644 ovn/controller/chassis.h create mode 100644 ovn/controller/ovn-controller.8.xml create mode 100644 ovn/controller/ovn-controller.c create mode 100644 ovn/controller/ovn-controller.h delete mode 100644 ovn/ovn-controller.8.in diff --git a/Makefile.am b/Makefile.am index 699a580..16d8e8d 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 9ddcbb8..cbd65a1 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 7bd89df..7a22606 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 180352e..6388fdc 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 0000000..4199a37 --- /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 0000000..7274cbd --- /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 0000000..1beb8ed --- /dev/null +++ b/ovn/controller/bindings.c @@ -0,0 +1,175 @@ +/* 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/vswitch-idl.h" +#include "openvswitch/vlog.h" +#include "ovn/ovn-sb-idl.h" +#include "ovn-controller.h" + +VLOG_DEFINE_THIS_MODULE(bindings); + +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); + + bridge_name = smap_get(&cfg->external_ids, "ovn-bridge"); + if (!bridge_name) { + bridge_name = "br-int"; + } + + 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_contains(&lports, bindings_rec->logical_port)) { + 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) +{ + const struct sbrec_bindings *bindings_rec; + struct ovsdb_idl_txn *txn; + int retval = TXN_TRY_AGAIN; + + if (!ctx->ovnsb_idl) { + return; + } + + while (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) { + 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 committing bindings information: %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 0000000..07681cd --- /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 0000000..8fa2624 --- /dev/null +++ b/ovn/controller/chassis.c @@ -0,0 +1,153 @@ +/* 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/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; + struct ovsdb_idl_txn *txn; + int retval; + + 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 committing chassis information: %s", + ovsdb_idl_txn_status_to_string(retval)); + } + 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) +{ + const struct sbrec_chassis *chassis_rec; + struct ovsdb_idl_txn *txn; + int retval; + + if (!ctx->ovnsb_idl) { + return; + } + + 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_SUCCESS && retval != TXN_UNCHANGED) { + VLOG_INFO("Problem committing chassis information: %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 0000000..aee701b --- /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 0000000..d172c08 --- /dev/null +++ b/ovn/controller/ovn-controller.8.xml @@ -0,0 +1,115 @@ +<?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 northbound to the OVN + database (see <code>ovn</code>(5)) over the OVSDB protocol, and + southbound 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 southbound 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> +.so lib/vlog-unixctl.man +</manpage> diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c new file mode 100644 index 0000000..d76af0b --- /dev/null +++ b/ovn/controller/ovn-controller.c @@ -0,0 +1,303 @@ +/* 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 "dummy.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 *ovn_remote; + + +static void +get_initial_snapshot(struct ovsdb_idl *idl) +{ + while (1) { + ovsdb_idl_run(idl); + if (ovsdb_idl_get_seqno(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 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; + } + + ovn_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; + bool exiting; + int retval; + + ovs_cmdl_proctitle_init(argc, argv); + set_program_name(argv[0]); + parse_options(argc, argv); + fatal_ignore_sigpipe(); + + daemonize_start(); + + memset(&ctx, '\0', sizeof ctx); + + 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 any tables or + * columns be 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(ovn_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)", + ovn_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); + + return retval; +} + +static void +parse_options(int argc, char *argv[]) +{ + enum { + OPT_PEER_CA_CERT = UCHAR_MAX + 1, + VLOG_OPTION_ENUMS, + DAEMON_OPTION_ENUMS, + OPT_ENABLE_DUMMY + }; + + 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}, + {"enable-dummy", no_argument, NULL, OPT_ENABLE_DUMMY}, + {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 OPT_ENABLE_DUMMY: + timeval_dummy_register(); + 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 0000000..c701edc --- /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 22c18e8..0000000 --- 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 c299de0..9e8ead0 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 -- 1.7.5.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev