vswitchd: Initial conversion to database-based configuration.
authorBen Pfaff <blp@nicira.com>
Thu, 3 Dec 2009 19:28:40 +0000 (11:28 -0800)
committerBen Pfaff <blp@nicira.com>
Thu, 3 Dec 2009 19:28:40 +0000 (11:28 -0800)
This has seen very little testing, so some features are almost certainly
busted.  Port mirroring is not yet converted, so it will definitely not
work.

24 files changed:
++WARNING++ [new file with mode: 0644]
Makefile.am
lib/automake.mk
lib/packets.c
lib/packets.h
lib/shash.c
lib/shash.h
ofproto/netflow.c
ofproto/ofproto.c
utilities/.gitignore
utilities/automake.mk
utilities/ovs-cfg-mod.8.in [deleted file]
utilities/ovs-cfg-mod.c [deleted file]
utilities/ovs-openflowd.c
vswitchd/automake.mk
vswitchd/bridge.c
vswitchd/bridge.h
vswitchd/mgmt.c [deleted file]
vswitchd/mgmt.h [deleted file]
vswitchd/ovs-vswitchd.8.in
vswitchd/ovs-vswitchd.c
vswitchd/ovs-vswitchd.conf.5.in [deleted file]
vswitchd/ovs-vswitchd.h [deleted file]
vswitchd/vswitch-idl.ovsidl

diff --git a/++WARNING++ b/++WARNING++
new file mode 100644 (file)
index 0000000..d8b05ea
--- /dev/null
@@ -0,0 +1,5 @@
+This version of Open vSwitch is in the middle of a transition from
+using the ovs-vswitchd.conf configuration file to database-based
+configuration.  Many features are known to be broken, so please do not
+use this version of Open vSwitch if you expect it to be working
+stably.
index 164ca3e1a3433821579da188ceff31bb9dfd4a34..5888e85f57d00689ad0757c7e05e411f889fe2a7 100644 (file)
@@ -34,7 +34,8 @@ EXTRA_DIST = INSTALL.bridge \
        INSTALL.OpenFlow \
        INSTALL.SSL \
        INSTALL.XenServer \
-       README-gcov
+       README-gcov \
+       ++WARNING++
 bin_PROGRAMS =
 sbin_PROGRAMS =
 bin_SCRIPTS =
index ee5a1956d4a5ff1cd860b6de594b76494b35b1ee..f216b3fb795bd6cc86ffa26bfebb0063fbe3f70a 100644 (file)
@@ -235,7 +235,6 @@ COVERAGE_FILES = \
        ofproto/ofproto.c \
        ofproto/pktbuf.c \
        vswitchd/bridge.c \
-       vswitchd/mgmt.c \
        vswitchd/ovs-brcompatd.c
 lib/coverage-counters.c: $(COVERAGE_FILES) lib/coverage-scan.pl
        (cd $(srcdir) && $(PERL) lib/coverage-scan.pl $(COVERAGE_FILES)) > $@.tmp
index 0547791ab653d86a8812306a8c27ab948f521dc8..29c4e7e4a9e3a9bd9820d69fb9afb84f5d6ee8bb 100644 (file)
 #include <config.h>
 #include "packets.h"
 #include <netinet/in.h>
+#include <stdlib.h>
 #include "ofpbuf.h"
 
+bool
+dpid_from_string(const char *s, uint64_t *dpidp)
+{
+    *dpidp = (strlen(s) == 12 && strspn(s, "0123456789abcdefABCDEF") == 12
+              ? strtoll(s, NULL, 16)
+              : 0);
+    return *dpidp != 0;
+}
+
+bool
+eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN])
+{
+    if (sscanf(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))
+        == ETH_ADDR_SCAN_COUNT) {
+        return true;
+    } else {
+        memset(ea, 0, ETH_ADDR_LEN);
+        return false;
+    }
+}
+
 /* Fills 'b' with an 802.2 SNAP packet with Ethernet source address 'eth_src',
  * the Nicira OUI as SNAP organization and 'snap_type' as SNAP type.  The text
  * string in 'tag' is enclosed as the packet payload.
index 4595c12cba74ec492944c895c7d43f0f12274587..83bdb6b57c2427701f0c48c80f4a030c2108a68a 100644 (file)
@@ -26,6 +26,8 @@
 
 struct ofpbuf;
 
+bool dpid_from_string(const char *s, uint64_t *dpidp);
+
 #define ETH_ADDR_LEN           6
 
 static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] UNUSED
@@ -101,6 +103,8 @@ static inline bool eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
             && (ea[5] & 0xf0) == 0x00);
 }
 
+bool eth_addr_from_string(const char *, uint8_t ea[ETH_ADDR_LEN]);
+
 void compose_benign_packet(struct ofpbuf *, const char *tag,
                            uint16_t snap_type,
                            const uint8_t eth_src[ETH_ADDR_LEN]);
index e6cb6b0db8eccfe4cad50c7b7076b9bd1cbc7192..5257de12aad4c4df7acb03809224e1e0bdd70e0c 100644 (file)
@@ -76,6 +76,17 @@ shash_add(struct shash *sh, const char *name, const void *data)
     return node;
 }
 
+bool
+shash_add_once(struct shash *sh, const char *name, const void *data)
+{
+    if (!shash_find(sh, name)) {
+        shash_add(sh, name, data);
+        return true;
+    } else {
+        return false;
+    }
+}
+
 void
 shash_delete(struct shash *sh, struct shash_node *node)
 {
index 236d865ed09c5df65411f500e8dc3114a3ca0f9f..8efdde1b9ef0d6b2ab409066af71a5c65c616edb 100644 (file)
@@ -44,6 +44,7 @@ void shash_clear(struct shash *);
 bool shash_is_empty(const struct shash *);
 size_t shash_count(const struct shash *);
 struct shash_node *shash_add(struct shash *, const char *, const void *);
+bool shash_add_once(struct shash *, const char *, const void *);
 void shash_delete(struct shash *, struct shash_node *);
 struct shash_node *shash_find(const struct shash *, const char *);
 void *shash_find_data(const struct shash *, const char *);
index 7c77c64ff2ff0019a9ac5766e77defc2bdce681b..2c7ae9e43ec564367c60beaacabd0062fff29b28 100644 (file)
@@ -20,7 +20,6 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include "cfg.h"
 #include "collectors.h"
 #include "flow.h"
 #include "netflow.h"
@@ -211,7 +210,7 @@ netflow_set_options(struct netflow *nf,
     collectors_create(&nf_options->collectors, 0, &nf->collectors);
 
     old_timeout = nf->active_timeout;
-    if (nf_options->active_timeout != -1) {
+    if (nf_options->active_timeout < 0) {
         nf->active_timeout = nf_options->active_timeout;
     } else {
         nf->active_timeout = ACTIVE_TIMEOUT_DEFAULT;
index 60e1828ebe0ac0370554d0b88e979846ea2178f3..09388ba2fda418a8b29e1acdcdc0e76e18712ec0 100644 (file)
@@ -536,7 +536,7 @@ int
 ofproto_set_netflow(struct ofproto *ofproto,
                     const struct netflow_options *nf_options)
 {
-    if (nf_options->collectors.n) {
+    if (nf_options && nf_options->collectors.n) {
         if (!ofproto->netflow) {
             ofproto->netflow = netflow_create();
         }
index ebbd69167f420966824fc820221768406f7cc6bc..55139d7047d9200d0e1257c11c4bce774ccf3a27 100644 (file)
@@ -3,8 +3,6 @@
 /nlmon
 /ovs-appctl
 /ovs-appctl.8
-/ovs-cfg-mod
-/ovs-cfg-mod.8
 /ovs-controller
 /ovs-controller.8
 /ovs-discover
index 9ac12c92470344f983fe7acd1b75f909b737794b..2c57da02aac47b0a2c4ded9d875edf9ac8865927 100644 (file)
@@ -1,6 +1,5 @@
 bin_PROGRAMS += \
        utilities/ovs-appctl \
-       utilities/ovs-cfg-mod \
        utilities/ovs-controller \
        utilities/ovs-discover \
        utilities/ovs-dpctl \
@@ -15,7 +14,6 @@ dist_sbin_SCRIPTS += utilities/ovs-monitor
 
 EXTRA_DIST += \
        utilities/ovs-appctl.8.in \
-       utilities/ovs-cfg-mod.8.in \
        utilities/ovs-controller.8.in \
        utilities/ovs-discover.8.in \
        utilities/ovs-dpctl.8.in \
@@ -30,7 +28,6 @@ EXTRA_DIST += \
        utilities/ovs-vsctl.in
 DISTCLEANFILES += \
        utilities/ovs-appctl.8 \
-       utilities/ovs-cfg-mod.8 \
        utilities/ovs-controller.8 \
        utilities/ovs-discover.8 \
        utilities/ovs-dpctl.8 \
@@ -46,7 +43,6 @@ DISTCLEANFILES += \
 
 man_MANS += \
        utilities/ovs-appctl.8 \
-       utilities/ovs-cfg-mod.8 \
        utilities/ovs-controller.8 \
        utilities/ovs-discover.8 \
        utilities/ovs-dpctl.8 \
@@ -59,9 +55,6 @@ man_MANS += \
 utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c
 utilities_ovs_appctl_LDADD = lib/libopenvswitch.a
 
-utilities_ovs_cfg_mod_SOURCES = utilities/ovs-cfg-mod.c
-utilities_ovs_cfg_mod_LDADD = lib/libopenvswitch.a
-
 utilities_ovs_controller_SOURCES = utilities/ovs-controller.c
 utilities_ovs_controller_LDADD = lib/libopenvswitch.a $(FAULT_LIBS) $(SSL_LIBS)
 
diff --git a/utilities/ovs-cfg-mod.8.in b/utilities/ovs-cfg-mod.8.in
deleted file mode 100644 (file)
index 5b96f28..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-.\" -*- nroff -*-
-.de IQ
-.  br
-.  ns
-.  IP "\\$1"
-..
-.TH ovs\-cfg\-mod 8 "June 2009" "Open vSwitch" "Open vSwitch Manual"
-.ds PN ovs\-cfg\-mod
-.
-.SH NAME
-ovs\-cfg\-mod \- Safely manage a ovs\-vswitchd.conf\-style configuration file
-.
-.SH SYNOPSIS
-\fB ovs\-cfg\-mod \fR[\fB\-T \fItimeout\fR] \fB\-F \fIfile\fR
-[\fIaction\fR] [\fIaction\fR...\fR]
-.
-.SH DESCRIPTION
-A program for managing a \fovs\-vswitchd.conf\fR(5)\-style configuration
-file.  \fBovs\-cfg\-mod\fR uses the same locking mechanisms as
-\fBovs\-vswitchd\fR and its related utilities.  This allows it to be
-run safely on ``live'' configurations.
-.
-.SH OPTIONS
-.SS "Specifying the Configuration File"
-.
-.IP "\fB\-T\fR \fItimeout\fR
-.IQ "\fB\-\-timeout=\fItimeout\fR
-By default, \fBovs\-cfg\-mod\fR will wait forever to lock the
-configuration file specified on \fB\-F\fR or \fB\-\-config\-file\fR.  This
-option makes \fBovs\-cfg\-mod\fR wait no more than \fItimeout\fR
-milliseconds to obtain the lock, after which it exits unsuccessfully.
-.
-If it is present, this option must be specified before \fB\-F\fR or
-\fB\-\-config\-file\fR.
-.
-.IP "\fB\-F\fR \fIfile\fR"
-.IQ "\fB\-\-config\-file=\fIfile\fR"
-Use \fIfile\fR as the configuration file to query or modify.
-.
-This option is required.  It must be specified before any action
-options.
-.
-.SS "Specifying Actions"
-A series of one or more action options may follow the configuration
-file options.  These are executed in the order provided and under a
-single lock instance, so they appear atomic to external viewers of
-\fIfile\fR.
-.
-As discussed in \fBovs\-vswitchd.conf\fR(5), each line in the
-configuration file consists of a key\-value pair.  Actions generally
-take either a \fIkey\fR or \fIentry\fR argument.  A \fIkey\fR is a
-dot\-separated description of a configuration option.  A \fIentry\fR is
-a key\-value pair, separated by the \fB=\fR sign.
-.
-The following actions are supported:
-.
-.IP "\fB\-a\fR \fIentry\fR"
-.IQ "\fB\-\-add=\fIentry\fR"
-Add \fIentry\fR to \fIfile\fR.  Please note that duplicates are
-allowed, so if a unique key is required, a delete must be done first.
-.
-.IP "\fB\-d\fR \fIentry\fR"
-.IQ "\fB\-\-del\-entry=\fIentry\fR"
-Delete \fIentry\fR from \fIfile\fR.  Deletes only the first entry 
-that matches \fIentry\fR.  
-.
-.IP "\fB\-D\fR \fIkey\fR"
-.IQ "\fB\-\-del\-section=\fIkey\fR"
-Delete section \fIkey\fR from \fIfile\fR.  
-.
-.IP "\fB\-\-del\-match=\fIpattern\fR"
-Deletes every entry that matches the given shell glob \fIpattern\fR.
-For example, \fB\-\-del\-match=bridge.*.port=*\fR deletes all the ports
-from every bridge, and \fB\-\-del\-match=bonding.bond0.*\fR is equivalent
-to \fB\-\-del\-section=bonding.bond0\fR.
-.
-.IP "\fB\-q\fR \fIkey\fR"
-.IQ "\fB\-\-query=\fIkey\fR"
-Queries \fIfile\fR for entries that match \fIkey\fR.  Each matching
-value is printed on a separate line.  Duplicates will be printed
-multiple times.  
-.
-.IP "\fB\-c\fR"
-.IQ "\fB\-\-changes\fR"
-Logs all of the changes made to the configuration file in a ``unified
-diff''\-like format.  Only actual changes are logged, so that if, for
-example, a \fB\-\-del\-match\fR action did not match any key\-value pairs,
-then nothing will be logged due to that action.  Furthermore, only the
-net effects of changes are logged: if a key\-value pair was deleted and
-then an identical key\-value pair was added back, then nothing would be
-logged due to those changes.
-.
-This action logs changes that have taken effect at the point where it
-is inserted.  Thus, if it is given before any other action, it will
-not log any changes.  If \fB\-\-changes\fR is given more than once,
-instances after the first log only the changes since the previous
-instance.
-.
-.SH "SEE ALSO"
-.BR ovs\-vswitchd (8),
-.BR ovs\-vswitchd.conf (5)
diff --git a/utilities/ovs-cfg-mod.c b/utilities/ovs-cfg-mod.c
deleted file mode 100644 (file)
index 1b52a7b..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* Copyright (c) 2008, 2009  Nicira Networks
- *
- * 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 <dirent.h>
-#include <errno.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "cfg.h"
-#include "command-line.h"
-#include "svec.h"
-#include "timeval.h"
-#include "util.h"
-
-#define THIS_MODULE VLM_cfg_mod
-#include "vlog.h"
-
-/* Configuration when we first read the configuration file. */
-static struct svec orig_cfg = SVEC_EMPTY_INITIALIZER;
-
-static void
-usage(char *prog_name, int exit_code)
-{
-    printf("Usage: %s --config-file=FILE ACTIONS\n"
-           "\nConfig:\n"
-           "  -T, --timeout=MS        wait at most MS milliseconds for lock\n"
-           "  -F, --config-file=FILE  use configuration FILE\n"
-           "\nActions:\n"
-           "  -a, --add=ENTRY         add ENTRY\n"
-           "  -d, --del-entry=ENTRY   delete ENTRY\n"
-           "  -D, --del-section=KEY   delete section matching KEY\n"
-           "  --del-match=PATTERN     delete entries matching shell PATTERN\n"
-           "  -q, --query=KEY         return all entries matching KEY\n"
-           "  -c, --log-changes       log changes up to this point\n"
-           "\nOther options:\n"
-           "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n",
-           prog_name);
-    exit(exit_code);
-}
-
-static void 
-open_config(char *config_file, int timeout) 
-{
-    int error;
-
-    cfg_init();
-    error = cfg_set_file(config_file);
-    if (error) {
-        ovs_fatal(error, "failed to add configuration file \"%s\"",
-                config_file);
-    }
-
-    error = cfg_lock(NULL, timeout);
-    if (error) {
-        ovs_fatal(error, "could not lock configuration file\n");
-    }
-
-    cfg_get_all(&orig_cfg);
-}
-
-static void
-print_vals(char *key)
-{
-    struct svec vals;
-    int i;
-
-    svec_init(&vals);
-    cfg_get_all_strings(&vals, "%s", key);
-
-    for (i=0; i<vals.n; i++) {
-        printf("%s\n", vals.names[i]);
-    }
-}
-
-static void
-log_diffs(void)
-{
-    struct svec new_cfg, removed, added;
-    size_t i;
-
-    svec_init(&new_cfg);
-    cfg_get_all(&new_cfg);
-    svec_diff(&orig_cfg, &new_cfg, &removed, NULL, &added);
-    if (removed.n || added.n) {
-        VLOG_INFO("configuration changes:");
-        for (i = 0; i < removed.n; i++) {
-            VLOG_INFO("-%s", removed.names[i]);
-        }
-        for (i = 0; i < added.n; i++) {
-            VLOG_INFO("+%s", added.names[i]);
-        }
-    } else {
-        VLOG_INFO("configuration unchanged");
-    }
-    svec_destroy(&added);
-    svec_destroy(&removed);
-    svec_swap(&new_cfg, &orig_cfg);
-    svec_destroy(&new_cfg);
-}
-
-int main(int argc, char *argv[])
-{
-    enum {
-        OPT_DEL_MATCH = UCHAR_MAX + 1,
-    };
-    static const struct option long_options[] = {
-        {"config-file",  required_argument, 0, 'F'},
-        {"timeout",      required_argument, 0, 'T'},
-        {"add",          required_argument, 0, 'a'},
-        {"del-entry",    required_argument, 0, 'd'},
-        {"del-section",  required_argument, 0, 'D'},
-        {"del-match",    required_argument, 0, OPT_DEL_MATCH},
-        {"query",        required_argument, 0, 'q'},
-        {"changes",      no_argument, 0, 'c'},
-        {"verbose",      optional_argument, 0, 'v'},
-        {"help",         no_argument, 0, 'h'},
-        {"version",      no_argument, 0, 'V'},
-        {0, 0, 0, 0},
-    };
-    char *short_options;
-    bool config_set = false;
-    int timeout = INT_MAX;
-
-    set_program_name(argv[0]);
-    time_init();
-    vlog_init();
-
-    short_options = long_options_to_short_options(long_options);
-    for (;;) {
-        int option;
-
-        option = getopt_long(argc, argv, short_options, long_options, NULL);
-        if (option == -1) {
-            break;
-        }
-
-        if ((option > UCHAR_MAX || !strchr("FhVv?", option))
-            && config_set == false) {
-            ovs_fatal(0, "no config file specified (use --help for help)");
-        }
-
-        switch (option) {
-        case 'T':
-            if (config_set) {
-                ovs_fatal(0, "--timeout or -T must be specified "
-                          "before --file or -F");
-            }
-            timeout = atoi(optarg);
-            break;
-
-        case 'F': 
-            open_config(optarg, timeout);
-            config_set = true;
-            break;
-
-       case 'a':
-            cfg_add_entry("%s", optarg);
-            break;
-
-        case 'd':
-            cfg_del_entry("%s", optarg);
-            break;
-
-        case 'D':
-            cfg_del_section("%s", optarg);
-            break;
-
-        case OPT_DEL_MATCH:
-            cfg_del_match("%s", optarg);
-            break;
-
-        case 'q':
-            print_vals(optarg);
-            break;
-
-        case 'c':
-            log_diffs();
-            break;
-
-        case 'h':
-            usage(argv[0], EXIT_SUCCESS);
-            break;
-
-        case 'V':
-            OVS_PRINT_VERSION(0, 0);
-            exit(EXIT_SUCCESS);
-
-        case 'v':
-            vlog_set_verbosity(optarg);
-            break;
-
-        case '?':
-            exit(EXIT_FAILURE);
-
-        default:
-            NOT_REACHED();
-        }
-    }
-    free(short_options);
-
-    if (optind != argc) {
-        ovs_fatal(0, "non-option arguments not accepted "
-                  "(use --help for help)");
-    }
-
-    if (cfg_is_dirty()) {
-        cfg_write();
-    }
-    cfg_unlock();
-
-    exit(0);
-}
index c275cd6a599703b58ed65cc707fd9c4936a609e7..7f79a5270666e78705aeeb96f5522b1239d4a2ab 100644 (file)
@@ -345,14 +345,9 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
 
         switch (c) {
         case OPT_DATAPATH_ID:
-            if (strlen(optarg) != 12
-                || strspn(optarg, "0123456789abcdefABCDEF") != 12) {
+            if (!dpid_from_string(optarg, &s->datapath_id)) {
                 ovs_fatal(0, "argument to --datapath-id must be "
-                          "exactly 12 hex digits");
-            }
-            s->datapath_id = strtoll(optarg, NULL, 16);
-            if (!s->datapath_id) {
-                ovs_fatal(0, "argument to --datapath-id must be nonzero");
+                          "exactly 12 hex digits and may not be all-zero");
             }
             break;
 
index 33473e0654863964702145e4c27fbd757aec11d1..a36d1ae5ed06ca8ac0ac9fc24f79556175b77890 100644 (file)
@@ -1,22 +1,17 @@
 sbin_PROGRAMS += vswitchd/ovs-vswitchd vswitchd/ovs-brcompatd
 man_MANS += \
-       vswitchd/ovs-vswitchd.conf.5 \
        vswitchd/ovs-vswitchd.8 \
        vswitchd/ovs-brcompatd.8
 DISTCLEANFILES += \
-       vswitchd/ovs-vswitchd.conf.5 \
        vswitchd/ovs-vswitchd.8 \
        vswitchd/ovs-brcompatd.8
 
 vswitchd_ovs_vswitchd_SOURCES = \
        vswitchd/bridge.c \
        vswitchd/bridge.h \
-       vswitchd/mgmt.c \
-       vswitchd/mgmt.h \
        vswitchd/proc-net-compat.c \
        vswitchd/proc-net-compat.h \
        vswitchd/ovs-vswitchd.c \
-       vswitchd/ovs-vswitchd.h \
        vswitchd/vswitch-idl.c \
        vswitchd/vswitch-idl.h \
        vswitchd/xenserver.c \
@@ -35,7 +30,6 @@ vswitchd_ovs_brcompatd_LDADD = \
        $(FAULT_LIBS) 
 
 EXTRA_DIST += \
-       vswitchd/ovs-vswitchd.conf.5.in \
        vswitchd/ovs-vswitchd.8.in \
        vswitchd/ovs-brcompatd.8.in
 
index 24a39c7c1d4a81627100a360ae8b547808877bf5..3028766cd93771ae96bd48b35897145f9b641a3b 100644 (file)
@@ -30,7 +30,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include "bitmap.h"
-#include "cfg.h"
 #include "coverage.h"
 #include "dirs.h"
 #include "dpif.h"
@@ -50,6 +49,7 @@
 #include "port-array.h"
 #include "proc-net-compat.h"
 #include "process.h"
+#include "sha1.h"
 #include "shash.h"
 #include "socket-util.h"
 #include "svec.h"
@@ -70,8 +70,6 @@ struct dst {
     uint16_t dp_ifidx;
 };
 
-extern uint64_t mgmt_id;
-
 struct iface {
     /* These members are always valid. */
     struct port *port;          /* Containing port. */
@@ -85,6 +83,9 @@ struct iface {
     int dp_ifidx;               /* Index within kernel datapath. */
     struct netdev *netdev;      /* Network device. */
     bool enabled;               /* May be chosen for flows? */
+
+    /* This member is only valid *during* bridge_reconfigure(). */
+    const struct ovsrec_interface *cfg;
 };
 
 #define BOND_MASK 0xff
@@ -134,11 +135,15 @@ struct port {
     tag_type no_ifaces_tag;     /* Tag for flows when all ifaces disabled. */
     int updelay, downdelay;     /* Delay before iface goes up/down, in ms. */
     bool bond_compat_is_stale;  /* Need to call port_update_bond_compat()? */
+    bool bond_fake_iface;       /* Fake a bond interface for legacy compat? */
 
     /* Port mirroring info. */
     mirror_mask_t src_mirrors;  /* Mirrors triggered when packet received. */
     mirror_mask_t dst_mirrors;  /* Mirrors triggered when packet sent. */
     bool is_mirror_output_port; /* Does port mirroring send frames here? */
+
+    /* This member is only valid *during* bridge_reconfigure(). */
+    const struct ovsrec_port *cfg;
 };
 
 #define DP_MAX_PORTS 255
@@ -177,6 +182,9 @@ struct bridge {
 
     /* Port mirroring. */
     struct mirror *mirrors[MAX_MIRRORS];
+
+    /* This member is only valid *during* bridge_reconfigure(). */
+    const struct ovsrec_bridge *cfg;
 };
 
 /* List of all bridges. */
@@ -190,9 +198,11 @@ static void bridge_destroy(struct bridge *);
 static struct bridge *bridge_lookup(const char *name);
 static unixctl_cb_func bridge_unixctl_dump_flows;
 static int bridge_run_one(struct bridge *);
-static void bridge_reconfigure_one(struct bridge *);
-static void bridge_reconfigure_controller(struct bridge *);
-static void bridge_get_all_ifaces(const struct bridge *, struct svec *ifaces);
+static void bridge_reconfigure_one(const struct ovsrec_open_vswitch *,
+                                   struct bridge *);
+static void bridge_reconfigure_controller(const struct ovsrec_open_vswitch *,
+                                          struct bridge *);
+static void bridge_get_all_ifaces(const struct bridge *, struct shash *ifaces);
 static void bridge_fetch_dp_ifaces(struct bridge *);
 static void bridge_flush(struct bridge *);
 static void bridge_pick_local_hw_addr(struct bridge *,
@@ -213,8 +223,8 @@ static void bond_rebalance_port(struct port *);
 static void bond_send_learning_packets(struct port *);
 static void bond_enable_slave(struct iface *iface, bool enable);
 
-static void port_create(struct bridge *, const char *name);
-static void port_reconfigure(struct port *);
+static struct port *port_create(struct bridge *, const char *name);
+static void port_reconfigure(struct port *, const struct ovsrec_port *);
 static void port_destroy(struct port *);
 static struct port *port_lookup(const struct bridge *, const char *name);
 static struct iface *port_lookup_iface(const struct port *, const char *name);
@@ -224,13 +234,20 @@ static void port_update_bond_compat(struct port *);
 static void port_update_vlan_compat(struct port *);
 static void port_update_bonding(struct port *);
 
+#if 0
 static void mirror_create(struct bridge *, const char *name);
 static void mirror_destroy(struct mirror *);
 static void mirror_reconfigure(struct bridge *);
 static void mirror_reconfigure_one(struct mirror *);
 static bool vlan_is_mirrored(const struct mirror *, int vlan);
+#else
+static bool vlan_is_mirrored(const struct mirror *m UNUSED, int vlan UNUSED)
+{
+    return false;
+}
+#endif
 
-static void iface_create(struct port *, const char *name);
+static struct iface *iface_create(struct port *, const char *name);
 static void iface_destroy(struct iface *);
 static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_from_dp_ifidx(const struct bridge *,
@@ -270,15 +287,21 @@ bridge_get_ifaces(struct svec *svec)
     }
 }
 
-/* The caller must already have called cfg_read(). */
 void
-bridge_init(void)
+bridge_init(const struct ovsrec_open_vswitch *cfg)
 {
+    struct svec bridge_names;
     struct svec dpif_names;
     size_t i;
 
     unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
 
+    svec_init(&bridge_names);
+    for (i = 0; i < cfg->n_bridges; i++) {
+        svec_add(&bridge_names, cfg->bridges[i]->name);
+    }
+    svec_sort(&bridge_names);
+
     svec_init(&dpif_names);
     dp_enumerate(&dpif_names);
     for (i = 0; i < dpif_names.n; i++) {
@@ -294,7 +317,7 @@ bridge_init(void)
             svec_init(&all_names);
             dpif_get_all_names(dpif, &all_names);
             for (j = 0; j < all_names.n; j++) {
-                if (cfg_has("bridge.%s.port", all_names.names[j])) {
+                if (svec_contains(&bridge_names, all_names.names[j])) {
                     goto found;
                 }
             }
@@ -310,14 +333,13 @@ bridge_init(void)
                              NULL);
 
     bond_init();
-    bridge_reconfigure();
+    bridge_reconfigure(cfg);
 }
 
 #ifdef HAVE_OPENSSL
 static bool
-config_string_change(const char *key, char **valuep)
+config_string_change(const char *value, char **valuep)
 {
-    const char *value = cfg_get_string(0, "%s", key);
     if (value && (!*valuep || strcmp(value, *valuep))) {
         free(*valuep);
         *valuep = xstrdup(value);
@@ -328,7 +350,7 @@ config_string_change(const char *key, char **valuep)
 }
 
 static void
-bridge_configure_ssl(void)
+bridge_configure_ssl(const struct ovsrec_ssl *ssl)
 {
     /* XXX SSL should be configurable on a per-bridge basis.
      * XXX should be possible to de-configure SSL. */
@@ -337,11 +359,16 @@ bridge_configure_ssl(void)
     static char *cacert_file;
     struct stat s;
 
-    if (config_string_change("ssl.private-key", &private_key_file)) {
+    if (!ssl) {
+        /* XXX We can't un-set SSL settings. */
+        return;
+    }
+
+    if (config_string_change(ssl->private_key, &private_key_file)) {
         vconn_ssl_set_private_key_file(private_key_file);
     }
 
-    if (config_string_change("ssl.certificate", &certificate_file)) {
+    if (config_string_change(ssl->certificate, &certificate_file)) {
         vconn_ssl_set_certificate_file(certificate_file);
     }
 
@@ -350,10 +377,9 @@ bridge_configure_ssl(void)
      * boot-strapping mode.  This opens a small security hole, because
      * the old certificate will still be trusted until vSwitch is
      * restarted.  We may want to address this in vconn's SSL library. */
-    if (config_string_change("ssl.ca-cert", &cacert_file)
+    if (config_string_change(ssl->ca_cert, &cacert_file)
         || (cacert_file && stat(cacert_file, &s) && errno == ENOENT)) {
-        vconn_ssl_set_ca_cert_file(cacert_file,
-                                   cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
+        vconn_ssl_set_ca_cert_file(cacert_file, ssl->bootstrap_ca_cert);
     }
 }
 #endif
@@ -361,58 +387,50 @@ bridge_configure_ssl(void)
 /* Attempt to create the network device 'iface_name' through the netdev
  * library. */
 static int
-set_up_iface(const char *iface_name, bool create) 
+set_up_iface(const struct ovsrec_interface *iface_cfg, bool create) 
 {
-    const char *type;
-    const char *arg;
-    struct svec arg_svec;
-    struct shash args;
+    struct shash_node *node;
+    struct shash options;
     int error;
     size_t i;
 
     /* If a type is not explicitly declared, then assume it's an existing
      * "system" device. */
-    type = cfg_get_string(0, "iface.%s.type", iface_name);
-    if (!type || !strcmp(type, "system")) {
+    if (iface_cfg->type[0] == '\0' || !strcmp(iface_cfg->type, "system")) {
         return 0;
     }
 
-    svec_init(&arg_svec);
-    cfg_get_subsections(&arg_svec, "iface.%s.args", iface_name);
-
-    shash_init(&args);
-    SVEC_FOR_EACH (i, arg, &arg_svec) {
-        const char *value;
-
-        value = cfg_get_string(0, "iface.%s.args.%s", iface_name, arg);
-        if (value) {
-            shash_add(&args, arg, xstrdup(value));
-        }
+    shash_init(&options);
+    for (i = 0; i < iface_cfg->n_options; i++) {
+        shash_add(&options, iface_cfg->key_options[i],
+                  xstrdup(iface_cfg->value_options[i]));
     }
 
     if (create) {
-        error = netdev_create(iface_name, type, &args);
+        error = netdev_create(iface_cfg->name, iface_cfg->type, &options);
     } else {
         /* xxx Check to make sure that the type hasn't changed. */
-        error = netdev_reconfigure(iface_name, &args);
+        error = netdev_reconfigure(iface_cfg->name, &options);
     }
 
-    svec_destroy(&arg_svec);
-    shash_destroy(&args);
+    SHASH_FOR_EACH (node, &options) {
+        free(node->data);
+    }
+    shash_destroy(&options);
 
     return error;
 }
 
 static int
-create_iface(const char *iface_name)
+create_iface(const struct ovsrec_interface *iface_cfg)
 {
-    return set_up_iface(iface_name, true);
+    return set_up_iface(iface_cfg, true);
 }
 
 static int
-reconfigure_iface(const char *iface_name)
+reconfigure_iface(const struct ovsrec_interface *iface_cfg)
 {
-    return set_up_iface(iface_name, false);
+    return set_up_iface(iface_cfg, false);
 }
 
 static void
@@ -461,12 +479,10 @@ static bool
 set_iface_properties(struct bridge *br UNUSED, struct iface *iface,
                    void *aux UNUSED)
 {
-    int rate, burst;
-
     /* Set policing attributes. */
-    rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
-    burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
-    netdev_set_policing(iface->netdev, rate, burst);
+    netdev_set_policing(iface->netdev,
+                        iface->cfg->ingress_policing_rate,
+                        iface->cfg->ingress_policing_burst);
 
     /* Set MAC address of internal interfaces other than the local
      * interface. */
@@ -510,49 +526,56 @@ iterate_and_prune_ifaces(struct bridge *br,
 }
 
 void
-bridge_reconfigure(void)
+bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 {
-    struct svec old_br, new_br;
+    struct shash old_br, new_br;
+    struct shash_node *node;
     struct bridge *br, *next;
     size_t i;
 
     COVERAGE_INC(bridge_reconfigure);
 
     /* Collect old and new bridges. */
-    svec_init(&old_br);
-    svec_init(&new_br);
+    shash_init(&old_br);
+    shash_init(&new_br);
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
-        svec_add(&old_br, br->name);
+        shash_add(&old_br, br->name, br);
+    }
+    for (i = 0; i < ovs_cfg->n_bridges; i++) {
+        const struct ovsrec_bridge *br_cfg = ovs_cfg->bridges[i];
+        if (!shash_add_once(&new_br, br_cfg->name, br_cfg)) {
+            VLOG_WARN("more than one bridge named %s", br_cfg->name);
+        }
     }
-    cfg_get_subsections(&new_br, "bridge");
 
     /* Get rid of deleted bridges and add new bridges. */
-    svec_sort(&old_br);
-    svec_sort(&new_br);
-    assert(svec_is_unique(&old_br));
-    assert(svec_is_unique(&new_br));
     LIST_FOR_EACH_SAFE (br, next, struct bridge, node, &all_bridges) {
-        if (!svec_contains(&new_br, br->name)) {
+        struct ovsrec_bridge *br_cfg = shash_find_data(&new_br, br->name);
+        if (br_cfg) {
+            br->cfg = br_cfg;
+        } else {
             bridge_destroy(br);
         }
     }
-    for (i = 0; i < new_br.n; i++) {
-        const char *name = new_br.names[i];
-        if (!svec_contains(&old_br, name)) {
-            bridge_create(name);
+    SHASH_FOR_EACH (node, &new_br) {
+        const char *br_name = node->name;
+        const struct ovsrec_bridge *br_cfg = node->data;
+        if (!shash_find_data(&old_br, br_name)) {
+            br = bridge_create(br_name);
+            br->cfg = br_cfg;
         }
     }
-    svec_destroy(&old_br);
-    svec_destroy(&new_br);
+    shash_destroy(&old_br);
+    shash_destroy(&new_br);
 
 #ifdef HAVE_OPENSSL
     /* Configure SSL. */
-    bridge_configure_ssl();
+    bridge_configure_ssl(ovs_cfg->ssl);
 #endif
 
     /* Reconfigure all bridges. */
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
-        bridge_reconfigure_one(br);
+        bridge_reconfigure_one(ovs_cfg, br);
     }
 
     /* Add and delete ports on all datapaths.
@@ -563,13 +586,13 @@ bridge_reconfigure(void)
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         struct odp_port *dpif_ports;
         size_t n_dpif_ports;
-        struct svec want_ifaces;
+        struct shash want_ifaces;
 
         dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
         bridge_get_all_ifaces(br, &want_ifaces);
         for (i = 0; i < n_dpif_ports; i++) {
             const struct odp_port *p = &dpif_ports[i];
-            if (!svec_contains(&want_ifaces, p->devname)
+            if (!shash_find(&want_ifaces, p->devname)
                 && strcmp(p->devname, br->name)) {
                 int retval = dpif_port_del(br->dpif, p->port);
                 if (retval) {
@@ -580,66 +603,74 @@ bridge_reconfigure(void)
                 destroy_iface(p->devname);
             }
         }
-        svec_destroy(&want_ifaces);
+        shash_destroy(&want_ifaces);
         free(dpif_ports);
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         struct odp_port *dpif_ports;
         size_t n_dpif_ports;
-        struct svec cur_ifaces, want_ifaces, add_ifaces;
+        struct shash cur_ifaces, want_ifaces;
+        struct shash_node *node;
 
+        /* Get the set of interfaces currently in this datapath. */
         dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
-        svec_init(&cur_ifaces);
+        shash_init(&cur_ifaces);
         for (i = 0; i < n_dpif_ports; i++) {
-            svec_add(&cur_ifaces, dpif_ports[i].devname);
+            const char *name = dpif_ports[i].devname;
+            if (!shash_find(&cur_ifaces, name)) {
+                shash_add(&cur_ifaces, name, NULL);
+            }
         }
         free(dpif_ports);
-        svec_sort_unique(&cur_ifaces);
-        bridge_get_all_ifaces(br, &want_ifaces);
-        svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL);
 
-        for (i = 0; i < cur_ifaces.n; i++) {
-            const char *if_name = cur_ifaces.names[i];
-            reconfigure_iface(if_name);
-        }
+        /* Get the set of interfaces we want on this datapath. */
+        bridge_get_all_ifaces(br, &want_ifaces);
 
-        for (i = 0; i < add_ifaces.n; i++) {
-            const char *if_name = add_ifaces.names[i];
-            bool internal;
-            int error;
+        SHASH_FOR_EACH (node, &want_ifaces) {
+            const char *if_name = node->name;
+            struct iface *iface = node->data;
 
-            /* Attempt to create the network interface in case it
-             * doesn't exist yet. */
-            error = create_iface(if_name);
-            if (error) {
-                VLOG_WARN("could not create iface %s: %s\n", if_name,
-                        strerror(error));
-                continue;
-            }
+            if (shash_find(&cur_ifaces, if_name)) {
+                /* Already exists, just reconfigure it. */
+                if (iface) {
+                    reconfigure_iface(iface->cfg);
+                }
+            } else {
+                /* Need to add to datapath. */
+                bool internal;
+                int error;
+
+                /* Attempt to create the network interface in case it
+                 * doesn't exist yet. */
+                error = iface ? create_iface(iface->cfg) : 0;
+                if (error) {
+                    VLOG_WARN("could not create iface %s: %s\n", if_name,
+                              strerror(error));
+                    continue;
+                }
 
-            /* Add to datapath. */
-            internal = iface_is_internal(br, if_name);
-            error = dpif_port_add(br->dpif, if_name,
-                                  internal ? ODP_PORT_INTERNAL : 0, NULL);
-            if (error == EFBIG) {
-                VLOG_ERR("ran out of valid port numbers on %s",
-                         dpif_name(br->dpif));
-                break;
-            } else if (error) {
-                VLOG_ERR("failed to add %s interface to %s: %s",
-                         if_name, dpif_name(br->dpif), strerror(error));
+                /* Add to datapath. */
+                internal = !iface || iface_is_internal(br, if_name);
+                error = dpif_port_add(br->dpif, if_name,
+                                      internal ? ODP_PORT_INTERNAL : 0, NULL);
+                if (error == EFBIG) {
+                    VLOG_ERR("ran out of valid port numbers on %s",
+                             dpif_name(br->dpif));
+                    break;
+                } else if (error) {
+                    VLOG_ERR("failed to add %s interface to %s: %s",
+                             if_name, dpif_name(br->dpif), strerror(error));
+                }
             }
         }
-        svec_destroy(&cur_ifaces);
-        svec_destroy(&want_ifaces);
-        svec_destroy(&add_ifaces);
+        shash_destroy(&cur_ifaces);
+        shash_destroy(&want_ifaces);
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         uint8_t ea[8];
         uint64_t dpid;
         struct iface *local_iface;
         struct iface *hw_addr_iface;
-        struct netflow_options nf_options;
 
         bridge_fetch_dp_ifaces(br);
         iterate_and_prune_ifaces(br, init_iface_netdev, NULL);
@@ -663,46 +694,50 @@ bridge_reconfigure(void)
         ofproto_set_datapath_id(br->ofproto, dpid);
 
         /* Set NetFlow configuration on this bridge. */
-        memset(&nf_options, 0, sizeof nf_options);
-        dpif_get_netflow_ids(br->dpif, &nf_options.engine_type,
-                             &nf_options.engine_id);
-        nf_options.active_timeout = -1;
-
-        if (cfg_has("netflow.%s.engine-type", br->name)) {
-            nf_options.engine_type = cfg_get_int(0, "netflow.%s.engine-type", 
-                    br->name);
-        }
-        if (cfg_has("netflow.%s.engine-id", br->name)) {
-            nf_options.engine_id = cfg_get_int(0, "netflow.%s.engine-id",
-                                               br->name);
-        }
-        if (cfg_has("netflow.%s.active-timeout", br->name)) {
-            nf_options.active_timeout = cfg_get_int(0,
-                                                    "netflow.%s.active-timeout",
-                                                    br->name);
-        }
-        if (cfg_has("netflow.%s.add-id-to-iface", br->name)) {
-            nf_options.add_id_to_iface = cfg_get_bool(0,
-                                                   "netflow.%s.add-id-to-iface",
-                                                    br->name);
-        }
-        if (nf_options.add_id_to_iface && nf_options.engine_id > 0x7f) {
-            VLOG_WARN("bridge %s: netflow port mangling may conflict with "
-                    "another vswitch, choose an engine id less than 128", 
-                    br->name);
-        }
-        if (nf_options.add_id_to_iface && br->n_ports > 508) {
-            VLOG_WARN("bridge %s: netflow port mangling will conflict with "
-                    "another port when more than 508 ports are used", 
-                    br->name);
-        }
-        svec_init(&nf_options.collectors);
-        cfg_get_all_keys(&nf_options.collectors, "netflow.%s.host", br->name);
-        if (ofproto_set_netflow(br->ofproto, &nf_options)) {
-            VLOG_ERR("bridge %s: problem setting netflow collectors", 
-                    br->name);
-        }
-        svec_destroy(&nf_options.collectors);
+        if (br->cfg->netflow) {
+            struct ovsrec_netflow *nf_cfg = br->cfg->netflow;
+            struct netflow_options opts;
+
+            memset(&opts, 0, sizeof opts);
+
+            dpif_get_netflow_ids(br->dpif, &opts.engine_type, &opts.engine_id);
+            if (nf_cfg->engine_type) {
+                opts.engine_type = nf_cfg->engine_type;
+            }
+            if (nf_cfg->engine_id) {
+                opts.engine_id = nf_cfg->engine_id;
+            }
+
+            opts.active_timeout = nf_cfg->active_timeout;
+            if (!opts.active_timeout) {
+                opts.active_timeout = -1;
+            } else if (opts.active_timeout < 0) {
+                opts.active_timeout = 0;
+            }
+
+            opts.add_id_to_iface = nf_cfg->add_id_to_interface;
+            if (opts.add_id_to_iface) {
+                if (opts.engine_id > 0x7f) {
+                    VLOG_WARN("bridge %s: netflow port mangling may conflict "
+                              "with another vswitch, choose an engine id less "
+                              "than 128", br->name);
+                }
+                if (br->n_ports > 508) {
+                    VLOG_WARN("bridge %s: netflow port mangling will conflict "
+                              "with another port when more than 508 ports are "
+                              "used", br->name);
+                }
+            }
+
+            opts.collectors.n = nf_cfg->n_targets;
+            opts.collectors.names = nf_cfg->targets;
+            if (ofproto_set_netflow(br->ofproto, &opts)) {
+                VLOG_ERR("bridge %s: problem setting netflow collectors", 
+                         br->name);
+            }
+        } else {
+            ofproto_set_netflow(br->ofproto, NULL);
+        }
 
         /* Update the controller and related settings.  It would be more
          * straightforward to call this from bridge_reconfigure_one(), but we
@@ -713,7 +748,7 @@ bridge_reconfigure(void)
          * yet; when a controller is configured, resetting the datapath ID will
          * immediately disconnect from the controller, so it's better to set
          * the datapath ID before the controller. */
-        bridge_reconfigure_controller(br);
+        bridge_reconfigure_controller(ovs_cfg, br);
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         for (i = 0; i < br->n_ports; i++) {
@@ -732,16 +767,13 @@ static void
 bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
                           struct iface **hw_addr_iface)
 {
-    uint64_t requested_ea;
     size_t i, j;
     int error;
 
     *hw_addr_iface = NULL;
 
     /* Did the user request a particular MAC? */
-    requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name);
-    if (requested_ea) {
-        eth_addr_from_uint64(requested_ea, ea);
+    if (br->cfg->hwaddr && eth_addr_from_string(br->cfg->hwaddr, ea)) {
         if (eth_addr_is_multicast(ea)) {
             VLOG_ERR("bridge %s: cannot set MAC address to multicast "
                      "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
@@ -759,7 +791,6 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
         uint8_t iface_ea[ETH_ADDR_LEN];
-        uint64_t iface_ea_u64;
         struct iface *iface;
 
         /* Mirror output ports don't participate. */
@@ -768,11 +799,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
         }
 
         /* Choose the MAC address to represent the port. */
-        iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
-        if (iface_ea_u64) {
-            /* User specified explicitly. */
-            eth_addr_from_uint64(iface_ea_u64, iface_ea);
-
+        if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
             /* Find the interface with this Ethernet address (if any) so that
              * we can provide the correct devname to the caller. */
             iface = NULL;
@@ -804,7 +831,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
              * we really want a physical MAC if we can get it, and internal
              * ports typically have randomly generated MACs. */
             if (iface->dp_ifidx == ODPP_LOCAL
-                || cfg_get_bool(0, "iface.%s.internal", iface->name)) {
+                || !strcmp(iface->cfg->type, "internal")) {
                 continue;
             }
 
@@ -863,8 +890,8 @@ bridge_pick_datapath_id(struct bridge *br,
      */
     uint64_t dpid;
 
-    dpid = cfg_get_dpid(0, "bridge.%s.datapath-id", br->name);
-    if (dpid) {
+    if (br->cfg->datapath_id
+        && dpid_from_string(br->cfg->datapath_id, &dpid)) {
         return dpid;
     }
 
@@ -1161,16 +1188,21 @@ bridge_run_one(struct bridge *br)
     return error;
 }
 
-static const char *
-bridge_get_controller(const struct bridge *br)
+static const struct ovsrec_controller *
+bridge_get_controller(const struct ovsrec_open_vswitch *ovs_cfg,
+                      const struct bridge *br)
 {
-    const char *controller;
+    const struct ovsrec_controller *controller;
 
-    controller = cfg_get_string(0, "bridge.%s.controller", br->name);
-    if (!controller) {
-        controller = cfg_get_string(0, "mgmt.controller");
+    controller = (br->cfg->controller ? br->cfg->controller
+                  : ovs_cfg->controller ? ovs_cfg->controller
+                  : NULL);
+
+    if (controller && !strcmp(controller->target, "none")) {
+        return NULL;
     }
-    return controller && controller[0] ? controller : NULL;
+
+    return controller;
 }
 
 static bool
@@ -1190,66 +1222,61 @@ check_duplicate_ifaces(struct bridge *br, struct iface *iface, void *ifaces_)
 }
 
 static void
-bridge_reconfigure_one(struct bridge *br)
+bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
+                       struct bridge *br)
 {
-    struct svec old_ports, new_ports, ifaces;
+    struct shash old_ports, new_ports;
+    struct svec ifaces;
     struct svec listeners, old_listeners;
     struct svec snoops, old_snoops;
+    struct shash_node *node;
+    uint64_t mgmt_id;
     size_t i;
 
     /* Collect old ports. */
-    svec_init(&old_ports);
+    shash_init(&old_ports);
     for (i = 0; i < br->n_ports; i++) {
-        svec_add(&old_ports, br->ports[i]->name);
+        shash_add(&old_ports, br->ports[i]->name, br->ports[i]);
     }
-    svec_sort(&old_ports);
-    assert(svec_is_unique(&old_ports));
 
     /* Collect new ports. */
-    svec_init(&new_ports);
-    cfg_get_all_keys(&new_ports, "bridge.%s.port", br->name);
-    svec_sort(&new_ports);
-    if (bridge_get_controller(br)) {
+    shash_init(&new_ports);
+    for (i = 0; i < br->cfg->n_ports; i++) {
+        const char *name = br->cfg->ports[i]->name;
+        if (!shash_add_once(&new_ports, name, br->cfg->ports[i])) {
+            VLOG_WARN("bridge %s: %s specified twice as bridge port",
+                      br->name, name);
+        }
+    }
+    if (bridge_get_controller(ovs_cfg, br)) {
         char local_name[IF_NAMESIZE];
         int error;
 
         error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
                                    local_name, sizeof local_name);
-        if (!error && !svec_contains(&new_ports, local_name)) {
-            svec_add(&new_ports, local_name);
-            svec_sort(&new_ports);
+        if (!error) {
+            shash_add_once(&new_ports, local_name, NULL);
         }
     }
-    if (!svec_is_unique(&new_ports)) {
-        VLOG_WARN("bridge %s: %s specified twice as bridge port",
-                  br->name, svec_get_duplicate(&new_ports));
-        svec_unique(&new_ports);
-    }
 
+    dpid_from_string(ovs_cfg->management_id, &mgmt_id);
     ofproto_set_mgmt_id(br->ofproto, mgmt_id);
 
     /* Get rid of deleted ports and add new ports. */
-    for (i = 0; i < br->n_ports; ) {
-        struct port *port = br->ports[i];
-        if (!svec_contains(&new_ports, port->name)) {
-            port_destroy(port);
-        } else {
-            i++;
+    SHASH_FOR_EACH (node, &old_ports) {
+        if (!shash_find(&new_ports, node->name)) {
+            port_destroy(node->data);
         }
     }
-    for (i = 0; i < new_ports.n; i++) {
-        const char *name = new_ports.names[i];
-        if (!svec_contains(&old_ports, name)) {
-            port_create(br, name);
+    SHASH_FOR_EACH (node, &new_ports) {
+        struct port *port = shash_find_data(&old_ports, node->name);
+        if (!port) {
+            port = port_create(br, node->name);
         }
+        port_reconfigure(port, node->data);
     }
-    svec_destroy(&old_ports);
-    svec_destroy(&new_ports);
-
-    /* Reconfigure all ports. */
-    for (i = 0; i < br->n_ports; i++) {
-        port_reconfigure(br->ports[i]);
-    }
+    shash_destroy(&old_ports);
+    shash_destroy(&new_ports);
 
     /* Check and delete duplicate interfaces. */
     svec_init(&ifaces);
@@ -1260,6 +1287,7 @@ bridge_reconfigure_one(struct bridge *br)
      * versa.  (XXX Should we delete all flows if we are switching from one
      * controller to another?) */
 
+#if 0
     /* Configure OpenFlow management listeners. */
     svec_init(&listeners);
     cfg_get_all_strings(&listeners, "bridge.%s.openflow.listeners", br->name);
@@ -1301,56 +1329,81 @@ bridge_reconfigure_one(struct bridge *br)
     }
     svec_destroy(&snoops);
     svec_destroy(&old_snoops);
+#else
+    /* Default listener. */
+    svec_init(&listeners);
+    svec_add_nocopy(&listeners, xasprintf("punix:%s/%s.mgmt",
+                                          ovs_rundir, br->name));
+    svec_init(&old_listeners);
+    ofproto_get_listeners(br->ofproto, &old_listeners);
+    if (!svec_equal(&listeners, &old_listeners)) {
+        ofproto_set_listeners(br->ofproto, &listeners);
+    }
+    svec_destroy(&listeners);
+    svec_destroy(&old_listeners);
 
+    /* Default snoop. */
+    svec_init(&snoops);
+    svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
+                                       ovs_rundir, br->name));
+    svec_init(&old_snoops);
+    ofproto_get_snoops(br->ofproto, &old_snoops);
+    if (!svec_equal(&snoops, &old_snoops)) {
+        ofproto_set_snoops(br->ofproto, &snoops);
+    }
+    svec_destroy(&snoops);
+    svec_destroy(&old_snoops);
+#endif
+
+#if 0
     mirror_reconfigure(br);
+#endif
 }
 
 static void
-bridge_reconfigure_controller(struct bridge *br)
+bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
+                              struct bridge *br)
 {
     char *pfx = xasprintf("bridge.%s.controller", br->name);
-    const char *controller;
+    const struct ovsrec_controller *c;
 
-    controller = bridge_get_controller(br);
-    if ((br->controller != NULL) != (controller != NULL)) {
+    c = bridge_get_controller(ovs_cfg, br);
+    if ((br->controller != NULL) != (c != NULL)) {
         ofproto_flush_flows(br->ofproto);
     }
     free(br->controller);
-    br->controller = controller ? xstrdup(controller) : NULL;
+    br->controller = c ? xstrdup(c->target) : NULL;
 
-    if (controller) {
-        const char *fail_mode;
+    if (c) {
         int max_backoff, probe;
         int rate_limit, burst_limit;
 
-        if (!strcmp(controller, "discover")) {
-            bool update_resolv_conf = true;
-
-            if (cfg_has("%s.update-resolv.conf", pfx)) {
-                update_resolv_conf = cfg_get_bool(0, "%s.update-resolv.conf",
-                        pfx);
-            }
+        if (!strcmp(c->target, "discover")) {
             ofproto_set_discovery(br->ofproto, true,
-                                  cfg_get_string(0, "%s.accept-regex", pfx),
-                                  update_resolv_conf);
+                                  c->discover_accept_regex,
+                                  c->discover_update_resolv_conf);
         } else {
             struct iface *local_iface;
+            struct in_addr ip;
             bool in_band;
 
-            in_band = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED,
-                                     "%s.in-band", pfx)
-                       || cfg_get_bool(0, "%s.in-band", pfx));
+            in_band = (!c->connection_mode
+                       || !strcmp(c->connection_mode, "out-of-band"));
             ofproto_set_discovery(br->ofproto, false, NULL, NULL);
             ofproto_set_in_band(br->ofproto, in_band);
 
             local_iface = bridge_get_local_iface(br);
-            if (local_iface
-                && cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
+            if (local_iface && c->local_ip && inet_aton(c->local_ip, &ip)) {
                 struct netdev *netdev = local_iface->netdev;
                 struct in_addr ip, mask, gateway;
-                ip.s_addr = cfg_get_ip(0, "%s.ip", pfx);
-                mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx);
-                gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx);
+
+                if (!c->local_netmask || !inet_aton(c->local_netmask, &mask)) {
+                    mask.s_addr = 0;
+                }
+                if (!c->local_gateway
+                    || !inet_aton(c->local_gateway, &gateway)) {
+                    gateway.s_addr = 0;
+                }
 
                 netdev_turn_flags_on(netdev, NETDEV_UP, true);
                 if (!mask.s_addr) {
@@ -1372,60 +1425,22 @@ bridge_reconfigure_controller(struct bridge *br)
             }
         }
 
-        fail_mode = cfg_get_string(0, "%s.fail-mode", pfx);
-        if (!fail_mode) {
-            fail_mode = cfg_get_string(0, "mgmt.fail-mode");
-        }
         ofproto_set_failure(br->ofproto,
-                            (!fail_mode
-                             || !strcmp(fail_mode, "standalone")
-                             || !strcmp(fail_mode, "open")));
-
-        probe = cfg_get_int(0, "%s.inactivity-probe", pfx);
-        if (probe < 5) {
-            probe = cfg_get_int(0, "mgmt.inactivity-probe");
-            if (probe < 5) {
-                probe = 5;
-            }
-        }
+                            (!c->fail_mode
+                             || !strcmp(c->fail_mode, "standalone")
+                             || !strcmp(c->fail_mode, "open")));
+
+        probe = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
         ofproto_set_probe_interval(br->ofproto, probe);
 
-        max_backoff = cfg_get_int(0, "%s.max-backoff", pfx);
-        if (!max_backoff) {
-            max_backoff = cfg_get_int(0, "mgmt.max-backoff");
-            if (!max_backoff) {
-                max_backoff = 8;
-            }
-        }
+        max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8;
         ofproto_set_max_backoff(br->ofproto, max_backoff);
 
-        rate_limit = cfg_get_int(0, "%s.rate-limit", pfx);
-        if (!rate_limit) {
-            rate_limit = cfg_get_int(0, "mgmt.rate-limit");
-        }
-        burst_limit = cfg_get_int(0, "%s.burst-limit", pfx);
-        if (!burst_limit) {
-            burst_limit = cfg_get_int(0, "mgmt.burst-limit");
-        }
+        rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
+        burst_limit = c->controller_burst_limit ? *c->controller_burst_limit : 0;
         ofproto_set_rate_limit(br->ofproto, rate_limit, burst_limit);
 
-        if (cfg_has("%s.commands.acl", pfx)) {
-            struct svec command_acls;
-            char *command_acl;
-
-            svec_init(&command_acls);
-            cfg_get_all_strings(&command_acls, "%s.commands.acl", pfx);
-            command_acl = svec_join(&command_acls, ",", "");
-
-            ofproto_set_remote_execution(br->ofproto, command_acl,
-                                         cfg_get_string(0, "%s.commands.dir",
-                                                        pfx));
-
-            svec_destroy(&command_acls);
-            free(command_acl);
-        } else {
-            ofproto_set_remote_execution(br->ofproto, NULL, NULL);
-        }
+        ofproto_set_remote_execution(br->ofproto, NULL, NULL); /* XXX */
     } else {
         union ofp_action action;
         flow_t flow;
@@ -1451,23 +1466,21 @@ bridge_reconfigure_controller(struct bridge *br)
 }
 
 static void
-bridge_get_all_ifaces(const struct bridge *br, struct svec *ifaces)
+bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
 {
     size_t i, j;
 
-    svec_init(ifaces);
+    shash_init(ifaces);
     for (i = 0; i < br->n_ports; i++) {
         struct port *port = br->ports[i];
         for (j = 0; j < port->n_ifaces; j++) {
             struct iface *iface = port->ifaces[j];
-            svec_add(ifaces, iface->name);
+            shash_add_once(ifaces, iface->name, iface);
         }
-        if (port->n_ifaces > 1
-            && cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
-            svec_add(ifaces, port->name);
+        if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
+            shash_add_once(ifaces, port->name, NULL);
         }
     }
-    svec_sort_unique(ifaces);
 }
 
 /* For robustness, in case the administrator moves around datapath ports behind
@@ -2918,7 +2931,7 @@ bond_init(void)
 \f
 /* Port functions. */
 
-static void
+static struct port *
 port_create(struct bridge *br, const char *name)
 {
     struct port *port;
@@ -2939,70 +2952,70 @@ port_create(struct bridge *br, const char *name)
 
     VLOG_INFO("created port %s on bridge %s", port->name, br->name);
     bridge_flush(br);
+
+    return port;
 }
 
 static void
-port_reconfigure(struct port *port)
+port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
 {
-    bool bonded = cfg_has_section("bonding.%s", port->name);
-    struct svec old_ifaces, new_ifaces;
+    struct shash old_ifaces, new_ifaces;
+    struct shash_node *node;
     unsigned long *trunks;
     int vlan;
     size_t i;
 
+    port->cfg = cfg;
+
     /* Collect old and new interfaces. */
-    svec_init(&old_ifaces);
-    svec_init(&new_ifaces);
+    shash_init(&old_ifaces);
+    shash_init(&new_ifaces);
     for (i = 0; i < port->n_ifaces; i++) {
-        svec_add(&old_ifaces, port->ifaces[i]->name);
+        shash_add(&old_ifaces, port->ifaces[i]->name, port->ifaces[i]);
     }
-    svec_sort(&old_ifaces);
-    if (bonded) {
-        cfg_get_all_keys(&new_ifaces, "bonding.%s.slave", port->name);
-        if (!new_ifaces.n) {
-            VLOG_ERR("port %s: no interfaces specified for bonded port",
-                     port->name);
-        } else if (new_ifaces.n == 1) {
-            VLOG_WARN("port %s: only 1 interface specified for bonded port",
-                      port->name);
+    for (i = 0; i < cfg->n_interfaces; i++) {
+        const char *name = cfg->interfaces[i]->name;
+        if (!shash_add_once(&new_ifaces, name, cfg->interfaces[i])) {
+            VLOG_WARN("port %s: %s specified twice as port interface",
+                      port->name, name);
         }
-
-        port->updelay = cfg_get_int(0, "bonding.%s.updelay", port->name);
-        if (port->updelay < 0) {
-            port->updelay = 0;
-        }
-        port->downdelay = cfg_get_int(0, "bonding.%s.downdelay", port->name);
-        if (port->downdelay < 0) {
-            port->downdelay = 0;
-        }
-    } else {
-        svec_init(&new_ifaces);
-        svec_add(&new_ifaces, port->name);
+    }
+    port->updelay = cfg->bond_updelay;
+    if (port->updelay < 0) {
+        port->updelay = 0;
+    }
+    port->updelay = cfg->bond_downdelay;
+    if (port->downdelay < 0) {
+        port->downdelay = 0;
     }
 
     /* Get rid of deleted interfaces and add new interfaces. */
-    for (i = 0; i < port->n_ifaces; i++) {
-        struct iface *iface = port->ifaces[i];
-        if (!svec_contains(&new_ifaces, iface->name)) {
-            iface_destroy(iface);
-        } else {
-            i++;
+    SHASH_FOR_EACH (node, &old_ifaces) {
+        if (!shash_find(&new_ifaces, node->name)) {
+            iface_destroy(node->data);
         }
     }
-    for (i = 0; i < new_ifaces.n; i++) {
-        const char *name = new_ifaces.names[i];
-        if (!svec_contains(&old_ifaces, name)) {
-            iface_create(port, name);
+    SHASH_FOR_EACH (node, &new_ifaces) {
+        const struct ovsrec_interface *if_cfg = node->data;
+        const char *if_name = node->name;
+        struct iface *iface;
+
+        iface = shash_find_data(&old_ifaces, if_name);
+        if (!iface) {
+            iface = iface_create(port, if_name);
         }
+        iface->cfg = if_cfg;
     }
 
     /* Get VLAN tag. */
     vlan = -1;
-    if (cfg_has("vlan.%s.tag", port->name)) {
-        if (!bonded) {
-            vlan = cfg_get_vlan(0, "vlan.%s.tag", port->name);
+    if (cfg->tag) {
+        if (port->n_ifaces < 2) {
+            vlan = *cfg->tag;
             if (vlan >= 0 && vlan <= 4095) {
                 VLOG_DBG("port %s: assigning VLAN tag %d", port->name, vlan);
+            } else {
+                vlan = -1;
             }
         } else {
             /* It's possible that bonded, VLAN-tagged ports make sense.  Maybe
@@ -3019,14 +3032,13 @@ port_reconfigure(struct port *port)
     /* Get trunked VLANs. */
     trunks = NULL;
     if (vlan < 0) {
-        size_t n_trunks, n_errors;
+        size_t n_errors;
         size_t i;
 
         trunks = bitmap_allocate(4096);
-        n_trunks = cfg_count("vlan.%s.trunks", port->name);
         n_errors = 0;
-        for (i = 0; i < n_trunks; i++) {
-            int trunk = cfg_get_vlan(i, "vlan.%s.trunks", port->name);
+        for (i = 0; i < cfg->n_trunks; i++) {
+            int trunk = cfg->trunks[i];
             if (trunk >= 0) {
                 bitmap_set1(trunks, trunk);
             } else {
@@ -3035,9 +3047,9 @@ port_reconfigure(struct port *port)
         }
         if (n_errors) {
             VLOG_ERR("port %s: invalid values for %zu trunk VLANs",
-                     port->name, n_trunks);
+                     port->name, cfg->n_trunks);
         }
-        if (n_errors == n_trunks) {
+        if (n_errors == cfg->n_trunks) {
             if (n_errors) {
                 VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
                          port->name);
@@ -3045,9 +3057,9 @@ port_reconfigure(struct port *port)
             bitmap_set_multiple(trunks, 0, 4096, 1);
         }
     } else {
-        if (cfg_has("vlan.%s.trunks", port->name)) {
-            VLOG_ERR("ignoring vlan.%s.trunks in favor of vlan.%s.vlan",
-                     port->name, port->name);
+        if (cfg->n_trunks) {
+            VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+                     port->name);
         }
     }
     if (trunks == NULL
@@ -3058,8 +3070,8 @@ port_reconfigure(struct port *port)
     bitmap_free(port->trunks);
     port->trunks = trunks;
 
-    svec_destroy(&old_ifaces);
-    svec_destroy(&new_ifaces);
+    shash_destroy(&old_ifaces);
+    shash_destroy(&new_ifaces);
 }
 
 static void
@@ -3068,17 +3080,18 @@ port_destroy(struct port *port)
     if (port) {
         struct bridge *br = port->bridge;
         struct port *del;
-        size_t i;
 
         proc_net_compat_update_vlan(port->name, NULL, 0);
         proc_net_compat_update_bond(port->name, NULL);
 
+#if 0
         for (i = 0; i < MAX_MIRRORS; i++) {
             struct mirror *m = br->mirrors[i];
             if (m && m->out_port == port) {
                 mirror_destroy(m);
             }
         }
+#endif
 
         while (port->n_ifaces > 0) {
             iface_destroy(port->ifaces[port->n_ifaces - 1]);
@@ -3139,6 +3152,7 @@ port_update_bonding(struct port *port)
             free(port->bond_hash);
             port->bond_hash = NULL;
             port->bond_compat_is_stale = true;
+            port->bond_fake_iface = false;
         }
     } else {
         if (!port->bond_hash) {
@@ -3154,6 +3168,7 @@ port_update_bonding(struct port *port)
             bond_choose_active_iface(port);
         }
         port->bond_compat_is_stale = true;
+        port->bond_fake_iface = port->cfg->bond_fake_iface;
     }
 }
 
@@ -3213,7 +3228,7 @@ port_update_bond_compat(struct port *port)
         netdev_get_etheraddr(iface->netdev, slave->mac);
     }
 
-    if (cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
+    if (port->bond_fake_iface) {
         struct netdev *bond_netdev;
 
         if (!netdev_open(port->name, NETDEV_ETH_TYPE_NONE, &bond_netdev)) {
@@ -3269,7 +3284,7 @@ port_update_vlan_compat(struct port *port)
 \f
 /* Interface functions. */
 
-static void
+static struct iface *
 iface_create(struct port *port, const char *name)
 {
     struct iface *iface;
@@ -3295,6 +3310,8 @@ iface_create(struct port *port, const char *name)
     VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
 
     bridge_flush(port->bridge);
+
+    return iface;
 }
 
 static void
@@ -3361,20 +3378,25 @@ iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
  * reason why this function takes a name instead of a struct iface: the fake
  * interfaces created this way do not have a struct iface. */
 static bool
-iface_is_internal(const struct bridge *br, const char *iface)
+iface_is_internal(const struct bridge *br, const char *if_name)
 {
-    if (!strcmp(iface, br->name)
-        || cfg_get_bool(0, "iface.%s.internal", iface)) {
+    /* XXX wastes time */
+    struct iface *iface;
+    struct port *port;
+
+    if (!strcmp(if_name, br->name)) {
         return true;
     }
 
-    if (cfg_get_bool(0, "bonding.%s.fake-iface", iface)) {
-        struct port *port = port_lookup(br, iface);
-        if (port && port->n_ifaces > 1) {
-            return true;
-        }
+    iface = iface_lookup(br, if_name);
+    if (iface && !strcmp(iface->cfg->type, "internal")) {
+        return true;
     }
 
+    port = port_lookup(br, if_name);
+    if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
+        return true;
+    }
     return false;
 }
 
@@ -3383,11 +3405,9 @@ iface_is_internal(const struct bridge *br, const char *iface)
 static void
 iface_set_mac(struct iface *iface)
 {
-    uint64_t mac = cfg_get_mac(0, "iface.%s.mac", iface->name);
-    if (mac) {
-        static uint8_t ea[ETH_ADDR_LEN];
+    uint8_t ea[ETH_ADDR_LEN];
 
-        eth_addr_from_uint64(mac, ea);
+    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
         if (eth_addr_is_multicast(ea)) {
             VLOG_ERR("interface %s: cannot set MAC to multicast address",
                      iface->name);
@@ -3406,8 +3426,9 @@ iface_set_mac(struct iface *iface)
 \f
 /* Port mirroring. */
 
+#if 0
 static void
-mirror_reconfigure(struct bridge *br)
+mirror_reconfigure(struct bridge *br UNUSED)
 {
     struct svec old_mirrors, new_mirrors;
     size_t i, n_rspan_vlans;
@@ -3614,7 +3635,7 @@ port_trunks_any_mirrored_vlan(const struct mirror *m, const struct port *p)
 }
 
 static void
-mirror_reconfigure_one(struct mirror *m)
+mirror_reconfigure_one(struct mirror *m UNUSED)
 {
     char *pfx = xasprintf("mirror.%s.%s", m->bridge->name, m->name);
     struct svec src_ports, dst_ports, ports;
@@ -3734,3 +3755,4 @@ exit:
     svec_destroy(&dst_ports);
     free(pfx);
 }
+#endif
index a7250b29f4e7e5a88d40a49513ab952ae38e9a66..3d3770d702212362d6869ef9eb9b053fd601f95b 100644 (file)
 #include <stddef.h>
 #include "list.h"
 
+struct ovsrec_open_vswitch;
 struct svec;
 
-void bridge_init(void);
-void bridge_reconfigure(void);
+void bridge_init(const struct ovsrec_open_vswitch *);
+void bridge_reconfigure(const struct ovsrec_open_vswitch *);
 int bridge_run(void);
 void bridge_wait(void);
 bool bridge_exists(const char *);
diff --git a/vswitchd/mgmt.c b/vswitchd/mgmt.c
deleted file mode 100644 (file)
index 8da640f..0000000
+++ /dev/null
@@ -1,909 +0,0 @@
-/* Copyright (c) 2009 Nicira Networks
- *
- * 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 <arpa/inet.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include "bridge.h"
-#include "cfg.h"
-#include "coverage.h"
-#include "list.h"
-#include "mgmt.h"
-#include "openflow/nicira-ext.h"
-#include "openflow/openflow.h"
-#include "openflow/openflow-mgmt.h"
-#include "ofpbuf.h"
-#include "ovs-vswitchd.h"
-#include "packets.h"
-#include "rconn.h"
-#include "svec.h"
-#include "vconn.h"
-#include "vconn-ssl.h"
-#include "xenserver.h"
-#include "xtoxll.h"
-
-#define THIS_MODULE VLM_mgmt
-#include "vlog.h"
-
-#define MAX_BACKOFF_DEFAULT 15
-#define INACTIVITY_PROBE_DEFAULT 15
-
-static struct svec mgmt_cfg;
-static uint8_t cfg_cookie[CFG_COOKIE_LEN];
-static bool need_reconfigure = false;
-static struct rconn *mgmt_rconn;
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
-static struct svec capabilities;
-static struct ofpbuf ext_data_buffer;
-static uint32_t ext_data_xid = UINT32_MAX;
-uint64_t mgmt_id;
-
-
-#define TXQ_LIMIT 128         /* Max number of packets to queue for tx. */
-struct rconn_packet_counter *txqlen; /* # pkts queued for tx on mgmt_rconn. */
-
-static uint64_t pick_fallback_mgmt_id(void);
-static void send_config_update(uint32_t xid, bool use_xid);
-static void send_resources_update(uint32_t xid, bool use_xid);
-static int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len);
-
-void
-mgmt_init(void)
-{
-    txqlen = rconn_packet_counter_create();
-
-    svec_init(&mgmt_cfg);
-    svec_init(&capabilities);
-    svec_add_nocopy(&capabilities, 
-            xasprintf("com.nicira.mgmt.manager=true\n"));
-
-    mgmt_id = cfg_get_dpid(0, "mgmt.id");
-    if (!mgmt_id) {
-        /* Randomly generate a mgmt id */
-        mgmt_id = pick_fallback_mgmt_id();
-    }
-
-    ofpbuf_init(&ext_data_buffer, 0);
-}
-
-#ifdef HAVE_OPENSSL
-static bool
-config_string_change(const char *key, char **valuep)
-{
-    const char *value = cfg_get_string(0, "%s", key);
-    if (value && (!*valuep || strcmp(value, *valuep))) {
-        free(*valuep);
-        *valuep = xstrdup(value);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static void
-mgmt_configure_ssl(void)
-{
-    static char *private_key_file;
-    static char *certificate_file;
-    static char *cacert_file;
-    struct stat s;
-
-    /* XXX SSL should be configurable separate from the bridges.
-     * XXX should be possible to de-configure SSL. */
-    if (config_string_change("ssl.private-key", &private_key_file)) {
-        vconn_ssl_set_private_key_file(private_key_file);
-    }
-
-    if (config_string_change("ssl.certificate", &certificate_file)) {
-        vconn_ssl_set_certificate_file(certificate_file);
-    }
-
-    /* We assume that even if the filename hasn't changed, if the CA cert 
-     * file has been removed, that we want to move back into
-     * boot-strapping mode.  This opens a small security hole, because
-     * the old certificate will still be trusted until vSwitch is
-     * restarted.  We may want to address this in vconn's SSL library. */
-    if (config_string_change("ssl.ca-cert", &cacert_file) 
-            || (stat(cacert_file, &s) && errno == ENOENT)) {
-        vconn_ssl_set_ca_cert_file(cacert_file,
-                cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
-    }
-}
-#endif
-
-void
-mgmt_reconfigure(void)
-{
-    struct svec new_cfg;
-    uint8_t new_cookie[CFG_COOKIE_LEN];
-    bool cfg_updated = false;
-    const char *controller_name;
-    int max_backoff;
-    int inactivity_probe;
-    int retval;
-
-    if (!cfg_has_section("mgmt")) {
-        svec_clear(&mgmt_cfg);
-        if (mgmt_rconn) {
-            rconn_destroy(mgmt_rconn);
-            mgmt_rconn = NULL;
-        }
-        return;
-    }
-
-    /* If this is an established connection, send a resources update. */
-    /* xxx This is wasteful if there were no resource changes!!! */
-    if (mgmt_rconn) {
-        send_resources_update(0, false);
-    }
-
-    cfg_get_cookie(new_cookie);
-    if (memcmp(cfg_cookie, new_cookie, sizeof(cfg_cookie))) {
-        memcpy(cfg_cookie, new_cookie, sizeof(cfg_cookie));
-        cfg_updated = true;
-    }
-
-    svec_init(&new_cfg);
-    cfg_get_section(&new_cfg, "mgmt");
-    if (svec_equal(&mgmt_cfg, &new_cfg)) {
-        /* Reconnecting to the controller causes the config file to be
-         * resent automatically.  If we're not reconnecting and the
-         * config file has changed, we need to notify the controller of
-         * changes. */
-        if (cfg_updated && mgmt_rconn) {
-            send_config_update(0, false);
-        }
-        svec_destroy(&new_cfg);
-        return;
-    }
-
-    controller_name = cfg_get_string(0, "mgmt.controller");
-    if (!controller_name) {
-        VLOG_ERR("no controller specified for managment");
-        svec_destroy(&new_cfg);
-        return;
-    }
-
-    max_backoff = cfg_get_int(0, "mgmt.max-backoff");
-    if (max_backoff < 1) {
-        max_backoff = MAX_BACKOFF_DEFAULT;
-    } else if (max_backoff > 3600) {
-        max_backoff = 3600;
-    }
-
-    inactivity_probe = cfg_get_int(0, "mgmt.inactivity-probe");
-    if (inactivity_probe < 5) {
-        inactivity_probe = INACTIVITY_PROBE_DEFAULT;
-    }
-
-    /* xxx If this changes, we need to restart bridges to use new id,
-     * xxx but they need the id before the connect to controller, but we
-     * xxx need their dpids. */
-    /* Check if a different mgmt id has been assigned. */
-    if (cfg_has("mgmt.id")) {
-        uint64_t cfg_mgmt_id = cfg_get_dpid(0, "mgmt.id");
-        if (cfg_mgmt_id != mgmt_id) {
-            mgmt_id = cfg_mgmt_id;
-        }
-    }
-
-    svec_swap(&new_cfg, &mgmt_cfg);
-    svec_destroy(&new_cfg);
-
-#ifdef HAVE_OPENSSL
-    /* Configure SSL. */
-    mgmt_configure_ssl();
-#endif
-
-    if (mgmt_rconn) {
-        rconn_destroy(mgmt_rconn);
-        mgmt_rconn = NULL;
-    }
-    mgmt_rconn = rconn_create(inactivity_probe, max_backoff);
-    retval = rconn_connect(mgmt_rconn, controller_name);
-    if (retval == EAFNOSUPPORT) {
-        VLOG_ERR("no support for %s vconn", controller_name);
-    }
-
-    /* Reset the extended message buffer when we create a new
-     * management connection. */
-    ofpbuf_clear(&ext_data_buffer);
-}
-
-static void *
-make_ofmp_xid(size_t ofmp_len, uint16_t type, uint32_t xid,
-        struct ofpbuf **bufferp)
-{
-    struct ofmp_header *oh;
-
-    oh = make_openflow_xid(ofmp_len, OFPT_VENDOR, xid, bufferp);
-    oh->header.vendor = htonl(NX_VENDOR_ID);
-    oh->header.subtype = htonl(NXT_MGMT);
-    oh->type = htons(type);
-
-    return oh;
-}
-
-static void *
-make_ofmp(size_t ofmp_len, uint16_t type, struct ofpbuf **bufferp)
-{
-    struct ofmp_header *oh;
-
-    oh = make_openflow(ofmp_len, OFPT_VENDOR, bufferp);
-    oh->header.vendor = htonl(NX_VENDOR_ID);
-    oh->header.subtype = htonl(NXT_MGMT);
-    oh->type = htons(type);
-
-    return oh;
-}
-
-static int
-send_openflow_buffer(struct ofpbuf *buffer)
-{               
-    int retval;
-
-    if (!mgmt_rconn) {
-        VLOG_ERR("attempt to send openflow packet with no rconn\n");
-        return EINVAL;
-    }
-
-    /* Make sure there's room to transmit the data.  We don't want to
-     * fail part way through a send. */
-    if (rconn_packet_counter_read(txqlen) >= TXQ_LIMIT) {
-        return EAGAIN;
-    }
-
-    /* OpenFlow messages use a 16-bit length field, so messages over 64K
-     * must be broken into multiple pieces. 
-     */
-    if (buffer->size <= 65535) {
-        update_openflow_length(buffer);
-        retval = rconn_send(mgmt_rconn, buffer, txqlen);
-        if (retval) {
-            VLOG_WARN_RL(&rl, "send to %s failed: %s",
-                         rconn_get_name(mgmt_rconn), strerror(retval));
-        }   
-        return retval;
-    } else {
-        struct ofmp_header *header = (struct ofmp_header *)buffer->data;
-        uint32_t xid = header->header.header.xid;
-        size_t remain = buffer->size;
-        uint8_t *ptr = buffer->data;
-        
-        /* Mark the OpenFlow header with a zero length to indicate some
-         * funkiness. 
-         */
-        header->header.header.length = 0;
-
-        while (remain > 0) {
-            struct ofpbuf *new_buffer;
-            struct ofmp_extended_data *oed;
-            size_t new_len = MIN(65535 - sizeof *oed, remain);
-
-            oed = make_ofmp_xid(sizeof *oed, OFMPT_EXTENDED_DATA, xid, 
-                    &new_buffer);
-            oed->type = header->type;
-
-            if (remain > new_len) {
-                oed->flags |= OFMPEDF_MORE_DATA;
-            }
-
-            /* Copy the entire original message, including the OpenFlow
-             * header, since management protocol structure definitions
-             * include these headers.
-             */
-            ofpbuf_put(new_buffer, ptr, new_len);
-
-            update_openflow_length(new_buffer);
-            retval = rconn_send(mgmt_rconn, new_buffer, txqlen);
-            if (retval) {
-                VLOG_WARN_RL(&rl, "send to %s failed: %s",
-                             rconn_get_name(mgmt_rconn), strerror(retval));
-                ofpbuf_delete(buffer);
-                return retval;
-            }   
-
-            remain -= new_len;
-            ptr += new_len;
-        }
-
-        ofpbuf_delete(buffer);
-        return 0;
-    }
-}   
-    
-static void
-send_features_reply(uint32_t xid)
-{
-    struct ofpbuf *buffer;
-    struct ofp_switch_features *ofr;
-
-    ofr = make_openflow_xid(sizeof *ofr, OFPT_FEATURES_REPLY, xid, &buffer);
-    ofr->datapath_id  = 0;
-    ofr->n_tables     = 0;
-    ofr->n_buffers    = 0;
-    ofr->capabilities = 0;
-    ofr->actions      = 0;
-    send_openflow_buffer(buffer);
-}
-
-static void 
-send_capability_reply(uint32_t xid)
-{
-    int i;
-    struct ofpbuf *buffer;
-    struct ofmp_capability_reply *ofmpcr;
-
-    ofmpcr = make_ofmp_xid(sizeof *ofmpcr, OFMPT_CAPABILITY_REPLY, 
-            xid, &buffer);
-    ofmpcr->format = htonl(OFMPCOF_SIMPLE);
-    ofmpcr->mgmt_id = htonll(mgmt_id);
-    for (i=0; i<capabilities.n; i++) {
-        ofpbuf_put(buffer, capabilities.names[i], 
-                strlen(capabilities.names[i]));
-    }
-    send_openflow_buffer(buffer);
-}
-
-static void 
-send_resources_update(uint32_t xid, bool use_xid)
-{
-    struct ofpbuf *buffer;
-    struct ofmp_resources_update *ofmpru;
-    struct ofmp_tlv *tlv;
-    struct svec br_list;
-    struct svec port_list;
-    const char *host_uuid;
-    int i;
-
-    if (use_xid) {
-        ofmpru = make_ofmp_xid(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, 
-                xid, &buffer);
-    } else {
-        ofmpru = make_ofmp(sizeof *ofmpru, OFMPT_RESOURCES_UPDATE, &buffer);
-    }
-
-    /* On XenServer systems, each host has its own UUID, which we provide
-     * to the controller. 
-     */ 
-    host_uuid = xenserver_get_host_uuid();
-    if (host_uuid) {
-        struct ofmptsr_mgmt_uuid *mgmt_uuid_tlv;
-
-        mgmt_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*mgmt_uuid_tlv));
-        mgmt_uuid_tlv->type = htons(OFMPTSR_MGMT_UUID);
-        mgmt_uuid_tlv->len = htons(sizeof(*mgmt_uuid_tlv));
-        mgmt_uuid_tlv->mgmt_id = htonll(mgmt_id);
-        memcpy(mgmt_uuid_tlv->uuid, host_uuid, OFMP_UUID_LEN);
-    }
-
-    svec_init(&br_list);
-    cfg_get_subsections(&br_list, "bridge");
-    for (i=0; i < br_list.n; i++) {
-        struct ofmptsr_dp *dp_tlv;
-        uint64_t dp_id;
-        int n_uuid;
-
-        dp_id = bridge_get_datapathid(br_list.names[i]);
-        if (!dp_id) {
-            VLOG_WARN_RL(&rl, "bridge %s doesn't seem to exist", 
-                    br_list.names[i]);
-            continue;
-        }
-        dp_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_tlv));
-        dp_tlv->type = htons(OFMPTSR_DP);
-        dp_tlv->len = htons(sizeof(*dp_tlv));
-
-        dp_tlv->dp_id = htonll(dp_id);
-        memcpy(dp_tlv->name, br_list.names[i], strlen(br_list.names[i])+1);
-
-        /* On XenServer systems, each network has one or more UUIDs
-         * associated with it, which we provide to the controller. 
-         */
-        n_uuid = cfg_count("bridge.%s.xs-network-uuids", br_list.names[i]);
-        if (n_uuid) {
-            struct ofmptsr_dp_uuid *dp_uuid_tlv;
-            size_t tlv_len = sizeof(*dp_uuid_tlv) + n_uuid * OFMP_UUID_LEN;
-            int j;
-
-            dp_uuid_tlv = ofpbuf_put_zeros(buffer, sizeof(*dp_uuid_tlv));
-            dp_uuid_tlv->type = htons(OFMPTSR_DP_UUID);
-            dp_uuid_tlv->len = htons(tlv_len);
-            dp_uuid_tlv->dp_id = htonll(dp_id);
-
-            for (j=0; j<n_uuid; j++) {
-                const char *dp_uuid = cfg_get_string(j, 
-                        "bridge.%s.xs-network-uuids", br_list.names[i]);
-
-                /* The UUID list could change underneath us, so just
-                 * fill with zeros in that case.  Another update will be
-                 * initiated shortly, which should contain corrected data.
-                 */
-                if (dp_uuid) {
-                    ofpbuf_put(buffer, dp_uuid, OFMP_UUID_LEN);
-                } else {
-                    ofpbuf_put_zeros(buffer, OFMP_UUID_LEN);
-                }
-            }
-        }
-    }
-    svec_destroy(&br_list);
-
-    /* On XenServer systems, extended information about virtual interfaces 
-     * (VIFs) is available, which is needed by the controller. 
-     */ 
-    svec_init(&port_list);
-    bridge_get_ifaces(&port_list);
-    for (i=0; i < port_list.n; i++) {
-        const char *vif_uuid, *vm_uuid, *net_uuid;
-        uint64_t vif_mac;
-        struct ofmptsr_vif *vif_tlv;
-
-        vif_uuid = cfg_get_string(0, "port.%s.vif-uuid", port_list.names[i]);
-        if (!vif_uuid) {
-            continue;
-        }
-
-        vif_tlv = ofpbuf_put_zeros(buffer, sizeof(*vif_tlv));
-        vif_tlv->type = htons(OFMPTSR_VIF);
-        vif_tlv->len = htons(sizeof(*vif_tlv));
-
-        memcpy(vif_tlv->name, port_list.names[i], strlen(port_list.names[i])+1);
-        memcpy(vif_tlv->vif_uuid, vif_uuid, sizeof(vif_tlv->vif_uuid));
-
-        vm_uuid = cfg_get_string(0, "port.%s.vm-uuid", port_list.names[i]);
-        if (vm_uuid) {
-            memcpy(vif_tlv->vm_uuid, vm_uuid, sizeof(vif_tlv->vm_uuid));
-        } else {
-            /* In case the vif disappeared underneath us. */
-            memset(vif_tlv->vm_uuid, '\0', sizeof(vif_tlv->vm_uuid));
-        }
-
-        net_uuid = cfg_get_string(0, "port.%s.net-uuid", port_list.names[i]);
-        if (net_uuid) {
-            memcpy(vif_tlv->net_uuid, net_uuid, sizeof(vif_tlv->net_uuid));
-        } else {
-            /* In case the vif disappeared underneath us. */
-            memset(vif_tlv->net_uuid, '\0', sizeof(vif_tlv->net_uuid));
-        }
-
-        vif_mac = cfg_get_mac(0, "port.%s.vif-mac", port_list.names[i]);
-        vif_tlv->vif_mac = htonll(vif_mac);
-    }
-    svec_destroy(&port_list);
-
-    /* Put end marker. */
-    tlv = ofpbuf_put_zeros(buffer, sizeof(*tlv));
-    tlv->type = htons(OFMPTSR_END);
-    tlv->len = htons(sizeof(*tlv));
-    send_openflow_buffer(buffer);
-}
-
-static void 
-send_config_update(uint32_t xid, bool use_xid)
-{
-    struct ofpbuf *buffer;
-    struct ofmp_config_update *ofmpcu;
-
-    if (use_xid) {
-        ofmpcu = make_ofmp_xid(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, 
-                xid, &buffer);
-    } else {
-        ofmpcu = make_ofmp(sizeof *ofmpcu, OFMPT_CONFIG_UPDATE, &buffer);
-    }
-
-    ofmpcu->format = htonl(OFMPCOF_SIMPLE);
-    memcpy(ofmpcu->cookie, cfg_cookie, sizeof(ofmpcu->cookie));
-    cfg_buf_put(buffer);
-    send_openflow_buffer(buffer);
-}
-
-static void 
-send_config_update_ack(uint32_t xid, bool success)
-{
-    struct ofpbuf *buffer;
-    struct ofmp_config_update_ack *ofmpcua;
-
-    ofmpcua = make_ofmp_xid(sizeof *ofmpcua, OFMPT_CONFIG_UPDATE_ACK, 
-            xid, &buffer);
-
-    ofmpcua->format = htonl(OFMPCOF_SIMPLE);
-    if (success) {
-        ofmpcua->flags = htonl(OFMPCUAF_SUCCESS);
-    }
-    cfg_get_cookie(ofmpcua->cookie);
-    send_openflow_buffer(buffer);
-}
-
-static void
-send_error_msg(uint32_t xid, uint16_t type, uint16_t code, 
-            const void *data, size_t len)
-{
-    struct ofpbuf *buffer;
-    struct ofp_error_msg *oem;
-
-    oem = make_openflow_xid(sizeof(*oem)+len, OFPT_ERROR, xid, &buffer);
-    oem->type = htons(type);
-    oem->code = htons(code);
-    memcpy(oem->data, data, len);
-    send_openflow_buffer(buffer);
-}
-
-static int
-recv_echo_request(uint32_t xid UNUSED, const void *msg)
-{
-    const struct ofp_header *rq = msg;
-    send_openflow_buffer(make_echo_reply(rq));
-    return 0;
-}
-
-static int
-recv_features_request(uint32_t xid, const void *msg UNUSED)
-{
-    send_features_reply(xid);
-    return 0;
-}
-
-static int
-recv_set_config(uint32_t xid UNUSED, const void *msg UNUSED)
-{
-    /* Nothing to configure! */
-    return 0;
-}
-
-static int
-recv_ofmp_capability_request(uint32_t xid, const struct ofmp_header *ofmph,
-        size_t len)
-{
-    struct ofmp_capability_request *ofmpcr;
-
-    if (len != sizeof(*ofmpcr)) {
-        /* xxx Send error */
-        return -EINVAL;
-    }
-
-    ofmpcr = (struct ofmp_capability_request *)ofmph;
-    if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
-        /* xxx Send error */
-        return -EINVAL;
-    }
-
-    send_capability_reply(xid);
-
-    return 0;
-}
-
-static int
-recv_ofmp_resources_request(uint32_t xid, const void *msg UNUSED, 
-        size_t len UNUSED)
-{
-    send_resources_update(xid, true);
-    return 0;
-}
-
-static int
-recv_ofmp_config_request(uint32_t xid, const struct ofmp_header *ofmph, 
-        size_t len)
-{
-    struct ofmp_config_request *ofmpcr;
-
-    if (len != sizeof(*ofmpcr)) {
-        /* xxx Send error */
-        return -EINVAL;
-    }
-
-    ofmpcr = (struct ofmp_config_request *)ofmph;
-    if (ofmpcr->format != htonl(OFMPCOF_SIMPLE)) {
-        /* xxx Send error */
-        return -EINVAL;
-    }
-
-    send_config_update(xid, true);
-
-    return 0;
-}
-
-static int
-recv_ofmp_config_update(uint32_t xid, const struct ofmp_header *ofmph,
-        size_t len)
-{
-    struct ofmp_config_update *ofmpcu;
-    int data_len;
-
-    data_len = len - sizeof(*ofmpcu);
-    if (data_len <= sizeof(*ofmpcu)) {
-        /* xxx Send error. */
-        return -EINVAL;
-    }
-
-    ofmpcu = (struct ofmp_config_update *)ofmph;
-    if (ofmpcu->format != htonl(OFMPCOF_SIMPLE)) {
-        /* xxx Send error */
-        return -EINVAL;
-    }
-
-    /* Check if the supplied cookie matches our current understanding of
-     * it.  If they don't match, tell the controller and let it sort
-     * things out. */
-    if (cfg_lock(ofmpcu->cookie, 0)) {  
-        /* xxx cfg_lock can fail for other reasons, such as being
-         * xxx locked... */
-        VLOG_WARN_RL(&rl, "config update failed due to bad cookie\n");
-
-        /* Check if our local view matches the controller, in which
-         * case, it is likely that there were local modifications
-         * without our being told to reread the config file. */
-        if (!memcmp(cfg_cookie, ofmpcu->cookie, sizeof cfg_cookie)) {
-            VLOG_WARN_RL(&rl, "config appears to have been locally modified "
-                              "without having told ovs-vswitchd to reload");
-        }
-        send_config_update_ack(xid, false);
-        return 0;
-    }
-
-    /* xxx We should probably do more sanity checking than this. */
-
-    cfg_write_data(ofmpcu->data, data_len);
-    cfg_unlock();
-
-    /* Send the ACK before running reconfigure, since our management
-     * connection settings may have changed. */
-    send_config_update_ack(xid, true);
-
-    need_reconfigure = true;
-
-    return 0;
-}
-
-static int
-recv_ofmp_extended_data(uint32_t xid, const struct ofmp_header *ofmph,
-        size_t len)
-{
-    int data_len;
-    struct ofmp_extended_data *ofmped;
-
-    if (len <= sizeof(*ofmped)) {
-        /* xxx Send error. */
-        return -EINVAL;
-    }
-
-    ext_data_xid = xid;
-    ofmped = (struct ofmp_extended_data *)ofmph;
-
-    data_len = len - sizeof(*ofmped);
-    ofpbuf_put(&ext_data_buffer, ofmped->data, data_len);
-
-    if (!(ofmped->flags & OFMPEDF_MORE_DATA)) {
-        struct ofmp_header *new_oh;
-        int error;
-
-        /* An embedded message must be greater than the size of an
-         * OpenFlow message. */
-        new_oh = ofpbuf_at(&ext_data_buffer, 0, 65536);
-        if (!new_oh) {
-            VLOG_WARN_RL(&rl, "received short embedded message: %zu\n",
-                    ext_data_buffer.size);
-            return -EINVAL;
-        }
-
-        /* Make sure that this is a management message and that there's
-         * not an embedded extended data message. */
-        if ((new_oh->header.vendor != htonl(NX_VENDOR_ID))
-                || (new_oh->header.subtype != htonl(NXT_MGMT))
-                || (new_oh->type == htonl(OFMPT_EXTENDED_DATA))) {
-            VLOG_WARN_RL(&rl, "received bad embedded message\n");
-            return -EINVAL;
-        }
-        new_oh->header.header.xid = ext_data_xid;
-        new_oh->header.header.length = 0;
-
-        error = recv_ofmp(xid, ext_data_buffer.data, ext_data_buffer.size);
-        ofpbuf_clear(&ext_data_buffer);
-
-        return error;
-    }
-
-    return 0;
-}
-
-/* Handles receiving a management message.  Generally, this function
- * will be called 'len' set to zero, and the length will be derived by
- * the OpenFlow header.  With the extended data message, management
- * messages are not constrained by OpenFlow's 64K message length limit.  
- * The extended data handler calls this function with the 'len' set to
- * the total message length and the OpenFlow header's length field is 
- * ignored.
- */
-static
-int recv_ofmp(uint32_t xid, struct ofmp_header *ofmph, size_t len)
-{
-    if (!len) {
-        len = ntohs(ofmph->header.header.length);
-    }
-
-    /* Reset the extended data buffer if this isn't a continuation of an 
-     * existing extended data message. */
-    if (ext_data_xid != xid) {
-        ofpbuf_clear(&ext_data_buffer);
-    }
-
-    /* xxx Should sanity-check for min/max length */
-    switch (ntohs(ofmph->type)) 
-    {
-        case OFMPT_CAPABILITY_REQUEST:
-            return recv_ofmp_capability_request(xid, ofmph, len);
-        case OFMPT_RESOURCES_REQUEST:
-            return recv_ofmp_resources_request(xid, ofmph, len);
-        case OFMPT_CONFIG_REQUEST:
-            return recv_ofmp_config_request(xid, ofmph, len);
-        case OFMPT_CONFIG_UPDATE:
-            return recv_ofmp_config_update(xid, ofmph, len);
-        case OFMPT_EXTENDED_DATA:
-            return recv_ofmp_extended_data(xid, ofmph, len);
-        default:
-            VLOG_WARN_RL(&rl, "unknown mgmt message: %d", 
-                    ntohs(ofmph->type));
-            return -EINVAL;
-    }
-}
-
-static int 
-recv_nx_msg(uint32_t xid, const void *oh)
-{
-    const struct nicira_header *nh = oh;
-
-    switch (ntohl(nh->subtype)) {
-
-    case NXT_MGMT:
-        return recv_ofmp(xid, (struct ofmp_header *)oh, 0);
-
-    default:
-        send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, 
-                oh, ntohs(nh->header.length));
-        return -EINVAL;
-    }
-}
-
-static int
-recv_vendor(uint32_t xid, const void *oh)
-{
-    const struct ofp_vendor_header *ovh = oh;
-
-    switch (ntohl(ovh->vendor))
-    {
-    case NX_VENDOR_ID:
-        return recv_nx_msg(xid, oh);
-
-    default:
-        VLOG_WARN_RL(&rl, "unknown vendor: 0x%x", ntohl(ovh->vendor));
-        send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR, 
-                oh, ntohs(ovh->header.length));
-        return -EINVAL; 
-    }
-}
-
-static int
-handle_msg(uint32_t xid, const void *msg, size_t length)
-{
-    int (*handler)(uint32_t, const void *);
-    struct ofp_header *oh;
-    size_t min_size;
-
-    COVERAGE_INC(mgmt_received);
-
-    /* Check encapsulated length. */
-    oh = (struct ofp_header *) msg;
-    if (ntohs(oh->length) > length) {
-        return -EINVAL;
-    }
-    assert(oh->version == OFP_VERSION);
-
-    /* Figure out how to handle it. */
-    switch (oh->type) {
-    case OFPT_ECHO_REQUEST:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_echo_request;
-        break;
-    case OFPT_ECHO_REPLY:
-        return 0;
-    case OFPT_FEATURES_REQUEST:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_features_request;
-        break;
-    case OFPT_SET_CONFIG:
-        min_size = sizeof(struct ofp_switch_config);
-        handler = recv_set_config;
-        break;
-    case OFPT_VENDOR:
-        min_size = sizeof(struct ofp_vendor_header);
-        handler = recv_vendor;
-        break;
-    default:
-        VLOG_WARN_RL(&rl, "unknown openflow type: %d", oh->type);
-        send_error_msg(xid, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
-                msg, length);
-        return -EINVAL;
-    }
-
-    /* Handle it. */
-    if (length < min_size) {
-        return -EFAULT;
-    }
-    return handler(xid, msg);
-}
-
-bool 
-mgmt_run(void)
-{
-    int i;
-
-    if (!mgmt_rconn) {
-        return false;
-    }
-
-    need_reconfigure = false;
-    rconn_run(mgmt_rconn);
-
-    /* Do some processing, but cap it at a reasonable amount so that
-     * other processing doesn't starve. */
-    for (i=0; i<50; i++) {
-        struct ofpbuf *buffer;
-        struct ofp_header *oh;
-
-        buffer = rconn_recv(mgmt_rconn);
-        if (!buffer) {
-            break;
-        }
-
-        if (buffer->size >= sizeof *oh) {
-            oh = buffer->data;
-            handle_msg(oh->xid, buffer->data, buffer->size);
-            ofpbuf_delete(buffer);
-        } else {
-            VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
-        }
-    }
-
-    return need_reconfigure;
-}
-
-void
-mgmt_wait(void)
-{
-    if (!mgmt_rconn) {
-        return;
-    }
-
-    rconn_run_wait(mgmt_rconn);
-    rconn_recv_wait(mgmt_rconn);
-}
-
-static uint64_t
-pick_fallback_mgmt_id(void)
-{
-    uint8_t ea[ETH_ADDR_LEN];
-    eth_addr_random(ea);
-    ea[0] = 0x00;               /* Set Nicira OUI. */
-    ea[1] = 0x23;
-    ea[2] = 0x20;
-    return eth_addr_to_uint64(ea);
-}
diff --git a/vswitchd/mgmt.h b/vswitchd/mgmt.h
deleted file mode 100644 (file)
index f05c916..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) 2009 Nicira Networks
- *
- * 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 VSWITCHD_MGMT_H
-#define VSWITCHD_MGMT_H 1
-
-void mgmt_init(void);
-void mgmt_reconfigure(void);
-bool mgmt_run(void);
-void mgmt_wait(void);
-uint64_t mgmt_get_mgmt_id(void);
-
-#endif /* mgmt.h */
index 431c94888b9b50764c143a85127aaeb55ba49a14..5a016cd0adad3334e836d74345c45152b6b49327 100644 (file)
@@ -12,21 +12,28 @@ ovs\-vswitchd \- Open vSwitch daemon
 .
 .SH SYNOPSIS
 .B ovs\-vswitchd
-\fIconfig\fR
+\fIdatabase\fR
 .
 .SH DESCRIPTION
 A daemon that manages and controls any number of Open vSwitch switches 
 on the local machine.
 .PP
-The mandatory \fIconfig\fR argument specifies a configuration file.
-For a description of \fBovs\-vswitchd\fR configuration syntax, see
-\fBovs\-vswitchd.conf\fR(5).
+The mandatory \fIdatabase\fR argument specifies the
+\fBovsdb\-server\fR from which \fBovs\-vswitchd\fR's configuration
+should be retrieved.  It takes one of the following forms:
+.IP "\fBtcp:\fIip\fB:\fIport\fR"
+Connect to the given TCP \fIport\fR on \fIip\fR.
+.IP "\fBunix:\fIfile\fR"
+Connect to the Unix domain server socket named \fIfile\fR.
 .PP
-At startup or upon receipt of a \fBSIGHUP\fR signal, \fBovs\-vswitchd\fR
-reads the configuration file.  It sets up Open vSwitch datapaths and then 
-operates switching across each bridge described in its configuration 
-files.  If a logfile was specified on the command line it will also 
-be opened or reopened.
+\fBovs\-vswitchd\fR retrieves its configuration from \fIdatabase\fR at
+startup.  It sets up Open vSwitch datapaths and then operates
+switching across each bridge described in its configuration files.  As
+the database changes, \fBovs\-vswitchd\fR automatically updates its
+configuration to match.
+.PP
+Upon receipt of a SIGHUP signal, \fBovs\-vswitchd\fR reopens its log
+file, if one was specified on the command line.
 .PP
 \fBovs\-vswitchd\fR switches may be configured with any of the following 
 features:
@@ -83,16 +90,7 @@ to be loaded.
 \fBovs\-appctl\fR(8) can send commands to a running
 \fBovs\-vswitchd\fR process.  The currently supported commands are
 described below.  The command descriptions assume an understanding of
-how to configure Open vSwitch, as described in
-\fBovs-vswitchd.conf\fR(5).
-.SS "OVS\-VSWITCHD COMMANDS"
-These commands manage the \fBovs-vswitchd\fR process.
-.IP "\fBvswitchd/reload\fR"
-Reloads the \fBovs\-vswitchd\fR configuration file, as if a
-\fBSIGHUP\fR signal were received.  The command completes only after
-reloading is finished, in particular after all datapaths have been
-created and destroyed and ports added and removed as specified by the
-new configuration.
+how to configure Open vSwitch.
 .SS "BRIDGE COMMANDS"
 These commands manage bridges.
 .IP "\fBfdb/show\fR \fIbridge\fR"
@@ -154,6 +152,6 @@ Returns the hash value which would be used for \fImac\fR.
 .so lib/vlog-unixctl.man
 .SH "SEE ALSO"
 .BR ovs\-appctl (8),
-.BR ovs\-vswitchd.conf (5),
 .BR ovs\-brcompatd (8),
+.BR ovsdb\-server (1),
 \fBINSTALL.Linux\fR in the Open vSwitch distribution.
index fd2144abb0da2e20d4ecf7decb7e55f990ffb21a..52a80e090d0577623dbbd531a2f4ed018f5dac64 100644 (file)
 #include <string.h>
 
 #include "bridge.h"
-#include "cfg.h"
 #include "command-line.h"
 #include "compiler.h"
 #include "daemon.h"
 #include "dpif.h"
 #include "fault.h"
 #include "leak-checker.h"
-#include "mgmt.h"
 #include "netdev.h"
-#include "ovs-vswitchd.h"
+#include "ovsdb-idl.h"
 #include "poll-loop.h"
 #include "proc-net-compat.h"
 #include "process.h"
 #include "signals.h"
+#include "stream.h"
 #include "svec.h"
 #include "timeval.h"
 #include "unixctl.h"
 #include "util.h"
 #include "vconn-ssl.h"
 #include "vconn.h"
+#include "vswitchd/vswitch-idl.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_vswitchd
 
-static void parse_options(int argc, char *argv[]);
+static const char *parse_options(int argc, char *argv[]);
 static void usage(void) NO_RETURN;
-static unixctl_cb_func reload;
-
-static bool need_reconfigure;
-static struct unixctl_conn **conns;
-static size_t n_conns;
 
 int
 main(int argc, char *argv[])
 {
     struct unixctl_server *unixctl;
     struct signal *sighup;
+    struct ovsdb_idl *idl;
+    const char *remote;
+    bool need_reconfigure;
+    bool inited;
+    unsigned int idl_seqno;
     int retval;
 
     set_program_name(argv[0]);
     register_fault_handlers();
     time_init();
     vlog_init();
-    parse_options(argc, argv);
+    remote = parse_options(argc, argv);
     signal(SIGPIPE, SIG_IGN);
     sighup = signal_register(SIGHUP);
     process_init();
@@ -79,39 +79,47 @@ main(int argc, char *argv[])
     if (retval) {
         ovs_fatal(retval, "could not listen for control connections");
     }
-    unixctl_command_register("vswitchd/reload", reload, NULL);
 
-    retval = cfg_read();
-    if (retval) {
-        ovs_fatal(retval, "could not read config file");
-    }
-    mgmt_init();
-    bridge_init();
-    mgmt_reconfigure();
+    idl = ovsdb_idl_create(remote, &ovsrec_idl_class);
+    idl_seqno = ovsdb_idl_get_seqno(idl);
 
     need_reconfigure = false;
+    inited = false;
     for (;;) {
-        if (need_reconfigure || signal_poll(sighup)) {
-            need_reconfigure = false;
+        if (signal_poll(sighup)) {
             vlog_reopen_log_file();
-            reconfigure();
         }
-        if (mgmt_run()) {
+        if (inited && bridge_run()) {
             need_reconfigure = true;
         }
-        if (bridge_run()) {
+        ovsdb_idl_run(idl);
+        if (idl_seqno != ovsdb_idl_get_seqno(idl)) {
+            idl_seqno = ovsdb_idl_get_seqno(idl);
             need_reconfigure = true;
         }
+        if (need_reconfigure) {
+            const struct ovsrec_open_vswitch *cfg;
+
+            need_reconfigure = false;
+            cfg = ovsrec_open_vswitch_first(idl);
+            if (cfg) {
+                if (inited) {
+                    bridge_reconfigure(cfg);
+                } else {
+                    bridge_init(cfg);
+                    inited = true;
+                }
+            }
+        }
         unixctl_server_run(unixctl);
         dp_run();
         netdev_run();
 
-        if (need_reconfigure) {
-            poll_immediate_wake();
-        }
         signal_wait(sighup);
-        mgmt_wait();
-        bridge_wait();
+        if (inited) {
+            bridge_wait();
+        }
+        ovsdb_idl_wait(idl);
         unixctl_server_wait(unixctl);
         dp_wait();
         netdev_wait();
@@ -121,32 +129,7 @@ main(int argc, char *argv[])
     return 0;
 }
 
-static void
-reload(struct unixctl_conn *conn, const char *args UNUSED, void *aux UNUSED)
-{
-    need_reconfigure = true;
-    conns = xrealloc(conns, sizeof *conns * (n_conns + 1));
-    conns[n_conns++] = conn;
-}
-
-void
-reconfigure(void)
-{
-    size_t i;
-
-    cfg_read();
-    bridge_reconfigure();
-    mgmt_reconfigure();
-
-    for (i = 0; i < n_conns; i++) {
-        unixctl_command_reply(conns[i], 202, NULL);
-    }
-    free(conns);
-    conns = NULL;
-    n_conns = 0;
-}
-
-static void
+static const char *
 parse_options(int argc, char *argv[])
 {
     enum {
@@ -169,7 +152,6 @@ parse_options(int argc, char *argv[])
         {0, 0, 0, 0},
     };
     char *short_options = long_options_to_short_options(long_options);
-    const char *config_file;
     int error;
 
     for (;;) {
@@ -221,26 +203,21 @@ parse_options(int argc, char *argv[])
     argv += optind;
 
     if (argc != 1) {
-        ovs_fatal(0, "config file is only non-option argument; "
+        ovs_fatal(0, "database socket is only non-option argument; "
                 "use --help for usage");
     }
 
-    cfg_init();
-    config_file = argv[0];
-    error = cfg_set_file(config_file);
-    if (error) {
-       ovs_fatal(error, "failed to add configuration file \"%s\"", 
-                config_file);
-    }
+    return argv[0];
 }
 
 static void
 usage(void)
 {
     printf("%s: Open vSwitch daemon\n"
-           "usage: %s [OPTIONS] CONFIG\n"
-           "CONFIG is a configuration file in ovs-vswitchd.conf(5) format.\n",
+           "usage: %s [OPTIONS] DATABASE\n"
+           "where DATABASE is a socket on which ovsdb-server is listening.\n",
            program_name, program_name);
+    stream_usage("DATABASE", true, false);
     daemon_usage();
     vlog_usage();
     printf("\nLegacy compatibility options:\n"
diff --git a/vswitchd/ovs-vswitchd.conf.5.in b/vswitchd/ovs-vswitchd.conf.5.in
deleted file mode 100644 (file)
index c416678..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-.\" -*- nroff -*-
-.de TQ
-.  br
-.  ns
-.  TP "\\$1"
-..
-.de IQ
-.  br
-.  ns
-.  IP "\\$1"
-..
-.de ST
-.  PP
-.  RS -0.15in
-.  I "\\$1"
-.  RE
-.  PP
-..
-.TH ovs\-vswitchd.conf 5 "June 2009" "Open vSwitch" "Open vSwitch Manual"
-.
-.SH NAME
-ovs\-vswitchd.conf \- configuration file for \fBovs\-vswitchd\fR
-.
-.SH DESCRIPTION
-This manual page explains how to configure \fBovs\-vswitchd\fR, the
-Open vSwitch virtual switch daemon.  Refer to \fBovs\-vswitchd\fR(8)
-for instructions on how to start, stop, and control the virtual switch
-daemon and for an overview of its features.
-.SS "Overview"
-\fBovs\-vswitchd\fR configuration is hierarchical.
-.ST "Global Configuration"
-A few aspects of configuration apply to the entire \fBovs\-vswitchd\fR
-process:
-.IP \(bu
-Remote management (see \fBRemote Management\fR below).
-.IP \(bu
-SSL key and certificate configuration (see \fBSSL Configuration\fR
-below).
-.ST "Bridge Configuration"
-\fBovs\-vswitchd\fR manages one or more ``bridges.''  A bridge is,
-conceptually, an Ethernet switch.  Properties configurable at the
-bridge level include:
-.
-.IP \(bu
-The set of bridge ports (see \fBBridge Configuration\fR below).
-.IP \(bu
-Mirroring of packets across ports and VLANs (see \fBPort mirroring
-(SPAN and RSPAN)\fR below).
-.IP \(bu
-Flow logging via NetFlow (see \fBNetFlow v5 Flow Logging\fR below).
-.IP \(bu
-Connectivity to an OpenFlow controller (see \fBOpenFlow Controller
-Connectivity\fR below).
-.IP \(bu
-Addresses on which to listen for OpenFlow management connections (see
-\fBOpenFlow Management Connections\fR below) or for snooping on the
-connection to the primary OpenFlow controller (see \fBOpenFlow
-Controller Connection Snooping\fR below).
-.PP
-.ST "Port Configuration"
-Each bridge has one or more ``ports.''  The main configurable property
-of a port is its 802.1Q VLAN configuration (see \fB802.1Q VLAN
-support\fR below).
-.PP
-Most commonly, a port has exactly one ``interface.''  Such a port
-logically corresponds to a port on a physical Ethernet switch.
-.PP
-A port that has more than one interface is a ``bonded port.''  Bonding
-allows for load balancing and fail-over (see \fBNetwork Device
-Bonding\fR below).
-.ST "Interface Configuration"
-There are two different kinds of interfaces:
-.IP "``external interfaces''"
-These interfaces are ordinary network devices, e.g. \fBeth0\fR on
-Linux.
-.IP "``internal interfaces''"
-These interfaces are simulated network device that sent and receive
-traffic.  Every bridge has one internal interface called the ``local
-interface'' and may also have additional internal interfaces.  It does
-not make sense to bond an internal interface, so the terms ``port''
-and ``interface'' are often used imprecisely for internal interfaces.
-.PP
-Interfaces have a few configurable properties of their own:
-.IP \(bu
-Ingress rate-limiting (see \fBInterface Rate-Limiting\fR below).
-.IP \(bu
-Ethernet address (internal interfaces only, see \fBBridge
-Configuration\fR below).
-.SS "Configuration File Syntax"
-The \fBovs\-vswitchd\fR configuration file syntax is based on
-key-value pairs, which are given
-one per line in the form \fIkey\fB=\fIvalue\fR.  Each \fIkey\fR
-consists of one or more parts separated by dots,
-e.g. \fIpart1\fB.\fIpart2\fB.\fIpart3\fR.  Each \fIpart\fR may consist
-only of the English letters, digits, and the special characters
-\fB_-@$:+\fR.  White space within \fIvalue\fR  and at the beginning of a
-line is significant, but is otherwise ignored.
-.PP
-If a single key is specified more than once, that key has multiple
-values, one value for each time the key is specified.  The ordering of
-key-value pairs, and the ordering of multiple values for a single key,
-within a configuration file is not significant.
-.PP
-Blank lines, lines that consist only of white space, and lines that
-begin with \fB#\fR (optionally preceded by white space) are ignored.
-Keep in mind that programs that modify the configuration file, such as 
-\fBovs\-brcompatd\fR and \fBovs-cfg-mod\fR, may alter the order of
-elements and 
-strip comments and blank lines.
-.PP
-The following subsections describe how key-value pairs are used to
-configure \fBovs\-vswitchd\fR.
-.SS "Bridge Configuration"
-A bridge (switch) with a given \fIname\fR is configured by specifying
-the names of its network devices as values for key
-\fBbridge.\fIname\fB.port\fR.
-.PP
-To designate network device \fInetdev\fR as an internal port, add
-\fBiface.\fInetdev\fB.internal=true\fR to the configuration file,
-which causes \fBovs\-vswitchd\fR to automatically creates
-\fInetdev\fR, which may then be configured using the usual system
-tools (e.g. \fBifconfig\fR, \fBip\fR).  An internal interface by
-default has a random Ethernet address, but you may configure a
-specific address by setting \fBiface.\fInetdev\fB.mac\fR to a MAC
-address in the format
-\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR, where each
-\fIx\fR is a hex digit.
-.PP
-A bridge with a given \fIname\fR always has an internal port with the
-same \fIname\fR, called the ``local port.''  This network device may
-be included
-in the bridge, by specifying it as one of the values for key
-\fBbridge.\fIname\fB.port\fR, or it may be omitted.  If it is
-included, then its MAC address is by default the lowest-numbered MAC
-address among the other bridge ports, ignoring other internal ports
-and bridge ports that are
-used as port mirroring destinations (see \fBPort Mirroring\fR, below).
-For this purpose, the MAC of a bonded port (see \fBNetwork Device
-Bonding\fR, below) is by default the MAC of its slave whose name is first in
-alphabetical order.
-There are two ways to modify this algorithm for selecting the MAC
-address of the local port:
-.IP \(bu
-To use a specific MAC address for the local port, set
-\fBbridge.\fIname\fB.mac\fR to a MAC address in the format
-\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fB:\fIxx\fR, where each
-\fIx\fR is a hex digit.
-.IP \(bu
-To override the MAC of a port for the purpose of this algorithm, set
-\fBport.\fIport\fB.mac\fR to a MAC address in the format described
-above.
-.PP
-If no valid MAC address can be determined
-either of these ways, then a MAC address is randomly generated.
-.PP
-The following syntax defines a bridge named \fBmybr\fR, configured
-with network devices \fBeth0\fR, \fBeth1\fR, and \fBeth2\fR:
-.RS
-.nf
-
-bridge.mybr.port=eth0
-bridge.mybr.port=eth1
-bridge.mybr.port=eth2
-
-.fi
-.RE
-.SS "802.1Q VLAN support"
-A bridge port may be configured either as a trunk port or as belonging
-to a single, untagged VLAN.  These two options are mutually exclusive,
-and a port must be configured in one way or the other.
-.ST "Trunk Ports"
-By default, bridge ports are trunk ports that carry all VLANs.  To
-limit the VLANs that a trunk port carries, define
-\fBvlan.\fIport\fB.trunks\fR to one or more integers between 0 and
-4095 designating VLANs.  Only frames that have an 802.1Q header with
-one of the listed VLANs are accepted on a trunk port.  If 0 is
-included in the list, then frames without an 802.1Q header are also
-accepted.  Other frames are discarded.
-.PP
-The following syntax makes network device \fBeth0\fR a trunk port that
-carries VLANs 1, 2, and 3:
-.PP
-.RS
-.nf
-
-vlan.eth0.trunks=1
-vlan.eth0.trunks=2
-vlan.eth0.trunks=3
-        
-.fi
-.RE
-.ST "Untagged VLAN Ports"
-A bridge port may be configured with an implicit, untagged VLAN.  
-Define key
-\fBvlan.\fIport\fB.tag\fR to an integer value \fIvid\fR between 0 and
-4095, inclusive, to designate the named \fIport\fR as a member
-of 802.1Q VLAN \fIvid\fR.  When \fIport\fR is assigned a VLAN tag this
-way, frames arriving on trunk ports will be forwarded to \fIport\fR
-only if they are tagged with VLAN \fIvid\fR, and frames arriving on
-other VLAN ports will be forwarded to \fIport\fR only if their
-\fIvid\fR values are equal.  Frames forwarded to \fIport\fR will not
-have an 802.1Q header.
-.PP
-When \fIvid\fR is 0, frames arriving on trunk ports without an 802.1Q
-VLAN header will also be forwarded to \fIport\fR.
-.PP
-When a frame with a 802.1Q header that indicates a nonzero VLAN is
-received on an implicit VLAN port, it is discarded.
-.PP
-The following syntax makes network device \fBeth0\fR a member of VLAN
-101:
-.PP
-.RS
-.nf
-
-vlan.eth0.tag=101
-        
-.fi
-.RE
-.SS "Network Device Bonding"
-Bonding allows multiple ``slave'' network devices to be treated as if
-they were a single virtual ``bonded'' network device.  It is useful for
-load balancing and fail-over.
-.PP
-\fBovs\-vswitchd\fR supports ``source load balancing'' (SLB) bonding, which
-assigns flows to slaves based on source MAC address, with periodic
-rebalancing as traffic patterns change.  This form of bonding does not
-require 802.3ad or other special support from the upstream switch to
-which the slave devices are connected.
-.PP
-To configure bonding, create a virtual bonding device by specifying
-the slave network device names as values for
-\fBbonding.\fIname\fB.slave\fR, then specify \fIname\fR as a bridge
-port.  The chosen \fIname\fR should not be the name of any real
-network device on the host system.
-.PP
-By default, bonding interfaces are enabled or disabled immediately
-when a carrier is detected or dropped on the underlying network
-device.  To insert a delay when carrier comes up or goes down before
-enabling or disabling an interface, set the value of
-\fBbonding.\fIname\fB.updelay\fR or
-\fBbonding.\fIname\fB.downdelay\fR, respectively, to a positive
-integer, interpreted in milliseconds.
-The \fBupdelay\fR setting is honored only when at least one bonded
-interface is already enabled.  When no interfaces are enabled, then
-the first bond interface to come up is enabled immediately.  The
-\fBdowndelay\fR setting is always honored.
-.PP
-The following syntax bonds \fBeth0\fR and \fBeth1\fR into a bonding
-device named \fBbond0\fR, which is added to bridge \fBmybr\fR along
-with physical network devices \fBeth2\fR and \fBeth3\fR:
-.PP
-.RS
-.nf
-
-bridge.mybr.port=bond0
-bridge.mybr.port=eth2
-bridge.mybr.port=eth3
-
-bonding.bond0.slave=eth0
-bonding.bond0.slave=eth1
-        
-.fi
-.RE
-.SS "Port Mirroring (SPAN and RSPAN)"
-\fBovs\-vswitchd\fR may be configured to send selected frames to special
-``mirrored'' ports, in addition to their normal destinations.  Mirroring
-traffic may also be referred to as SPAN or RSPAN, depending on the
-mechanism used for delivery.
-.PP
-Up to 32 instances of port mirroring may be configured on a given
-bridge.  Each must be given a name that is unique within the bridge.
-The keys associated with port mirroring instance \fIpmname\fR for
-bridge \fIbrname\fR begin with \fBmirror.\fIbrname\fB.\fIpmname\fR.
-.PP
-The selection of the frames to mirror and the form in which they
-should be output is configured separately for each port mirroring
-instances, through a subsection of
-\fBmirror.\fIbrname\fB.\fIpmname\fR, named \fBselect\fR, and
-\fBoutput\fR, respectively.
-.ST "Selecting Frames to Mirror"
-The values for the following keys, if specified, limit the frames that
-are chosen for mirroring.  If none of these keys is specified, then
-all frames received by the bridge are mirrored.  If more than one of
-these keys is specified, then a frame must meet all specified criteria
-to be mirrored.
-.TP
-\fBmirror.\fIbrname\fB.\fIpmname\fB.select.src-port=\fIport\fR
-.TQ
-\fBmirror.\fIbrname\fB.\fIpmname\fB.select.dst-port=\fIport\fR
-.TQ
-\fBmirror.\fIbrname\fB.\fIpmname\fB.select.port=\fIport\fR
-Frame received on \fIport\fR, output to \fIport\fR, or either received
-on or output to \fIport\fR, respectively.  \fIport\fR must be part of
-the bridge \fIbrname\fR; that is, it must be listed on
-\fBbridge.\fIbrname\fB.port\fR.
-.TP
-\fBmirror.\fIbrname\fB.\fIpmname\fB.select.vlan=\fIvid\fR
-.
-\fIvid\fR must be an integer between 0 and 4095, inclusive.  A nonzero
-\fIvid\fR selects frames that belong to VLAN \fIvid\fR, that is,
-frames that arrived on a trunk port tagged with VLAN \fIvid\fR or on a
-port that is configured as part of VLAN \fIvid\fR (see \fB802.1Q VLAN
-tagging\fR, above).  A \fIvid\fR of zero selects frames that do not
-belong to a VLAN, that is, frames that arrived on a trunk port without
-a VLAN tag or tagged with VLAN 0.
-.ST "Mirror Output"
-The values of the following keys determine how frames selected for
-mirroring are output.  Only one of the keys may be specified.
-.TP
-\fBmirror.\fIbrname\fB.\fIpmname\fB.output.port=\fIport\fR
-.
-Causes the selected frames to be sent out \fIport\fR, which must be
-part of the bridge \fIbrname\fR; that is, it must be listed on
-\fBbridge.\fIbrname\fB.port\fR.
-.IP
-Specifying a \fIport\fR in this way reserves that port exclusively for
-mirroring.  No frames other than those selected for mirroring will be
-forwarded to \fIport\fR, and any frames received on \fIport\fR will be
-discarded.  This type of mirroring may be referred to as SPAN.
-.TP
-\fBmirror.\fIbrname\fB.\fIpmname\fB.output.vlan=\fIvid\fR
-.
-Causes the selected frames to be sent on the VLAN numbered \fIvid\fR,
-which must be an integer between 0 and 4095, inclusive.  The frames
-will be sent out all ports that trunk VLAN \fIvid\fR, as well as any
-ports with implicit VLAN \fIvid\fR.  When a mirrored frame is sent out
-a trunk port, the frame's VLAN tag will be set to \fIvid\fR, replacing
-any existing tag; when it is sent out an implicit VLAN port, the frame
-will not be tagged.  This type of mirroring may be referred to as
-RSPAN.
-.IP
-Please note that mirroring to a VLAN can disrupt a network that
-contains unmanaged switches.  Consider an unmanaged physical switch
-with two ports: port 1, connected to an end host, and port 2,
-connected to an Open vSwitch configured to mirror received packets
-into VLAN 123 on port 2.  Suppose that the end host sends a packet on
-port 1 that the physical switch forwards to port 2.  The Open vSwitch
-forwards this packet to its destination and then reflects it back on
-port 2 in VLAN 123.  This reflected packet causes the unmanaged
-physical switch to replace the MAC learning table entry, which
-correctly pointed to port 1, with one that incorrectly points to port
-2.  Afterward, the physical switch will direct packets destined for
-the end host to the Open vSwitch on port 2, instead of to the end host
-on port 1, disrupting connectivity.  If mirroring to a VLAN is desired
-in this scenario, then the physical switch must be replaced by one
-that learns Ethernet addresses on a per-VLAN basis.  In addition,
-learning should be disabled on the VLAN containing mirrored traffic.
-If this is not done then intermediate switches will learn the MAC
-address of each end host from the mirrored traffic.  If packets being
-sent to that end host are also mirrored, then they will be dropped
-since the switch will attempt to send them out the input port.
-Disabling learning for the VLAN will cause the switch to correctly
-send the packet out all ports configured for that VLAN.  If Open
-vSwitch is being used as an intermediate switch learning can be disabled
-by setting the key \fBvlan.\fIbrname\fB.learning-disable=\fIvid\fR
-to the mirrored VLAN.
-.ST "Example"
-The following \fBovs\-vswitchd\fR configuration copies all frames received
-on \fBeth1\fR or \fBeth2\fR to \fBeth3\fR.
-.PP
-.RS
-.nf
-
-bridge.mybr.port=eth1
-bridge.mybr.port=eth2
-bridge.mybr.port=eth3
-
-mirror.mybr.a.select.src-port=eth1
-mirror.mybr.a.select.src-port=eth2
-mirror.mybr.a.output.port=eth3
-        
-.fi
-.RE
-.SS "Interface Rate-Limiting"
-Traffic policing and shaping are configured on interfaces.  Policing
-defines a hard limit at which traffic that exceeds the specified rate is
-dropped.  Shaping uses queues to delay packets so that egress traffic
-leaves at the specified rate.
-
-.ST "Ingress Policing"
-The rate at which traffic is allowed to enter through a interface may be 
-configured with ingress policing.  Note that "ingress" is from the 
-perspective of \fBovs\-vswitchd\fR.  If configured on a physical interface, 
-then it limits the rate at which traffic is allowed into the system from 
-the outside.  If configured on a virtual interface that is connected to 
-a virtual machine, then it limits the rate at which the guest is able to 
-transmit.
-
-The rate is specified in kilobits (1000 bits) per second with a maximum 
-burst size specified in kilobits (1000 bits).  The burst size should be at 
-least the size of the interface's MTU.  
-
-An interface may be configured to enforce ingress policing by defining the
-key \fBport.\fIname\fB.ingress.policing-rate\fR with an integer
-indicating the rate.  The interface \fIname\fR will only allow traffic to be
-received at the rate specified in kilobits per second.  If the rate is zero 
-or the key is not defined, then ingress policing is disabled.
-
-If ingress policing is enabled, then the burst rate may be set by defining 
-the key \fBport.\fIname\fB.ingress.policing-burst\fR with an integer 
-indicating the burst rate in kilobits.  If the key is not supplied or is 
-zero, then the default burst is 10 kilobits.
-
-.PP
-The following syntax limits interface \fBeth1\fR to receiving traffic at
-\fB512\fR kilobits per second with a burst of \fB20\fR kilobits:
-.PP
-.RS
-.nf
-
-port.eth1.ingress.policing-rate=512
-port.eth1.ingress.policing-burst=20
-
-.fi
-.SS "NetFlow v5 Flow Logging"
-NetFlow is a protocol that exports a number of details about terminating
-IP flows, such as the principals involved and duration.  A bridge may be
-configured to send NetFlow v5 records to NetFlow collectors when flows
-end.  To enable, define the key \fBnetflow.\fIbridge\fB.host\fR for each
-collector in the form \fIip\fB:\fIport\fR.  Records from \fIbridge\fR
-will be sent to each \fIip\fR on UDP \fIport\fR.  The \fIip\fR must
-be specified numerically, not as a DNS name.
-
-In addition to terminating flows, NetFlow can also send records at a set
-interval for flows that are still active.  This interval can be configured
-by defining the key \fBnetflow.\fIbridge\fB\.active-timeout\fR.  The value
-is in seconds.  An active timeout of 0 will disable this functionality.  By
-default there is timeout value of 600 seconds.
-
-The NetFlow messages will use the datapath index for the engine type and id.
-This can be overridden with the \fBnetflow.\fIbridge\fB.engine-type\fR and
-\fBnetflow.\fIbridge\fB.engine-id\fR, respectively.  Each takes a value
-between 0 and 255, inclusive.
-
-Many NetFlow collectors do not expect multiple switches to be
-sending messages from the same host, and they do not store the engine
-information which could be used to disambiguate the traffic.  To prevent
-flows from multiple switches appearing as if they came on the interface,
-add \fBnetflow.\fIbridge\fB.add-id-to-iface=true\fR to the configuration
-file.  This will place the least significant 7 bits of the engine id
-into the most significant bits of the ingress and egress interface fields
-of flow records.  When this option is enabled, a maximum of 508 ports are
-supported.  By default, this behavior is disabled.
-
-The egress interface field normally contains the OpenFlow port number,
-however, certain port values have special meaning: 0xFFFF indicates
-flooding, 0xFFFE is multiple controller-specified output interfaces, and
-0xFFFD means that packets from the flow were dropped.  If add-id-to-iface
-is enabled then these values become 0x1FF, 0x1FE, and 0x1FD respectively.
-
-The following syntax sends NetFlow records for \fBmybr\fR to the NetFlow
-collector \fBnflow.example.com\fR on UDP port \fB9995\fR:
-.PP
-.RS
-.nf
-
-netflow.mybr.host=nflow.example.com:9995
-
-.fi
-.RE
-.SS "Remote Management"
-A \fBovs\-vswitchd\fR instance may be remotely managed by a controller that
-supports the OpenFlow Management Protocol, such as NOX.  This
-functionality is enabled by setting the key \fBmgmt.controller\fR to one 
-of the following values:
-.
-.IP "\fBssl:\fIip\fR[\fB:\fIport\fR]"
-The specified SSL \fIport\fR (default: 6633) on the host at the given
-\fIip\fR, which must be expressed as an IP address (not a DNS name).
-SSL must be configured when this form is used (see \fBSSL
-Configuration\fR, below).
-.
-.IP "\fBtcp:\fIip\fR[\fB:\fIport\fR]"
-The specified TCP \fIport\fR (default: 6633) on the host at the given
-\fIip\fR, which must be expressed as an IP address (not a DNS name).
-.PP
-The maximum time between attempts to connect to the controller may be
-specified in integral seconds with the \fBmgmt.max-backoff\fR key.  The
-default maximum backoff is 8 seconds, and the minimum value is 1
-second.
-
-An inactivity probe may be configured with the \fBmgmt.inactivity-probe\fR
-key.  If \fBovs\-vswitchd\fR does not communicate with the controller for the
-specified number of seconds, it will send a probe.  If a response is not
-received for an additional amount of that time, \fBovs\-vswitchd\fR assumes
-the connection has been broken and attempts to reconnect.  The default
-and minimum values are both 5 seconds.
-
-A management id may be specified with the \fBmgmt.id\fR key.  It takes
-an id in the form of exactly 12 hexadecimal digits.  If one is not
-specified, a random id is generated each time \fBovs\-vswitchd\fR is started.
-.fi
-.RE
-.SS "OpenFlow Controller Connectivity"
-\fBovs\-vswitchd\fR can perform all configured bridging and switching
-locally, or it can be configured to connect a given bridge to an
-external OpenFlow controller, such as NOX.  Its behavior depends on
-the \fBbridge.\fIname\fB.controller\fR setting:
-.
-.TP
-\fI\[la]unset\[ra]\fR
-When the key is not set, the behavior depends on whether remote 
-management is configured.  If management is configured, then the switch 
-will connect to the controller specified on \fBmgmt.controller\fR.  If 
-management is not configured, the switch will perform all configured 
-bridging and switching locally.
-.
-.TP
-\fI\[la]empty\[ra]\fR
-Setting an empty string value disables controller connectivity.  The
-switch will perform all configured bridging and switching locally.
-.
-.TP
-\fBdiscover\fR
-Use controller discovery to find the local OpenFlow controller.
-Refer to \fB\ovs\-openflowd\fR(8) for information on how to configure a DHCP
-server to support controller discovery.  The following additional
-options control the discovery process:
-.
-.RS
-.TP
-\fBbridge.\fIname\fB.controller.accept-regex=\fIregex\fR
-A POSIX extended regular expression against which the discovered
-controller location is validated.  Only controllers whose names match
-the regular expression will be accepted.
-.IP
-The default regular expression is \fBssl:.*\fR, meaning that only SSL
-controller connections will be accepted, when SSL is configured (see
-\fBSSL Configuration\fR), and \fBtcp:.*\fR otherwise, meaning that only
-TCP controller connections will be accepted.
-.IP
-The regular expression is implicitly anchored at the beginning of the
-controller location string, as if it begins with \fB^\fR.
-.TP
-\fBbridge.\fIname\fB.controller.update-resolv.conf=\fBtrue\fR|\fBfalse\fR
-By default, or if this is set to \fBtrue\fR, \fBovs\-vswitchd\fR overwrites
-the system's \fB/etc/resolv.conf\fR with domain information and DNS
-servers obtained via DHCP.  If this setting is \fBfalse\fR,
-\fBovs\-vswitchd\fR will not modify \fB/etc/resolv.conf\fR.
-.IP
-\fBovs\-vswitchd\fR will only modify \fBresolv.conf\fR if the DHCP response
-that it receives specifies one or more DNS servers.
-.RE
-.
-.TP
-\fBssl:\fIip\fR[\fB:\fIport\fR]
-The specified SSL \fIport\fR (default: 6633) on the host at the given
-\fIip\fR, which must be expressed as an IP address (not a DNS name).
-SSL must be configured when this form is used (see \fBSSL
-Configuration\fR, below).
-.
-.TP
-\fBtcp:\fIip\fR[\fB:\fIport\fR]
-The specified TCP \fIport\fR (default: 6633) on the host at the given
-\fIip\fR, which must be expressed as an IP address (not a DNS name).
-.
-.TP
-\fBunix:\fIfile\fR
-The Unix domain server socket named \fIfile\fR.
-.PP
-The datapath ID used by the bridge to identify itself to the remote
-controller may be specified as \fBbridge.\fIname\fB.datapath-id\fR,
-in the form of exactly 12 hexadecimal digits.  If the datapath ID
-is not specified, then it defaults to the bridge's MAC address (see
-\fBBridge Configuration\fR, above, for information on how the bridge's
-MAC address is chosen).
-.ST "Local Port Network Configuration"
-When an external controller is configured, but controller discovery is
-not in use, the following additional settings are honored:
-.TP
-\fBbridge.\fIname\fB.controller.in-band=\fBtrue\fR|\fBfalse\fR
-By default, or if this is set to \fBtrue\fR, \fBovs\-vswitchd\fR connects
-to the controller in-band.  If this is set to \fBfalse\fR,
-\fBovs\-vswitchd\fR connects to the controller out-of-band.  Refer to
-\fBovs\-openflowd\fR(8) for a description of in-band and out-of-band control.
-.IP "\fBbridge.\fIname\fB.controller.ip=\fIip\fR"
-If specified, the IP address to configure on the bridge's local port.
-.IP "\fBbridge.\fIname\fB.controller.netmask=\fInetmask\fR"
-When an IP is specified, the corresponding netmask.  The default is
-255.255.255.0 for a Class C IP address, 255.255.0.0 for Class B, and
-255.0.0.0 for Class A.
-.IP "\fBbridge.\fIname\fB.controller.gateway=\fIip\fR"
-When an IP is specified, the corresponding IP gateway.  There is no
-default gateway.
-.ST "Controller Failure Settings"
-The following additional settings take effect when any remote
-controller is configured:
-.IP "\fBbridge.\fIname\fB.controller.inactivity-probe=\fIsecs\fR"
-This optional setting may be set to \fIsecs\fR, a number of seconds.
-The minimum value of \fIsecs\fR is 5 seconds.  The default is taken
-from \fBmgmt.inactivity-probe\fR (see above).
-.IP
-When the switch is connected to the controller, it waits for a
-message to be received from the controller for \fIsecs\fR seconds
-before it sends a inactivity probe to the controller.  After sending
-the inactivity probe, if no response is received for an additional
-\fIsecs\fR seconds, \fBovs-vswitchd\fR assumes that the connection has
-been broken and attempts to reconnect.
-.IP
-Changing the inactivity probe interval also changes the interval
-before entering standalone mode (see below).
-.IP "\fBbridge.\fIname\fB.controller.fail-mode=\fBstandalone\fR|\fBsecure\fR"
-.IQ "\fBmgmt.fail-mode=standalone\fR|\fBsecure\fR"
-When a controller is configured, it is, ordinarily, responsible for
-setting up all flows on the switch.  Thus, if the connection to
-the controller fails, no new network connections can be set up.  If
-the connection to the controller stays down long enough, no packets
-can pass through the switch at all.
-.IP
-The first of these that is set takes effect.
-If the value is \fBstandalone\fR, or if neither of these settings
-is set, \fBovs\-vswitchd\fR will take over
-responsibility for setting up
-flows when no message has been received from the controller for three
-times the inactivity probe interval (see above).  In this mode,
-\fBovs\-vswitchd\fR causes the datapath to act like an ordinary
-MAC-learning switch.  \fBovs\-vswitchd\fR will continue to retry connecting
-to the controller in the background and, when the connection succeeds,
-it discontinues its standalone behavior.
-.IP
-If this option is set to \fBsecure\fR, \fBovs\-vswitchd\fR will not
-set up flows on its own when the controller connection fails.
-.IP "\fBbridge.\fIname\fB.controller.max-backoff=\fIsecs\fR"
-Sets the maximum time between attempts to connect to the controller to
-\fIsecs\fR, which must be at least 1.  The actual interval between
-connection attempts starts at 1 second and doubles on each failing
-attempt until it reaches the maximum.  The default maximum backoff
-time is taken from \fBmgmt.max-backoff\fR.
-.ST "Controller Rate-Limiting"
-These settings configure how the switch applies a ``token
-bucket'' to limit the rate at which packets in unknown flows are
-forwarded to the OpenFlow controller for flow-setup processing.  This
-feature prevents a single bridge from overwhelming a controller.
-.PP
-In addition, when a high rate triggers rate-limiting,
-\fBovs\-vswitchd\fR queues controller packets for each port and
-transmits them to the controller at the configured rate.  The number
-of queued packets is limited by a ``burst size'' parameter.  The
-packet queue is shared fairly among the ports on a bridge.
-.PP
-\fBovs\-vswitchd\fR maintains two such packet rate-limiters per
-bridge.  One of these applies to packets sent up to the controller
-because they do not correspond to any flow.  The other applies to
-packets sent up to the controller by request through flow actions.
-When both rate-limiters are filled with packets, the actual rate that
-packets are sent to the controller is up to twice the specified rate.
-.IP "\fBbridge.\fIname\fB.controller.rate-limit=\fIrate\fR"
-.IQ "\fBmgmt.rate-limit=\fIrate\fR"
-Limits the maximum rate at which packets will be forwarded to the
-OpenFlow controller to \fIrate\fR packets per second.  A rate specified
-explicitly for \fIname\fR overrides a value configured using the
-\fBmgmt.rate-limit\fR key.
-.IP
-If neither one of these settings is set, then the bridge does not
-limit the rate at which packets are forwarded to the controller.
-.IP "\fBbridge.\fIname\fB.controller.burst-limit=\fIburst\fR"
-.IQ "\fBmgmt.burst-limit=\fIburst\fR"
-Sets the maximum number of unused packet credits that the bridge will
-allow to accumulate during the time in which no packets are being
-forwarded to the OpenFlow controller to \fIburst\fR (measured in
-packets).  The default \fIburst\fR is one-quarter of the \fIrate\fR
-specified in the rate-limit setting.
-.IP
-A burst specified explicitly for \fIname\fR overrides a value configured 
-using the \fBmgmt.burst-limit\fR key.  This option takes effect only 
-when a rate-limit is specified.
-.ST "Remote Command Execution Settings"
-These settings configure the commands that remote OpenFlow connections
-are allowed to invoke using (e.g.) \fBovs\-ofctl execute\fR.  To be
-permitted, a command name must be whitelisted and must not be
-blacklisted.  When the whitelist and blacklist permit a command name,
-\fBovs\-vswitchd\fR looks for a program with the same name as the command
-in the commands directory (see below).  Other directories are not
-searched.
-.IP "\fBbridge.\fIname\fB.controller.commands.acl=\fIglob\fR"
-Whitelists commands whose names match shell glob pattern \fIglob\fR,
-allowing those commands to be invoked by the remote controller.
-.IP
-By default, no commands are whitelisted, so this setting is mandatory
-if any remote command execution is to be allowed.
-.IP "\fBbridge.\fIname\fB.controller.commands.acl=\fB!\fR\fIglob\fR"
-Blacklists commands whose names match shell glob pattern \fIglob\fR,
-prohibiting those commands from being invoked by the remote
-controller.  Command names that include characters other than upper-
-and lower-case English letters, digits, and the underscore and hyphen
-characters are blacklisted unconditionally.
-.IP "\fBbridge.\fIname\fB.controller.commands.dir=\fIdirectory\fR"
-Sets the directory searched for remote command execution to
-\fIdirectory\fR.  The default directory is
-\fB@pkgdatadir@/commands\fR.
-.SS "SSL Configuration"
-When \fBovs\-vswitchd\fR is configured to connect over SSL for management or
-for controller connectivity, the following settings are required:
-.TP
-\fBssl.private-key=\fIprivkey.pem\fR
-Specifies a PEM file containing the private key used as the 
-switch's identity for SSL connections to the controller.
-.TP
-\fBssl.certificate=\fIcert.pem\fR
-Specifies a PEM file containing a certificate, signed by the
-certificate authority (CA) used by the controller and manager, that
-certifies the switch's private key, identifying a trustworthy
-switch.
-.TP
-\fBssl.ca-cert=\fIcacert.pem\fR
-Specifies a PEM file containing the CA certificate used to verify that
-the switch is connected to a trustworthy controller.
-.PP
-These files are read only once, at \fBovs\-vswitchd\fR startup time.  If
-their contents change, \fBovs\-vswitchd\fR must be killed and restarted.
-.PP
-These SSL settings apply to all SSL connections made by the switch.
-.ST "CA Certificate Bootstrap"
-Ordinarily, all of the files named in the SSL configuration must exist
-when \fBovs\-vswitchd\fR starts.  However, if \fBssl.bootstrap-ca-cert\fR
-is set to \fBtrue\fR, then \fBovs\-vswitchd\fR will attempt to obtain the
-CA certificate from the controller on its first SSL connection and
-save it to the named PEM file.  If it is successful, it will
-immediately drop the connection and reconnect, and from then on all
-SSL connections must be authenticated by a certificate signed by the
-CA certificate thus obtained.
-.PP
-\fBThis option exposes the SSL connection to a man-in-the-middle
-attack obtaining the initial CA certificate\fR, but it may be useful
-for bootstrapping.
-.PP
-This option is only useful if the controller sends its CA certificate
-as part of the SSL certificate chain.  The SSL protocol does not
-require the controller to send the CA certificate, but
-\fBcontroller\fR(8) can be configured to do so with the
-\fB--peer-ca-cert\fR option.
-.SS "OpenFlow Management Connections"
-By default, each bridge \fIname\fR listens for OpenFlow management
-connections on a Unix domain socket named
-\fB@RUNDIR@/\fIname\fB.mgmt\fR.  This socket can be used to perform
-local OpenFlow monitoring and administration, e.g., \fBovs\-ofctl dump-flows
-unix:@RUNDIR@/\fIname\fB.mgmt\fR to display the flows currently set up
-in bridge \fIname\fR.
-.PP
-If \fBbridge.\fIname\fB.openflow.listeners\fR is set to one or more
-values, \fBovs\-vswitchd\fR instead listens on the specified connection
-methods.  Acceptable connection methods include:
-.RS
-.IP "\fBpunix:\fIfile\fR"
-Listens for connections on the Unix domain server socket named \fIfile\fR.
-.IP "\fBpssl:\fR[\fIport\fR]"
-Listens for SSL connections on \fIport\fR (default: 6633).  SSL must
-be configured when this form is used (see \fBSSL Configuration\fR,
-above).
-.IP "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
-Listens for TCP connections on \fIport\fR (default: 6633).
-By default, \fB\ovs\-vswitchd\fR listens for connections to any local
-IP address, but \fIip\fR may be specified to limit connections to the
-specified local \fIip\fR.
-.RE
-To entirely disable listening for management connections, set
-\fBbridge.\fIname\fB.openflow.listeners\fR to the single value
-\fBnone\fR.
-
-.SS "OpenFlow Controller Connection Snooping"
-By default, each bridge \fIname\fR listens for OpenFlow controller
-connection snooping connections on a Unix domain socket named
-\fB@RUNDIR@/\fIname\fB.snoop\fR.  A client that connects to this
-socket, e.g., \fBovs\-ofctl monitor unix:@RUNDIR@/\fIname\fB.snoop\fR, will
-receive a copy of every OpenFlow message sent by the switch to the
-controller, or vice versa, on the primary OpenFlow controller
-connection.
-.PP
-If \fBbridge.\fIname\fB.openflow.snoops\fR is set to one or more
-values, \fBovs\-vswitchd\fR instead listens on the specified connection
-methods.  The acceptable connection methods are the same as for
-OpenFlow management connections (see above).
-.PP
-To entirely disable controller connection snooping, set
-\fBbridge.\fIname\fB.openflow.snoops\fR to the single value
-\fBnone\fR.
-.SH "SEE ALSO"
-.BR ovs\-brcompatd (8),
-.BR ovs\-cfg\-mod (8),
-.BR ovs\-vswitchd (8)
diff --git a/vswitchd/ovs-vswitchd.h b/vswitchd/ovs-vswitchd.h
deleted file mode 100644 (file)
index 3877f88..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Copyright (c) 2009 Nicira Networks
- *
- * 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 VSWITCHD_H
-#define VSWITCHD_H 1
-
-void reconfigure(void);
-
-#endif /* ovs-vswitchd.h */
index df50bf0219d7dbd7c8be3a830394651d14d97379..e713d6fe88aa466405d85754385ed058b8bd3047 100644 (file)
@@ -46,7 +46,7 @@
          "type": {"key": "uuid", "keyRefTable": "Mirror", "min": 0, "max": "unlimited"}},
        "netflow": {
          "comment": "NetFlow configuration.",
-         "type": {"key": "uuid", "keyRefTable": "NetFlow", "min": 0, "max": "unlimited"}},
+         "type": {"key": "uuid", "keyRefTable": "NetFlow", "min": 0, "max": 1}},
        "controller": {
          "comment": "OpenFlow controller.  If unset, defaults to that specified by the parent Open_vSwitch.",
          "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}}}},
        "tag": {
          "comment": "This port's implicitly tagged VLAN.  Should be empty if this is a trunk port.",
          "type": {"key": "integer", "min": 0, "max": 1}},
-       "updelay": {
+       "mac": {
+         "comment": "The MAC address to use for this port for the purpose of choosing the bridge's MAC address.  This column does not necessarily reflect the port's actual MAC address, nor will setting it change the port's actual MAC address.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "bond_updelay": {
          "comment": "For a bonded port, the number of milliseconds for which carrier must stay up on an interface before the interface is considered to be up.  Ignored for non-bonded ports.",
          "type": "integer"},
-       "downdelay": {
+       "bond_downdelay": {
          "comment": "For a bonded port, the number of milliseconds for which carrier must stay down on an interface before the interface is considered to be down.  Ignored for non-bonded ports.",
-         "type": "integer"}}},
+         "type": "integer"},
+       "bond_fake_iface": {
+         "comment": "For a bonded port, whether to create a fake interface with the name of the port.  Use only for compatibility with legacy software that requires this.",
+         "type": "boolean"}}},
    "Interface": {
      "comment": "An interface within a Port.",
      "columns": {
        "name": {
          "comment": "Interface name.  Should be alphanumeric and no more than about 8 bytes long.  May be the same as the port name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
          "type": "string"},
+       "type": {
+         "comment": "The interface type.  Normal network devices, e.g. eth0, have type \"system\" or \"\" (which are synonyms).  Internal ports have type \"internal\".  TUN/TAP devices have type \"tap\".",
+         "type": "string"},
+       "options": {
+         "comment": "Configuration options whose interpretation varies based on \"type\".",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
        "internal": {
          "comment": "An \"internal\" port is one that is implemented in software as a logical device.",
          "type": "boolean"},
          "type": "integer"},
        "ingress_policing_burst": {
          "comment": "Maximum burst size for data received on this interface, in kb.  The default burst size if set to 0 is 10 kb.",
-         "type": "integer"}}},
+         "type": "integer"},
+       "mac": {
+         "comment": "Ethernet address to set for this interface.  If unset then the default MAC address is used.  May not be supported on all interfaces.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
+         "type": {"key": "string", "min": 0, "max": 1}}}},
    "Mirror": {
      "comment": "A port mirror within a Bridge.",
      "columns": {
    "NetFlow": {
      "comment": "A NetFlow target.",
      "columns": {
-       "target": {
-         "comment": "NetFlow target in the form \"IP:PORT\".",
-         "type": "string"},
+       "targets": {
+         "comment": "NetFlow targets in the form \"IP:PORT\".",
+         "type": {"key": "string", "min": 1, "max": "unlimited"}},
        "engine_type": {
          "comment": "Engine type to use in NetFlow messages.  Defaults to datapath index if not specified.",
          "type": "integer", "min":0, "max":1},
          "type": "integer", "min":0, "max":1},
        "add_id_to_interface": {
          "comment": "Place least-significant 7 bits of engine ID into most significant bits of ingress and egress interface fields of NetFlow records?",
-         "type": "boolean"}}},
+         "type": "boolean"},
+       "active_timeout": {
+         "comment": "Active timeout interval, in seconds.  A value of 0 requests the default timeout; a negative value disables active timeouts.",
+         "type": "integer"}}},
    "Controller": {
      "comment": "An OpenFlow controller.",
      "columns": {
        "target": {
-         "comment": "Connection method for controller, e.g. \"ssl:...\", \"tcp:...\".  The special string \"discover\" enables controller discovery.",
+         "comment": "Connection method for controller, e.g. \"ssl:...\", \"tcp:...\".  The special string \"discover\" enables controller discovery.  The special string \"none\" disables the controller.",
          "type": "string"},
        "max_backoff": {
          "comment": "Maximum number of milliseconds to wait between connection attempts.  Default is implementation-specific.",
          "type": "string"},
        "ca_cert": {
          "comment": "Name of a PEM file containing the CA certificate used to verify that the switch is connected to a trustworthy controller.",
-         "type": "string"}}}}}
+         "type": "string"},
+       "bootstrap_ca_cert": {
+         "comment": "If set to true, then Open vSwitch will attempt to obtain the CA certificate from the controller on its first SSL connection and save it to the named PEM file. If it is successful, it will immediately drop the connection and reconnect, and from then on all SSL connections must be authenticated by a certificate signed by the CA certificate thus obtained.  This option exposes the SSL connection to a man-in-the-middle attack obtaining the initial CA certificate, but it may be useful for bootstrapping.",
+         "type": "boolean"}}}}}