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> --- ovn/.gitignore | 2 + ovn/TODO | 19 --- ovn/automake.mk | 16 ++- ovn/bindings.c | 181 ++++++++++++++++++++++++++++ ovn/bindings.h | 26 ++++ ovn/chassis.c | 153 ++++++++++++++++++++++++ ovn/chassis.h | 25 ++++ ovn/ovn-controller.8.in | 41 ------- ovn/ovn-controller.8.xml | 122 +++++++++++++++++++ ovn/ovn-controller.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 821 insertions(+), 62 deletions(-) create mode 100644 ovn/bindings.c create mode 100644 ovn/bindings.h create mode 100644 ovn/chassis.c create mode 100644 ovn/chassis.h delete mode 100644 ovn/ovn-controller.8.in create mode 100644 ovn/ovn-controller.8.xml create mode 100644 ovn/ovn-controller.c diff --git a/ovn/.gitignore b/ovn/.gitignore index e354a82..a130e5b 100644 --- a/ovn/.gitignore +++ b/ovn/.gitignore @@ -1,7 +1,9 @@ /ovn.5 /ovn.gv +/ovn.ovsidl /ovn.pic /ovn-architecture.7 +/ovn-controller /ovn-controller.8 /ovn-idl.c /ovn-idl.h diff --git a/ovn/TODO b/ovn/TODO index 43a867c..9142d73 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 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 426e547..b37fe2c 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 @@ -127,3 +127,15 @@ ovn_ovn_nbctl_LDADD = ovn/libovn.la ovsdb/libovsdb.la lib/libopenvswitch.la bin_PROGRAMS += ovn/ovn-nbd ovn_ovn_nbd_SOURCES = ovn/ovn-nbd.c ovn_ovn_nbd_LDADD = ovn/libovn.la ovsdb/libovsdb.la lib/libopenvswitch.la + +# ovn-controller +bin_PROGRAMS += ovn/ovn-controller +ovn_ovn_controller_SOURCES = \ + ovn/bindings.c \ + ovn/bindings.h \ + ovn/chassis.c \ + ovn/chassis.h \ + ovn/ovn-controller.c +ovn_ovn_controller_LDADD = ovn/libovn.la lib/libopenvswitch.la +man_MANS += ovn/ovn-controller.8 +EXTRA_DIST += ovn/ovn-controller.8.xml diff --git a/ovn/bindings.c b/ovn/bindings.c new file mode 100644 index 0000000..79a19cf --- /dev/null +++ b/ovn/bindings.c @@ -0,0 +1,181 @@ +/* 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 "openvswitch/vlog.h" +#include "lib/svec.h" +#include "lib/vswitch-idl.h" +#include "ovn/ovn-idl.h" +#include "bindings.h" + +VLOG_DEFINE_THIS_MODULE(bindings); + +extern char *chassis_name; + +void +bindings_init(struct ovsdb_idl *ovs_idl OVS_UNUSED) +{ + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_bridges); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge); + ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_name); + ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_ports); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_port); + ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_name); + ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_interfaces); + + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface); + ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name); + ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_external_ids); +} + +static void +mod_binding(const struct ovnrec_bindings *bindings_rec, bool add, + struct ovsdb_idl *ovn_idl) +{ + struct ovsdb_idl_txn *txn; + int retval; + + txn = ovsdb_idl_txn_create(ovn_idl); + ovsdb_idl_txn_add_comment(txn, "ovn-controller: %s lport '%s' to '%s'", + add ? "registering" : "unregistering", + bindings_rec->logical_port, chassis_name); + + /* xxx Unclear if ovn-controller or ovn-nbd should be setting + * xxx "mac". */ + ovnrec_bindings_set_chassis(bindings_rec, add ? chassis_name : ""); + + retval = ovsdb_idl_txn_commit_block(txn); + if (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) { + VLOG_INFO("Problem committing bindings information: %s", + ovsdb_idl_txn_status_to_string(retval)); + } + ovsdb_idl_txn_destroy(txn); +} + +static void +add_binding(const struct ovnrec_bindings *bindings_rec, + struct ovsdb_idl *ovn_idl) +{ + mod_binding(bindings_rec, true, ovn_idl); +} + +static void +del_binding(const struct ovnrec_bindings *bindings_rec, + struct ovsdb_idl *ovn_idl) +{ + mod_binding(bindings_rec, false, ovn_idl); +} + +static void +get_local_iface_ids(struct svec *lports, struct ovsdb_idl *ovs_idl) +{ + const struct ovsrec_open_vswitch *cfg; + const struct ovsrec_bridge *bridge_rec; + const char *bridge_name; + int i; + + cfg = ovsrec_open_vswitch_first(ovs_idl); + + bridge_name = smap_get(&cfg->external_ids, "ovn-bridge"); + if (!bridge_name) { + VLOG_INFO_ONCE("Need to specify the integration bridge"); + return; + } + + OVSREC_BRIDGE_FOR_EACH(bridge_rec, 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; + } + svec_add(lports, iface_id); + } + } + + svec_sort(lports); +} + +void +bindings_run(struct ovsdb_idl *ovn_idl OVS_UNUSED, struct ovsdb_idl *ovs_idl) +{ + const struct ovnrec_bindings *bindings_rec; + struct svec lports; + const char *name; + int i; + + svec_init(&lports); + get_local_iface_ids(&lports, ovs_idl); + + OVNREC_BINDINGS_FOR_EACH(bindings_rec, ovn_idl) { + if (svec_contains(&lports, bindings_rec->logical_port)) { + svec_del(&lports, bindings_rec->logical_port); + + if (!strcmp(bindings_rec->chassis, chassis_name)) { + continue; + } + if (strlen(bindings_rec->chassis)) { + VLOG_INFO("Changing chassis for lport %s from %s to %s", + bindings_rec->logical_port, bindings_rec->chassis, + chassis_name); + } + add_binding(bindings_rec, ovn_idl); + } else if (!strcmp(bindings_rec->chassis, chassis_name)) { + del_binding(bindings_rec, ovn_idl); + } + } + SVEC_FOR_EACH (i, name, &lports) { + VLOG_DBG("No binding record for lport %s", name); + } + svec_destroy(&lports); +} + +void +bindings_destroy(struct ovsdb_idl *ovn_idl) +{ + const struct ovnrec_bindings *bindings_rec; + + OVNREC_BINDINGS_FOR_EACH(bindings_rec, ovn_idl) { + if (!strcmp(bindings_rec->chassis, chassis_name)) { + del_binding(bindings_rec, ovn_idl); + } + } +} diff --git a/ovn/bindings.h b/ovn/bindings.h new file mode 100644 index 0000000..ae97ee5 --- /dev/null +++ b/ovn/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 ovsdb_idl; + +void bindings_init(struct ovsdb_idl *ovs_idl); +void bindings_run(struct ovsdb_idl *ovn_idl, struct ovsdb_idl *ovs_idl); +void bindings_destroy(struct ovsdb_idl *ovn_idl); + +#endif /* ovn/bindings.h */ diff --git a/ovn/chassis.c b/ovn/chassis.c new file mode 100644 index 0000000..370d2ac --- /dev/null +++ b/ovn/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 <string.h> +#include <stdio.h> + +#include "openvswitch/vlog.h" +#include "lib/vswitch-idl.h" +#include "ovn/ovn-idl.h" +#include "compiler.h" +#include "chassis.h" + +VLOG_DEFINE_THIS_MODULE(chassis); + +extern char *chassis_name; + +void +chassis_init(struct ovsdb_idl *ovs_idl) +{ + ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids); +} + +static void +register_chassis(const struct ovnrec_chassis *chassis_rec, + const char *encap_type, const char *encap_ip, + struct ovsdb_idl *ovn_idl) +{ + struct ovnrec_encap **encap_recs; + struct ovnrec_encap *encap_rec; + struct ovsdb_idl_txn *txn; + int n_encaps = 1; + int retval; + + txn = ovsdb_idl_txn_create(ovn_idl); + ovsdb_idl_txn_add_comment(txn, + "ovn-controller: registering chassis '%s'", + chassis_name); + + if (!chassis_rec) { + chassis_rec = ovnrec_chassis_insert(txn); + ovnrec_chassis_set_name(chassis_rec, chassis_name); + } + + encap_rec = ovnrec_encap_insert(txn); + + ovnrec_encap_set_type(encap_rec, encap_type); + ovnrec_encap_set_ip(encap_rec, encap_ip); + + encap_recs = xmalloc(sizeof *encap_rec * n_encaps); + encap_recs[0] = encap_rec; + + ovnrec_chassis_set_encaps(chassis_rec, encap_recs, 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 ovsdb_idl *ovn_idl, struct ovsdb_idl *ovs_idl) +{ + const struct ovnrec_chassis *chassis_rec; + const struct ovsrec_open_vswitch *cfg; + const char *encap_type, *encap_ip; + static bool inited = false; + + OVNREC_CHASSIS_FOR_EACH(chassis_rec, ovn_idl) { + if (!strcmp(chassis_rec->name, chassis_name)) { + break; + } + } + + /* xxx Need to support more than one encap. Also need to support + * xxx encap options. */ + cfg = ovsrec_open_vswitch_first(ovs_idl); + 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(chassis_rec, encap_type, encap_ip, ovn_idl); + inited = true; +} + +void +chassis_destroy(struct ovsdb_idl *ovn_idl) +{ + const struct ovnrec_chassis *chassis_rec; + struct ovsdb_idl_txn *txn; + int retval; + + OVNREC_CHASSIS_FOR_EACH(chassis_rec, ovn_idl) { + if (!strcmp(chassis_rec->name, chassis_name)) { + break; + } + } + + if (!chassis_rec) { + return; + } + + txn = ovsdb_idl_txn_create(ovn_idl); + ovsdb_idl_txn_add_comment(txn, + "ovn-controller: unregistering chassis '%s'", + chassis_name); + ovnrec_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/chassis.h b/ovn/chassis.h new file mode 100644 index 0000000..acd9af0 --- /dev/null +++ b/ovn/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 ovsdb_idl; + +void chassis_init(struct ovsdb_idl *ovs_idl); +void chassis_run(struct ovsdb_idl *ovn_idl, struct ovsdb_idl *ovs_idl); +void chassis_destroy(struct ovsdb_idl *ovn_idl); + +#endif /* ovn/chassis.h */ diff --git a/ovn/ovn-controller.8.in b/ovn/ovn-controller.8.in deleted file mode 100644 index 59fcb59..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 northbound to the OVN database (see -\fBovn\fR(5)) over the OVSDB protocol, and southbound 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/ovn/ovn-controller.8.xml b/ovn/ovn-controller.8.xml new file mode 100644 index 0000000..54b4dc5 --- /dev/null +++ b/ovn/ovn-controller.8.xml @@ -0,0 +1,122 @@ +<?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>Synopsys</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 <code>unix:@RUNDIR@/db.sock</code>. + OVS-DATABASE 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. + </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> + + <h1>Options</h1> + <p><code>-h</code> | <code>--help</code></p> + <p><code>-V</code> | <code>--version</code></p> + + <h1>Logging options</h1> + <p><code>-v</code><var>spec</var>, <code>--verbose=</code><var>spec</var></p> + <p><code>-v</code>, <code>--verbose</code></p> + <p><code>--log-file</code>[<code>=</code><var>file</var>]</p> + <p><code>--syslog-target=</code><var>host</var><code>:</code><var>port</var></p> +</manpage> diff --git a/ovn/ovn-controller.c b/ovn/ovn-controller.c new file mode 100644 index 0000000..27ee435 --- /dev/null +++ b/ovn/ovn-controller.c @@ -0,0 +1,298 @@ +/* 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 "poll-loop.h" +#include "fatal-signal.h" +#include "smap.h" +#include "stream.h" +#include "stream-ssl.h" +#include "unixctl.h" +#include "util.h" +#include "openvswitch/vconn.h" +#include "openvswitch/vlog.h" +#include "lib/vswitch-idl.h" +#include "ovn/ovn-idl.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; +char *chassis_name; + + +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 ovsdb_idl *ovs_idl) +{ + const struct ovsrec_open_vswitch *cfg; + + cfg = ovsrec_open_vswitch_first(ovs_idl); + + while (1) { + const char *remote, *system_id; + + ovsdb_idl_run(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); + chassis_name = xstrdup(system_id); + return; + +try_again: + ovsdb_idl_wait(ovs_idl); + poll_block(); + } + +} + +int +main(int argc, char *argv[]) +{ + struct unixctl_server *unixctl; + bool exiting; + int retval; + struct ovsdb_idl *ovn_idl; + struct ovsdb_idl *ovs_idl; + + 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(); + ovnrec_init(); + + /* Connect to OVS OVSDB instance. We do not monitor any tables or + * columns be default, so modules must register their interest + * explicitly. */ + 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(ovs_idl, &ovsrec_table_open_vswitch); + ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids); + + chassis_init(ovs_idl); + bindings_init(ovs_idl); + + get_initial_snapshot(ovs_idl); + + get_core_config(ovs_idl); + + ovn_idl = ovsdb_idl_create(ovn_remote, &ovnrec_idl_class, true, true); + + get_initial_snapshot(ovn_idl); + + exiting = false; + while (!exiting) { + ovsdb_idl_run(ovs_idl); + ovsdb_idl_run(ovn_idl); + + if (!ovsdb_idl_is_alive(ovn_idl)) { + int retval = ovsdb_idl_get_last_error(ovn_idl); + VLOG_ERR("%s: database connection failed (%s)", + ovn_remote, ovs_retval_to_string(retval)); + retval = EXIT_FAILURE; + break; + } + + if (!ovsdb_idl_is_alive(ovs_idl)) { + int retval = ovsdb_idl_get_last_error(ovs_idl); + VLOG_ERR("%s: database connection failed (%s)", + ovs_remote, ovs_retval_to_string(retval)); + retval = EXIT_FAILURE; + break; + } + + chassis_run(ovn_idl, ovs_idl); + bindings_run(ovn_idl, ovs_idl); + unixctl_server_run(unixctl); + + unixctl_server_wait(unixctl); + if (exiting) { + poll_immediate_wake(); + } + + ovsdb_idl_wait(ovs_idl); + ovsdb_idl_wait(ovn_idl); + poll_block(); + } + + unixctl_server_destroy(unixctl); + bindings_destroy(ovn_idl); + chassis_destroy(ovn_idl); + + ovsdb_idl_destroy(ovs_idl); + ovsdb_idl_destroy(ovn_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(OFP10_VERSION, OFP10_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 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); +} -- 1.7.5.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev