/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "compiler.h"
#include "dirs.h"
#include "dynamic-string.h"
+#include "fatal-signal.h"
#include "hash.h"
#include "json.h"
#include "ovsdb-data.h"
#include "table.h"
#include "timeval.h"
#include "util.h"
-#include "vconn.h"
-#include "vlog.h"
+#include "openvswitch/vconn.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(vsctl);
int min_args; /* Min number of arguments following name. */
int max_args; /* Max number of arguments following name. */
+ /* Names that roughly describe the arguments that the command
+ * uses. These should be similar to the names displayed in the
+ * man page or in the help output. */
+ const char *arguments;
+
/* If nonnull, calls ovsdb_idl_add_column() or ovsdb_idl_add_table() for
* each column or table in ctx->idl that it uses. */
void (*prerequisites)(struct vsctl_context *ctx);
/* A comma-separated list of supported options, e.g. "--a,--b", or the
* empty string if the command does not support any options. */
const char *options;
+
enum { RO, RW } mode; /* Does this command modify the database? */
};
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;
+OVS_NO_RETURN static void vsctl_exit(int status);
+OVS_NO_RETURN static void vsctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2);
static char *default_db(void);
-static void usage(void) NO_RETURN;
+OVS_NO_RETURN static void usage(void);
+OVS_NO_RETURN static void print_vsctl_commands(void);
+OVS_NO_RETURN static void print_vsctl_options(const struct option *options);
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);
+ vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
ovsrec_init();
/* Log our arguments. This is often valuable for debugging systems. */
OPT_PEER_CA_CERT,
OPT_LOCAL,
OPT_RETRY,
+ OPT_COMMANDS,
+ OPT_OPTIONS,
VLOG_OPTION_ENUMS,
TABLE_OPTION_ENUMS
};
{"timeout", required_argument, NULL, 't'},
{"retry", no_argument, NULL, OPT_RETRY},
{"help", no_argument, NULL, 'h'},
+ {"commands", no_argument, NULL, OPT_COMMANDS},
+ {"options", no_argument, NULL, OPT_OPTIONS},
{"version", no_argument, NULL, 'V'},
VLOG_LONG_OPTIONS,
TABLE_LONG_OPTIONS,
size_t n_options;
size_t i;
- tmp = long_options_to_short_options(global_long_options);
+ tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
short_options = xasprintf("+%s", tmp);
free(tmp);
case 'h':
usage();
+ case OPT_COMMANDS:
+ print_vsctl_commands();
+
+ case OPT_OPTIONS:
+ print_vsctl_options(global_long_options);
+
case 'V':
ovs_print_version(0, 0);
+ printf("DB Schema %s\n", ovsrec_get_db_version());
exit(EXIT_SUCCESS);
case 't':
del-ssl delete the SSL configuration\n\
set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\n\
\n\
+Auto Attach commands:\n\
+ add-aa-mapping BRIDGE I-SID VLAN add Auto Attach mapping to BRIDGE\n\
+ del-aa-mapping BRIDGE I-SID VLAN delete Auto Attach mapping VLAN from BRIDGE\n\
+ get-aa-mapping BRIDGE get Auto Attach mappings from BRIDGE\n\
+\n\
Switch commands:\n\
emer-reset reset switch to known good state\n\
\n\
exit(EXIT_SUCCESS);
}
+/* Converts the command arguments into format that can be parsed by
+ * bash completion script.
+ *
+ * Therein, arguments will be attached with following prefixes:
+ *
+ * !argument :: The argument is required
+ * ?argument :: The argument is optional
+ * *argument :: The argument may appear any number (0 or more) times
+ * +argument :: The argument may appear one or more times
+ *
+ */
+static void
+print_command_arguments(const struct vsctl_command_syntax *command)
+{
+ /*
+ * The argument string is parsed in reverse. We use a stack 'oew_stack' to
+ * keep track of nested optionals. Whenever a ']' is encountered, we push
+ * a bit to 'oew_stack'. The bit is set to 1 if the ']' is not nested.
+ * Subsequently, we pop an entry everytime '[' is met.
+ *
+ * We use 'whole_word_is_optional' value to decide whether or not a ! or +
+ * should be added on encountering a space: if the optional surrounds the
+ * whole word then it shouldn't be, but if it is only a part of the word
+ * (i.e. [key=]value), it should be.
+ */
+ uint32_t oew_stack = 0;
+
+ const char *arguments = command->arguments;
+ int length = strlen(arguments);
+ if (!length) {
+ return;
+ }
+
+ /* Output buffer, written backward from end. */
+ char *output = xmalloc(2 * length);
+ char *outp = output + 2 * length;
+ *--outp = '\0';
+
+ bool in_repeated = false;
+ bool whole_word_is_optional = false;
+
+ for (const char *inp = arguments + length; inp > arguments; ) {
+ switch (*--inp) {
+ case ']':
+ oew_stack <<= 1;
+ if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') {
+ oew_stack |= 1;
+ }
+ break;
+ case '[':
+ /* Checks if the whole word is optional, and sets the
+ * 'whole_word_is_optional' accordingly. */
+ if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) {
+ *--outp = in_repeated ? '*' : '?';
+ whole_word_is_optional = true;
+ } else {
+ *--outp = '?';
+ whole_word_is_optional = false;
+ }
+ oew_stack >>= 1;
+ break;
+ case ' ':
+ if (!whole_word_is_optional) {
+ *--outp = in_repeated ? '+' : '!';
+ }
+ *--outp = ' ';
+ in_repeated = false;
+ whole_word_is_optional = false;
+ break;
+ case '.':
+ in_repeated = true;
+ break;
+ default:
+ *--outp = *inp;
+ break;
+ }
+ }
+ if (arguments[0] != '[' && outp != output + 2 * length - 1) {
+ *--outp = in_repeated ? '+' : '!';
+ }
+ printf("%s", outp);
+ free(output);
+}
+
+static void
+print_vsctl_commands(void)
+{
+ const struct vsctl_command_syntax *p;
+
+ for (p = get_all_commands(); p->name; p++) {
+ char *options = xstrdup(p->options);
+ char *options_begin = options;
+ char *item;
+
+ for (item = strsep(&options, ","); item != NULL;
+ item = strsep(&options, ",")) {
+ if (item[0] != '\0') {
+ printf("[%s] ", item);
+ }
+ }
+ printf(",%s,", p->name);
+ print_command_arguments(p);
+ printf("\n");
+
+ free(options_begin);
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+static void
+print_vsctl_options(const struct option *options)
+{
+ for (; options->name; options++) {
+ const struct option *o = options;
+
+ printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : "");
+ if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
+ printf("-%c%s\n", o->val, o->has_arg ? " ARG" : "");
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+
static char *
default_db(void)
{
struct vsctl_bridge {
struct ovsrec_bridge *br_cfg;
char *name;
- struct list ports; /* Contains "struct vsctl_port"s. */
+ struct ovs_list ports; /* Contains "struct vsctl_port"s. */
/* VLAN ("fake") bridge support.
*
};
struct vsctl_port {
- struct list ports_node; /* In struct vsctl_bridge's 'ports' list. */
- struct list ifaces; /* Contains "struct vsctl_iface"s. */
+ struct ovs_list ports_node; /* In struct vsctl_bridge's 'ports' list. */
+ struct ovs_list ifaces; /* Contains "struct vsctl_iface"s. */
struct ovsrec_port *port_cfg;
struct vsctl_bridge *bridge;
};
struct vsctl_iface {
- struct list ifaces_node; /* In struct vsctl_port's 'ifaces' list. */
+ struct ovs_list ifaces_node; /* In struct vsctl_port's 'ifaces' list. */
struct ovsrec_interface *iface_cfg;
struct vsctl_port *port;
};
+static struct vsctl_bridge *find_vlan_bridge(struct vsctl_bridge *parent,
+ int vlan);
+
static char *
vsctl_context_to_string(const struct vsctl_context *ctx)
{
br->vlan = vlan;
hmap_init(&br->children);
if (parent) {
- hmap_insert(&parent->children, &br->children_node, hash_int(vlan, 0));
+ struct vsctl_bridge *conflict = find_vlan_bridge(parent, vlan);
+ if (conflict) {
+ VLOG_WARN("%s: bridge has multiple VLAN bridges (%s and %s) "
+ "for VLAN %d, but only one is allowed",
+ parent->name, name, conflict->name, vlan);
+ } else {
+ hmap_insert(&parent->children, &br->children_node,
+ hash_int(vlan, 0));
+ }
}
shash_add(&ctx->bridges, br->name, br);
return br;
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);
ovs_insert_bridge(ctx->ovs, br);
} else {
+ struct vsctl_bridge *conflict;
struct vsctl_bridge *parent;
struct ovsrec_port *port;
- struct ovsrec_interface *iface;
struct ovsrec_bridge *br;
int64_t tag = vlan;
if (!parent) {
vsctl_fatal("parent bridge %s does not exist", parent_name);
}
+ conflict = find_vlan_bridge(parent, vlan);
+ if (conflict) {
+ vsctl_fatal("bridge %s already has a child VLAN bridge %s "
+ "on VLAN %d", parent_name, conflict->name, vlan);
+ }
br = parent->br_cfg;
iface = ovsrec_interface_insert(ctx->txn);
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);
ovsrec_open_vswitch_set_ssl(ctx->ovs, ssl);
}
+
+static void
+autoattach_insert_mapping(struct ovsrec_autoattach *aa,
+ int64_t isid,
+ int64_t vlan)
+{
+ int64_t *key_mappings, *value_mappings;
+ size_t i;
+
+ key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings + 1));
+ value_mappings = xmalloc(sizeof *aa->value_mappings * (aa->n_mappings + 1));
+
+ for (i = 0; i < aa->n_mappings; i++) {
+ key_mappings[i] = aa->key_mappings[i];
+ value_mappings[i] = aa->value_mappings[i];
+ }
+ key_mappings[aa->n_mappings] = isid;
+ value_mappings[aa->n_mappings] = vlan;
+
+ ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings,
+ aa->n_mappings + 1);
+
+ free(key_mappings);
+ free(value_mappings);
+}
+
+static void
+cmd_add_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+ int64_t isid, vlan;
+ char *nptr = NULL;
+
+ isid = strtoull(ctx->argv[2], &nptr, 10);
+ if (nptr == ctx->argv[2] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[2]);
+ return;
+ }
+
+ vlan = strtoull(ctx->argv[3], &nptr, 10);
+ if (nptr == ctx->argv[3] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[3]);
+ return;
+ }
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ if (br && br->br_cfg) {
+ if (!br->br_cfg->auto_attach) {
+ struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn);
+ ovsrec_bridge_set_auto_attach(br->br_cfg, aa);
+ }
+ autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan);
+ }
+}
+
+static void
+del_aa_mapping(struct ovsrec_autoattach *aa,
+ int64_t isid,
+ int64_t vlan)
+{
+ int64_t *key_mappings, *value_mappings;
+ size_t i, n;
+
+ key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings));
+ value_mappings = xmalloc(sizeof *value_mappings * (aa->n_mappings));
+
+ for (i = n = 0; i < aa->n_mappings; i++) {
+ if (aa->key_mappings[i] != isid && aa->value_mappings[i] != vlan) {
+ key_mappings[n] = aa->key_mappings[i];
+ value_mappings[n++] = aa->value_mappings[i];
+ }
+ }
+
+ ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings, n);
+
+ free(key_mappings);
+ free(value_mappings);
+}
+
+static void
+cmd_del_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+ int64_t isid, vlan;
+ char *nptr = NULL;
+
+ isid = strtoull(ctx->argv[2], &nptr, 10);
+ if (nptr == ctx->argv[2] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[2]);
+ return;
+ }
+
+ vlan = strtoull(ctx->argv[3], &nptr, 10);
+ if (nptr == ctx->argv[3] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[3]);
+ return;
+ }
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ br->br_cfg->auto_attach->key_mappings &&
+ br->br_cfg->auto_attach->value_mappings) {
+ size_t i;
+
+ for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
+ if (br->br_cfg->auto_attach->key_mappings[i] == isid &&
+ br->br_cfg->auto_attach->value_mappings[i] == vlan) {
+ del_aa_mapping(br->br_cfg->auto_attach, isid, vlan);
+ break;
+ }
+ }
+ }
+}
+
+static void
+pre_aa_mapping(struct vsctl_context *ctx)
+{
+ pre_get_info(ctx);
+
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach);
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
+}
+
+static void
+verify_auto_attach(struct ovsrec_bridge *bridge)
+{
+ if (bridge) {
+ ovsrec_bridge_verify_auto_attach(bridge);
+
+ if (bridge->auto_attach) {
+ ovsrec_autoattach_verify_mappings(bridge->auto_attach);
+ }
+ }
+}
+
+static void
+cmd_get_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ verify_auto_attach(br->br_cfg);
+
+ if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ br->br_cfg->auto_attach->key_mappings &&
+ br->br_cfg->auto_attach->value_mappings) {
+ size_t i;
+
+ for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
+ ds_put_format(&ctx->output, "%"PRId64" %"PRId64"\n",
+ br->br_cfg->auto_attach->key_mappings[i],
+ br->br_cfg->auto_attach->value_mappings[i]);
+ }
+ }
+}
+
\f
/* Parameter commands. */
{&ovsrec_table_flow_sample_collector_set, NULL,
&ovsrec_flow_sample_collector_set_col_ipfix}}},
+ {&ovsrec_table_autoattach,
+ {{&ovsrec_table_bridge,
+ &ovsrec_bridge_col_name,
+ &ovsrec_bridge_col_auto_attach},
+ {NULL, NULL, NULL}}},
+
{&ovsrec_table_flow_sample_collector_set,
{{NULL, NULL, NULL},
{NULL, NULL, NULL}}},
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++) {
*
* On success, returns NULL. On failure, returned a malloc()'d string error
* message and stores NULL into all of the nonnull output arguments. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_column_key_value(const char *arg,
const struct vsctl_table_class *table,
const struct ovsdb_idl_column **columnp, char **keyp,
}
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;
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) {
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)
{
&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:
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);
free(error);
}
+/*
+ * Developers who add new commands to the 'struct vsctl_command_syntax' must
+ * define the 'arguments' member of the struct. The following keywords are
+ * available for composing the argument format:
+ *
+ * TABLE RECORD BRIDGE PARENT PORT
+ * KEY VALUE ARG KEY=VALUE ?KEY=VALUE
+ * IFACE SYSIFACE COLUMN COLUMN?:KEY COLUMN?:KEY=VALUE
+ * MODE CA-CERT CERTIFICATE PRIVATE-KEY
+ * TARGET NEW-* (e.g. NEW-PORT)
+ *
+ * For argument types not listed above, just uses 'ARG' as place holder.
+ *
+ * Encloses the keyword with '[]' if it is optional. Appends '...' to
+ * keyword or enclosed keyword to indicate that the argument can be specified
+ * multiple times.
+ *
+ * */
static const struct vsctl_command_syntax all_commands[] = {
/* Open vSwitch commands. */
- {"init", 0, 0, NULL, cmd_init, NULL, "", RW},
- {"show", 0, 0, pre_cmd_show, cmd_show, NULL, "", RO},
+ {"init", 0, 0, "", NULL, cmd_init, NULL, "", RW},
+ {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
/* Bridge commands. */
- {"add-br", 1, 3, pre_get_info, cmd_add_br, NULL, "--may-exist", RW},
- {"del-br", 1, 1, pre_get_info, cmd_del_br, NULL, "--if-exists", RW},
- {"list-br", 0, 0, pre_get_info, cmd_list_br, NULL, "--real,--fake", RO},
- {"br-exists", 1, 1, pre_get_info, cmd_br_exists, NULL, "", RO},
- {"br-to-vlan", 1, 1, pre_get_info, cmd_br_to_vlan, NULL, "", RO},
- {"br-to-parent", 1, 1, pre_get_info, cmd_br_to_parent, NULL, "", RO},
- {"br-set-external-id", 2, 3, pre_cmd_br_set_external_id,
- cmd_br_set_external_id, NULL, "", RW},
- {"br-get-external-id", 1, 2, pre_cmd_br_get_external_id,
+ {"add-br", 1, 3, "NEW-BRIDGE [PARENT] [NEW-VLAN]", pre_get_info,
+ cmd_add_br, NULL, "--may-exist", RW},
+ {"del-br", 1, 1, "BRIDGE", pre_get_info, cmd_del_br,
+ NULL, "--if-exists", RW},
+ {"list-br", 0, 0, "", pre_get_info, cmd_list_br, NULL, "--real,--fake",
+ RO},
+ {"br-exists", 1, 1, "BRIDGE", pre_get_info, cmd_br_exists, NULL, "", RO},
+ {"br-to-vlan", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_vlan, NULL, "",
+ RO},
+ {"br-to-parent", 1, 1, "BRIDGE", pre_get_info, cmd_br_to_parent, NULL,
+ "", RO},
+ {"br-set-external-id", 2, 3, "BRIDGE KEY [VALUE]",
+ pre_cmd_br_set_external_id, cmd_br_set_external_id, NULL, "", RW},
+ {"br-get-external-id", 1, 2, "BRIDGE [KEY]", pre_cmd_br_get_external_id,
cmd_br_get_external_id, NULL, "", RO},
/* Port commands. */
- {"list-ports", 1, 1, pre_get_info, cmd_list_ports, NULL, "", RO},
- {"add-port", 2, INT_MAX, pre_get_info, cmd_add_port, NULL, "--may-exist",
- RW},
- {"add-bond", 4, INT_MAX, pre_get_info, cmd_add_bond, NULL,
- "--may-exist,--fake-iface", RW},
- {"del-port", 1, 2, pre_get_info, cmd_del_port, NULL,
+ {"list-ports", 1, 1, "BRIDGE", pre_get_info, cmd_list_ports, NULL, "",
+ RO},
+ {"add-port", 2, INT_MAX, "BRIDGE NEW-PORT [COLUMN[:KEY]=VALUE]...",
+ pre_get_info, cmd_add_port, NULL, "--may-exist", RW},
+ {"add-bond", 4, INT_MAX,
+ "BRIDGE NEW-BOND-PORT SYSIFACE... [COLUMN[:KEY]=VALUE]...", pre_get_info,
+ cmd_add_bond, NULL, "--may-exist,--fake-iface", RW},
+ {"del-port", 1, 2, "[BRIDGE] PORT|IFACE", pre_get_info, cmd_del_port, NULL,
"--if-exists,--with-iface", RW},
- {"port-to-br", 1, 1, pre_get_info, cmd_port_to_br, NULL, "", RO},
+ {"port-to-br", 1, 1, "PORT", pre_get_info, cmd_port_to_br, NULL, "", RO},
/* Interface commands. */
- {"list-ifaces", 1, 1, pre_get_info, cmd_list_ifaces, NULL, "", RO},
- {"iface-to-br", 1, 1, pre_get_info, cmd_iface_to_br, NULL, "", RO},
+ {"list-ifaces", 1, 1, "BRIDGE", pre_get_info, cmd_list_ifaces, NULL, "",
+ RO},
+ {"iface-to-br", 1, 1, "IFACE", pre_get_info, cmd_iface_to_br, NULL, "",
+ RO},
/* Controller commands. */
- {"get-controller", 1, 1, pre_controller, cmd_get_controller, NULL, "", RO},
- {"del-controller", 1, 1, pre_controller, cmd_del_controller, NULL, "", RW},
- {"set-controller", 1, INT_MAX, pre_controller, cmd_set_controller, NULL,
+ {"get-controller", 1, 1, "BRIDGE", pre_controller, cmd_get_controller,
+ NULL, "", RO},
+ {"del-controller", 1, 1, "BRIDGE", pre_controller, cmd_del_controller,
+ NULL, "", RW},
+ {"set-controller", 1, INT_MAX, "BRIDGE TARGET...", pre_controller,
+ cmd_set_controller, NULL, "", RW},
+ {"get-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_get_fail_mode, NULL,
+ "", RO},
+ {"del-fail-mode", 1, 1, "BRIDGE", pre_get_info, cmd_del_fail_mode, NULL,
"", RW},
- {"get-fail-mode", 1, 1, pre_get_info, cmd_get_fail_mode, NULL, "", RO},
- {"del-fail-mode", 1, 1, pre_get_info, cmd_del_fail_mode, NULL, "", RW},
- {"set-fail-mode", 2, 2, pre_get_info, cmd_set_fail_mode, NULL, "", RW},
+ {"set-fail-mode", 2, 2, "BRIDGE MODE", pre_get_info, cmd_set_fail_mode,
+ NULL, "", RW},
/* Manager commands. */
- {"get-manager", 0, 0, pre_manager, cmd_get_manager, NULL, "", RO},
- {"del-manager", 0, 0, pre_manager, cmd_del_manager, NULL, "", RW},
- {"set-manager", 1, INT_MAX, pre_manager, cmd_set_manager, NULL, "", RW},
+ {"get-manager", 0, 0, "", pre_manager, cmd_get_manager, NULL, "", RO},
+ {"del-manager", 0, 0, "", pre_manager, cmd_del_manager, NULL, "", RW},
+ {"set-manager", 1, INT_MAX, "TARGET...", pre_manager, cmd_set_manager,
+ NULL, "", RW},
/* SSL commands. */
- {"get-ssl", 0, 0, pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
- {"del-ssl", 0, 0, pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
- {"set-ssl", 3, 3, pre_cmd_set_ssl, cmd_set_ssl, NULL, "--bootstrap", RW},
+ {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
+ {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
+ {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl,
+ cmd_set_ssl, NULL, "--bootstrap", RW},
+
+ /* Auto Attach commands. */
+ {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_add_aa_mapping,
+ NULL, "", RW},
+ {"del-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_del_aa_mapping,
+ NULL, "", RW},
+ {"get-aa-mapping", 1, 1, "BRIDGE", pre_aa_mapping, cmd_get_aa_mapping,
+ NULL, "", RO},
/* Switch commands. */
- {"emer-reset", 0, 0, pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW},
+ {"emer-reset", 0, 0, "", pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW},
/* Database commands. */
- {"comment", 0, INT_MAX, NULL, NULL, NULL, "", RO},
- {"get", 2, INT_MAX, pre_cmd_get, cmd_get, NULL, "--if-exists,--id=", RO},
- {"list", 1, INT_MAX, pre_cmd_list, cmd_list, NULL,
+ {"comment", 0, INT_MAX, "[ARG]...", NULL, NULL, NULL, "", RO},
+ {"get", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]]...",pre_cmd_get, cmd_get,
+ NULL, "--if-exists,--id=", RO},
+ {"list", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_list, cmd_list, NULL,
"--if-exists,--columns=", RO},
- {"find", 1, INT_MAX, pre_cmd_find, cmd_find, NULL, "--columns=", RO},
- {"set", 3, INT_MAX, pre_cmd_set, cmd_set, NULL, "--if-exists", RW},
- {"add", 4, INT_MAX, pre_cmd_add, cmd_add, NULL, "--if-exists", RW},
- {"remove", 4, INT_MAX, pre_cmd_remove, cmd_remove, NULL, "--if-exists",
- RW},
- {"clear", 3, INT_MAX, pre_cmd_clear, cmd_clear, NULL, "--if-exists", RW},
- {"create", 2, INT_MAX, pre_create, cmd_create, post_create, "--id=", RW},
- {"destroy", 1, INT_MAX, pre_cmd_destroy, cmd_destroy, NULL,
- "--if-exists,--all", RW},
- {"wait-until", 2, INT_MAX, pre_cmd_wait_until, cmd_wait_until, NULL, "",
- RO},
-
- {NULL, 0, 0, NULL, NULL, NULL, NULL, RO},
+ {"find", 1, INT_MAX, "TABLE [COLUMN[:KEY]=VALUE]...", pre_cmd_find,
+ cmd_find, NULL, "--columns=", RO},
+ {"set", 3, INT_MAX, "TABLE RECORD COLUMN[:KEY]=VALUE...", pre_cmd_set,
+ cmd_set, NULL, "--if-exists", RW},
+ {"add", 4, INT_MAX, "TABLE RECORD COLUMN [KEY=]VALUE...", pre_cmd_add,
+ cmd_add, NULL, "--if-exists", RW},
+ {"remove", 4, INT_MAX, "TABLE RECORD COLUMN KEY|VALUE|KEY=VALUE...",
+ pre_cmd_remove, cmd_remove, NULL, "--if-exists", RW},
+ {"clear", 3, INT_MAX, "TABLE RECORD COLUMN...", pre_cmd_clear, cmd_clear,
+ NULL, "--if-exists", RW},
+ {"create", 2, INT_MAX, "TABLE COLUMN[:KEY]=VALUE...", pre_create,
+ cmd_create, post_create, "--id=", RW},
+ {"destroy", 1, INT_MAX, "TABLE [RECORD]...", pre_cmd_destroy, cmd_destroy,
+ NULL, "--if-exists,--all", RW},
+ {"wait-until", 2, INT_MAX, "TABLE RECORD [COLUMN[:KEY]=VALUE]...",
+ pre_cmd_wait_until, cmd_wait_until, NULL, "", RO},
+
+ {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
};
static const struct vsctl_command_syntax *get_all_commands(void)