From: Andy Zhou <az...@nicira.com> 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). Signed-off-by: Andy Zhou <az...@nicira.com> Signed-off-by: Thomas Graf <tg...@redhat.com> --- V2: Improved error message to indicate error occurs during setup and that additional details can be found in the log. --- tests/ovs-vsctl.at | 8 +++-- utilities/ovs-vsctl.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 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..05aea87 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,60 @@ 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("Error detected while setting up '%s'. See log for details.", + 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 +4222,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 +4231,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.8.3.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev