ovs-vsctl is a command-line interface to the Open vSwitch database,
and as such it just modifies the desired Open vSwitch configuration in
the database.  ovs-vswitchd, on the other hand, monitors the database
and implements the actual configuration specified in the database.
This can lead to surprises when the user makes a change to the
database, with ovs-vsctl, that ovs-vswitchd cannot actually
implement. In such a case, the ovs-vsctl command silently succeeds
(because the database was successfully updated) but its desired
effects don't actually take place. One good example of such a change
is attempting to add a port with a misspelled name (e.g. ``ovs-vsctl
add-port br0 fth0'', where fth0 should be eth0); another is creating
a bridge or a port whose name is longer than supported
(e.g. ``ovs-vsctl add-br'' with a 16-character bridge name on
Linux). It can take users a long time to realize the error, because it
requires looking through the ovs-vswitchd log.

The patch improves the situation by checking whether operations that
ovs executes succeed and report an error when
they do not.  This patch only report add-br and add-port
operation errors by examining the `ofport' value that
ovs-vswitchd stores into the database record for the newly created
interface.  Until ovs-vswitchd finishes implementing the new
configuration, this column is empty, and after it finishes it is
either -1 (on failure) or a positive number (on success).

CC: Thomas Graf <tg...@redhat.com>
Co-authored-by: Thomas Graf <tg...@redhat.com>
Signed-off-by: Andy Zhou <az...@nicira.com>

---
V0-V1:
* This patch is prepared as part of OVS Hackathon 2014.

* Ben has provided many valuable inputs on the implementation
  approach. The commit message is almost entirely his words
  lifted from the Hackathon project idea write up.

* Thomas: Some of the code and ideas are imported from your
  12/11/2012 patch titled "ovs-vsctl: Check "ofport" column after
  adding a new port", and subsequent mailing list discussions.
  Please feel free to review, fix and enhance the patch as
  you see fit. More testing will is definitly needed. If make sense,
  we can add more unit test cases. The ovs-vsctl manpage needs to be
  updated. Please re-post the patch as v2 when you are done with
  your changes.
---
 tests/ovs-vsctl.at    |    8 +++--
 utilities/ovs-vsctl.c |   91 ++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
index 851e4d8..e62156b 100644
--- a/tests/ovs-vsctl.at
+++ b/tests/ovs-vsctl.at
@@ -1209,7 +1209,9 @@ m4_foreach(
 [vxlan_system]],
 [
 # Try creating the port
-AT_CHECK([ovs-vsctl add-port br0 reserved_name], [0], [], [])
+AT_CHECK([ovs-vsctl add-port br0 reserved_name], [1], [], [dnl
+ovs-vsctl: Unable to add 'reserved_name'
+])
 # Detect the warning log message
 AT_CHECK([sed -n "s/^.*\(|bridge|WARN|.*\)$/\1/p" ovs-vswitchd.log], [0], [dnl
 |bridge|WARN|could not create interface reserved_name, name is reserved
@@ -1242,7 +1244,9 @@ m4_foreach(
 [vxlan_system]],
 [
 # Try creating the port
-AT_CHECK([ovs-vsctl add-port br0 reserved_name], [0], [], [])
+AT_CHECK([ovs-vsctl add-port br0 reserved_name], [1], [], [dnl
+ovs-vsctl: Unable to add 'reserved_name'
+])
 # Detect the warning log message
 AT_CHECK([sed -n "s/^.*\(|bridge|WARN|.*\)$/\1/p" ovs-vswitchd.log], [0], [dnl
 |bridge|WARN|could not create interface reserved_name, name is reserved
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index 21ac777..1323d3c 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -165,6 +165,34 @@ static bool is_condition_satisfied(const struct 
vsctl_table_class *,
                                    const char *arg,
                                    struct ovsdb_symbol_table *);
 
+/* Post_db_reload_check frame work is to allow ovs-vsctl to do additional
+ * checks after OVSDB transactions are successfully recorded and reload by
+ * ovs-vswitchd.
+ *
+ * For example, When a new interface is added to OVSDB, ovs-vswitchd will
+ * either store a positive values on successful implementing the new
+ * interface, or -1 on failure.
+ *
+ * Unless -no-wait command line option is specified,
+ * post_db_reload_do_checks() is called right after any configuration
+ * changes is picked up (i.e. reload) by ovs-vswitchd. Any error detected
+ * post OVSDB reload is reported as ovs-vsctl errors. OVS-vswitchd logs
+ * more detailed messages about those errors.
+ *
+ * Current implementation only check for Post OVSDB reload failures on new
+ * interface additions with 'add-br' and 'add-port' commands.
+ *
+ * post_db_reload_expect_iface()
+ * post_db_reload_unexpect_iface()
+ *
+ * keep track of interfaces to be checked post OVSDB reload. */
+static void post_db_reload_check_init(void);
+static void post_db_reload_do_checks(const struct ovsdb_idl *idl);
+static void post_db_reload_expect_iface(const char *iface);
+static void post_db_reload_unexpect_iface(const char *iface);
+static void post_db_reload_check_cleanup(void);
+static struct sset neoteric_ifaces;
+
 int
 main(int argc, char *argv[])
 {
@@ -181,6 +209,7 @@ main(int argc, char *argv[])
     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
     vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
     ovsrec_init();
+    post_db_reload_check_init();
 
     /* Log our arguments.  This is often valuable for debugging systems. */
     args = process_escape_args(argv);
@@ -1004,6 +1033,7 @@ pre_get_info(struct vsctl_context *ctx)
     ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_interfaces);
 
     ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name);
+    ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport);
 }
 
 static void
@@ -1659,6 +1689,7 @@ cmd_add_br(struct vsctl_context *ctx)
         bridge_insert_port(br, port);
     }
 
+    post_db_reload_expect_iface(br_name);
     vsctl_context_invalidate_cache(ctx);
 }
 
@@ -1672,6 +1703,7 @@ del_port(struct vsctl_context *ctx, struct vsctl_port 
*port)
                         : port->bridge->br_cfg), port->port_cfg);
 
     LIST_FOR_EACH_SAFE (iface, next_iface, ifaces_node, &port->ifaces) {
+        post_db_reload_unexpect_iface(iface->iface_cfg->name);
         del_cached_iface(ctx, iface);
     }
     del_cached_port(ctx, port);
@@ -1699,6 +1731,7 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge 
*br)
         }
     }
 
+    post_db_reload_unexpect_iface(br->name);
     del_cached_bridge(ctx, br);
 }
 
@@ -1952,6 +1985,7 @@ add_port(struct vsctl_context *ctx,
     for (i = 0; i < n_ifaces; i++) {
         ifaces[i] = ovsrec_interface_insert(ctx->txn);
         ovsrec_interface_set_name(ifaces[i], iface_names[i]);
+        post_db_reload_expect_iface(iface_names[i]);
     }
 
     port = ovsrec_port_insert(ctx->txn);
@@ -3644,6 +3678,59 @@ post_create(struct vsctl_context *ctx)
 }
 
 static void
+post_db_reload_check_init(void)
+{
+    sset_init(&neoteric_ifaces);
+}
+
+static void
+post_db_reload_expect_iface(const char *iface)
+{
+    sset_add_assert(&neoteric_ifaces, iface);
+}
+
+static void
+post_db_reload_unexpect_iface(const char *iface)
+{
+    sset_find_and_delete(&neoteric_ifaces, iface);
+}
+
+static void
+append_dead_iface(struct ds *ds, const char *iface)
+{
+    if (strlen(ds_cstr(ds))) {
+        ds_put_cstr(ds, ", ");
+    }
+    ds_put_format(ds, "%s", iface);
+}
+
+static void
+post_db_reload_do_checks(const struct ovsdb_idl *idl)
+{
+    struct ds dead_ifaces = DS_EMPTY_INITIALIZER;
+    const struct ovsrec_interface *iface;
+
+    OVSREC_INTERFACE_FOR_EACH (iface, idl) {
+        if (sset_contains(&neoteric_ifaces, iface->name) &&
+            (!iface->ofport || *iface->ofport == -1)) {
+            append_dead_iface(&dead_ifaces, iface->name);
+        }
+    }
+
+    if (strlen(ds_cstr(&dead_ifaces))) {
+        vsctl_fatal("Unable to add '%s'", ds_cstr(&dead_ifaces));
+    }
+
+    ds_destroy(&dead_ifaces);
+}
+
+static void
+post_db_reload_check_cleanup(void)
+{
+    sset_destroy(&neoteric_ifaces);
+}
+
+static void
 pre_cmd_destroy(struct vsctl_context *ctx)
 {
     const char *table_name = ctx->argv[1];
@@ -4134,6 +4221,7 @@ do_vsctl(const char *args, struct vsctl_command 
*commands, size_t n_commands,
             ovsdb_idl_run(idl);
             OVSREC_OPEN_VSWITCH_FOR_EACH (ovs, idl) {
                 if (ovs->cur_cfg >= next_cfg) {
+                    post_db_reload_do_checks(idl);
                     goto done;
                 }
             }
@@ -4142,6 +4230,7 @@ do_vsctl(const char *args, struct vsctl_command 
*commands, size_t n_commands,
         }
     done: ;
     }
+    post_db_reload_check_cleanup();
     ovsdb_idl_destroy(idl);
 
     exit(EXIT_SUCCESS);
-- 
1.7.9.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to