/*
- * 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.
#include "compiler.h"
#include "dirs.h"
#include "dynamic-string.h"
+#include "fatal-signal.h"
#include "hash.h"
#include "json.h"
#include "ovsdb-data.h"
static struct table_style table_style = TABLE_STYLE_DEFAULT;
/* All supported commands. */
-static const struct vsctl_command_syntax all_commands[];
+static const struct vsctl_command_syntax *get_all_commands(void);
/* The IDL we're using and the current transaction, if any.
* This is for use by vsctl_exit() only, to allow it to clean up.
static struct ovsdb_idl *the_idl;
static struct ovsdb_idl_txn *the_idl_txn;
-static void vsctl_exit(int status) NO_RETURN;
-static void vsctl_fatal(const char *, ...) PRINTF_FORMAT(1, 2) NO_RETURN;
+NO_RETURN static void vsctl_exit(int status);
+NO_RETURN static void vsctl_fatal(const char *, ...) PRINTF_FORMAT(1, 2);
static char *default_db(void);
-static void usage(void) NO_RETURN;
+NO_RETURN static void usage(void);
static void parse_options(int argc, char *argv[], struct shash *local_options);
static bool might_write_to_db(char **argv);
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()
+ *
+ * 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 vsctl_context *);
+static void post_db_reload_expect_iface(const struct ovsrec_interface *);
+
+static struct uuid *neoteric_ifaces;
+static size_t n_neoteric_ifaces;
+static size_t allocated_neoteric_ifaces;
+
int
main(int argc, char *argv[])
{
char *args;
set_program_name(argv[0]);
- signal(SIGPIPE, SIG_IGN);
+ fatal_ignore_sigpipe();
vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
ovsrec_init();
options = xmemdup(global_long_options, sizeof global_long_options);
allocated_options = ARRAY_SIZE(global_long_options);
n_options = n_global_long_options;
- for (p = all_commands; p->name; p++) {
+ for (p = get_all_commands(); p->name; p++) {
if (p->options[0]) {
char *save_ptr = NULL;
char *name;
case 'V':
ovs_print_version(0, 0);
+ printf("DB Schema %s\n", ovsrec_get_db_version());
exit(EXIT_SUCCESS);
case 't':
if (shash_is_empty(&commands)) {
const struct vsctl_command_syntax *p;
- for (p = all_commands; p->name; p++) {
+ for (p = get_all_commands(); p->name; p++) {
shash_add_assert(&commands, p->name, p);
}
}
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
&ovsrec_interface_col_name,
{&ovsrec_interface_col_type,
&ovsrec_interface_col_options,
- NULL},
+ &ovsrec_interface_col_error},
false},
{&ovsrec_table_controller,
{
bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
const char *br_name, *parent_name;
+ struct ovsrec_interface *iface;
int vlan;
br_name = ctx->argv[1];
if (!parent_name) {
struct ovsrec_port *port;
- struct ovsrec_interface *iface;
struct ovsrec_bridge *br;
iface = ovsrec_interface_insert(ctx->txn);
} else {
struct vsctl_bridge *parent;
struct ovsrec_port *port;
- struct ovsrec_interface *iface;
struct ovsrec_bridge *br;
int64_t tag = vlan;
bridge_insert_port(br, port);
}
+ post_db_reload_expect_iface(iface);
vsctl_context_invalidate_cache(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(ifaces[i]);
}
port = ovsrec_port_insert(ctx->txn);
vsctl_context_populate_cache(ctx);
if (find_bridge(ctx, target, false)) {
- vsctl_fatal("cannot delete port %s because it is the local port "
- "for bridge %s (deleting this port requires deleting "
- "the entire bridge)", target, target);
+ if (must_exist) {
+ vsctl_fatal("cannot delete port %s because it is the local port "
+ "for bridge %s (deleting this port requires deleting "
+ "the entire bridge)", target, target);
+ }
+ port = NULL;
} else if (!with_iface) {
port = find_port(ctx, target, must_exist);
} else {
const struct ovsdb_idl_row *row;
struct uuid uuid;
+ row = NULL;
if (uuid_from_string(&uuid, record_id)) {
row = ovsdb_idl_get_row_for_uuid(ctx->idl, table->class, &uuid);
- } else {
+ }
+ if (!row) {
int i;
for (i = 0; i < ARRAY_SIZE(table->row_ids); i++) {
}
static void
-check_mutable(const struct vsctl_table_class *table,
+check_mutable(const struct ovsdb_idl_row *row,
const struct ovsdb_idl_column *column)
{
- if (!column->mutable) {
+ if (!ovsdb_idl_is_mutable(row, column)) {
vsctl_fatal("cannot modify read-only column %s in table %s",
- column->name, table->class->name);
+ column->name, row->table->class->name);
}
}
table = pre_get_table(ctx, table_name);
for (i = 3; i < ctx->argc; i++) {
- const struct ovsdb_idl_column *column;
-
- column = pre_parse_column_key_value(ctx, ctx->argv[i], table);
- check_mutable(table, column);
+ pre_parse_column_key_value(ctx, ctx->argv[i], table);
}
}
if (!value_string) {
vsctl_fatal("%s: missing value", arg);
}
+ check_mutable(row, column);
if (key_string) {
union ovsdb_atom key, value;
ovsdb_datum_union(&datum, ovsdb_idl_read(row, column),
&column->type, false);
+ ovsdb_idl_txn_verify(row, column);
ovsdb_idl_txn_write(row, column, &datum);
} else {
struct ovsdb_datum datum;
table = pre_get_table(ctx, table_name);
pre_get_column(ctx, table, column_name, &column);
- check_mutable(table, column);
}
static void
if (!row) {
return;
}
+ check_mutable(row, column);
type = &column->type;
ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
table = pre_get_table(ctx, table_name);
pre_get_column(ctx, table, column_name, &column);
- check_mutable(table, column);
}
static void
if (!row) {
return;
}
+ check_mutable(row, column);
type = &column->type;
ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
rm_type.n_max = UINT_MAX;
error = ovsdb_datum_from_string(&rm, &rm_type,
ctx->argv[i], ctx->symtab);
- if (error && ovsdb_type_is_map(&rm_type)) {
- free(error);
- rm_type.value.type = OVSDB_TYPE_VOID;
- die_if_error(ovsdb_datum_from_string(&rm, &rm_type,
- ctx->argv[i], ctx->symtab));
+ if (error) {
+ if (ovsdb_type_is_map(&rm_type)) {
+ rm_type.value.type = OVSDB_TYPE_VOID;
+ free(error);
+ die_if_error(ovsdb_datum_from_string(
+ &rm, &rm_type, ctx->argv[i], ctx->symtab));
+ } else {
+ vsctl_fatal("%s", error);
+ }
}
ovsdb_datum_subtract(&old, type, &rm, &rm_type);
ovsdb_datum_destroy(&rm, &rm_type);
const struct ovsdb_idl_column *column;
pre_get_column(ctx, table, ctx->argv[i], &column);
- check_mutable(table, column);
}
}
struct ovsdb_datum datum;
die_if_error(get_column(table, ctx->argv[i], &column));
+ check_mutable(row, column);
type = &column->type;
if (type->n_min > 0) {
struct uuid dummy;
if (!uuid_from_string(&dummy, ds_cstr(&ctx->output))) {
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
real = ovsdb_idl_txn_get_insert_uuid(ctx->txn, &dummy);
if (real) {
ds_put_char(&ctx->output, '\n');
}
+static void
+post_db_reload_check_init(void)
+{
+ n_neoteric_ifaces = 0;
+}
+
+static void
+post_db_reload_expect_iface(const struct ovsrec_interface *iface)
+{
+ if (n_neoteric_ifaces >= allocated_neoteric_ifaces) {
+ neoteric_ifaces = x2nrealloc(neoteric_ifaces,
+ &allocated_neoteric_ifaces,
+ sizeof *neoteric_ifaces);
+ }
+ neoteric_ifaces[n_neoteric_ifaces++] = iface->header_.uuid;
+}
+
+static void
+post_db_reload_do_checks(const struct vsctl_context *ctx)
+{
+ struct ds dead_ifaces = DS_EMPTY_INITIALIZER;
+ size_t i;
+
+ for (i = 0; i < n_neoteric_ifaces; i++) {
+ const struct uuid *uuid;
+
+ uuid = ovsdb_idl_txn_get_insert_uuid(ctx->txn, &neoteric_ifaces[i]);
+ if (uuid) {
+ const struct ovsrec_interface *iface;
+
+ iface = ovsrec_interface_get_for_uuid(ctx->idl, uuid);
+ if (iface && (!iface->ofport || *iface->ofport == -1)) {
+ ds_put_format(&dead_ifaces, "'%s', ", iface->name);
+ }
+ }
+ }
+
+ if (dead_ifaces.length) {
+ dead_ifaces.length -= 2; /* Strip off trailing comma and space. */
+ ovs_error(0, "Error detected while setting up %s. See ovs-vswitchd "
+ "log for details.", ds_cstr(&dead_ifaces));
+ }
+
+ ds_destroy(&dead_ifaces);
+}
+
static void
pre_cmd_destroy(struct vsctl_context *ctx)
{
return ovsdb_datum_includes_all(b, a, type);
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
&ovsrec_open_vswitch_col_next_cfg);
}
+ post_db_reload_check_init();
symtab = ovsdb_symbol_table_create();
for (c = commands; c < &commands[n_commands]; c++) {
ds_init(&c->output);
}
}
error = xstrdup(ovsdb_idl_txn_get_error(txn));
- ovsdb_idl_txn_destroy(txn);
- txn = the_idl_txn = NULL;
switch (status) {
case TXN_UNCOMMITTED:
case TXN_INCOMPLETE:
- NOT_REACHED();
+ OVS_NOT_REACHED();
case TXN_ABORTED:
/* Should not happen--we never call ovsdb_idl_txn_abort(). */
vsctl_fatal("database not locked");
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
free(error);
free(commands);
if (wait_for_reload && status != TXN_UNCHANGED) {
+ /* Even, if --retry flag was not specified, ovs-vsctl still
+ * has to retry to establish OVSDB connection, if wait_for_reload
+ * was set. Otherwise, ovs-vsctl would end up waiting forever
+ * until cur_cfg would be updated. */
+ ovsdb_idl_enable_reconnect(idl);
for (;;) {
ovsdb_idl_run(idl);
OVSREC_OPEN_VSWITCH_FOR_EACH (ovs, idl) {
if (ovs->cur_cfg >= next_cfg) {
+ post_db_reload_do_checks(&ctx);
goto done;
}
}
}
done: ;
}
+ ovsdb_idl_txn_destroy(txn);
ovsdb_idl_destroy(idl);
exit(EXIT_SUCCESS);
{NULL, 0, 0, NULL, NULL, NULL, NULL, RO},
};
+static const struct vsctl_command_syntax *get_all_commands(void)
+{
+ return all_commands;
+}