#include "ovsdb-idl.h"
#include "poll-loop.h"
#include "process.h"
+#include "stream.h"
#include "stream-ssl.h"
+#include "sset.h"
#include "svec.h"
#include "vswitchd/vswitch-idl.h"
#include "table.h"
%s: ovs-vswitchd management utility\n\
usage: %s [OPTIONS] COMMAND [ARG...]\n\
\n\
+Open vSwitch commands:\n\
+ init initialize database, if not yet initialized\n\
+ emer-reset reset configuration to clean state\n\
+\n\
Bridge commands:\n\
add-br BRIDGE create a new bridge named BRIDGE\n\
add-br BRIDGE PARENT VLAN create new fake BRIDGE in PARENT on VLAN\n\
br-get-external-id BRIDGE KEY print value of KEY on BRIDGE\n\
br-get-external-id BRIDGE list key-value pairs on BRIDGE\n\
\n\
-Port commands:\n\
+Port commands (a bond is considered to be a single port):\n\
list-ports BRIDGE print the names of all the ports on BRIDGE\n\
add-port BRIDGE PORT add network device PORT to BRIDGE\n\
add-bond BRIDGE PORT IFACE... add bonded port PORT in BRIDGE from IFACES\n\
del-port [BRIDGE] PORT delete PORT (which may be bonded) from BRIDGE\n\
port-to-br PORT print name of bridge that contains PORT\n\
-A bond is considered to be a single port.\n\
\n\
Interface commands (a bond consists of multiple interfaces):\n\
list-ifaces BRIDGE print the names of all interfaces on BRIDGE\n\
Options:\n\
--db=DATABASE connect to DATABASE\n\
(default: %s)\n\
+ --no-wait do not wait for ovs-vswitchd to reconfigure\n\
+ -t, --timeout=SECS wait at most SECS seconds for ovs-vswitchd\n\
+ --dry-run do not commit changes to database\n\
--oneline print exactly one line of output per command\n",
program_name, program_name, default_db());
vlog_usage();
+ printf("\
+ --no-syslog equivalent to --verbose=vsctl:syslog:warn\n");
+ stream_usage("database", true, true, false);
printf("\n\
Other options:\n\
-h, --help display this help message\n\
get_info(struct vsctl_context *ctx, struct vsctl_info *info)
{
const struct ovsrec_open_vswitch *ovs = ctx->ovs;
- struct shash bridges, ports;
+ struct sset bridges, ports;
size_t i;
info->ctx = ctx;
shash_init(&info->ports);
shash_init(&info->ifaces);
- shash_init(&bridges);
- shash_init(&ports);
+ sset_init(&bridges);
+ sset_init(&ports);
for (i = 0; i < ovs->n_bridges; i++) {
struct ovsrec_bridge *br_cfg = ovs->bridges[i];
struct vsctl_bridge *br;
size_t j;
- if (!shash_add_once(&bridges, br_cfg->name, NULL)) {
+ if (!sset_add(&bridges, br_cfg->name)) {
VLOG_WARN("%s: database contains duplicate bridge name",
br_cfg->name);
continue;
for (j = 0; j < br_cfg->n_ports; j++) {
struct ovsrec_port *port_cfg = br_cfg->ports[j];
- if (!shash_add_once(&ports, port_cfg->name, NULL)) {
+ if (!sset_add(&ports, port_cfg->name)) {
VLOG_WARN("%s: database contains duplicate port name",
port_cfg->name);
continue;
}
if (port_is_fake_bridge(port_cfg)
- && shash_add_once(&bridges, port_cfg->name, NULL)) {
+ && sset_add(&bridges, port_cfg->name)) {
add_bridge(info, NULL, port_cfg->name, br, *port_cfg->tag);
}
}
}
- shash_destroy(&bridges);
- shash_destroy(&ports);
+ sset_destroy(&bridges);
+ sset_destroy(&ports);
- shash_init(&bridges);
- shash_init(&ports);
+ sset_init(&bridges);
+ sset_init(&ports);
for (i = 0; i < ovs->n_bridges; i++) {
struct ovsrec_bridge *br_cfg = ovs->bridges[i];
struct vsctl_bridge *br;
size_t j;
- if (!shash_add_once(&bridges, br_cfg->name, NULL)) {
+ if (!sset_add(&bridges, br_cfg->name)) {
continue;
}
br = shash_find_data(&info->bridges, br_cfg->name);
struct vsctl_port *port;
size_t k;
- if (!shash_add_once(&ports, port_cfg->name, NULL)) {
+ if (!sset_add(&ports, port_cfg->name)) {
continue;
}
if (port_is_fake_bridge(port_cfg)
- && !shash_add_once(&bridges, port_cfg->name, NULL)) {
+ && !sset_add(&bridges, port_cfg->name)) {
continue;
}
}
}
}
- shash_destroy(&bridges);
- shash_destroy(&ports);
+ sset_destroy(&bridges);
+ sset_destroy(&ports);
}
static void
static void
pre_cmd_emer_reset(struct vsctl_context *ctx)
{
- ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_managers);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl);
const struct ovsrec_sflow *sflow, *next_sflow;
/* Reset the Open_vSwitch table. */
- ovsrec_open_vswitch_set_managers(ctx->ovs, NULL, 0);
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL);
if (!key && !strncmp(keys[i], prefix, prefix_len)) {
svec_add_nocopy(&svec, xasprintf("%s=%s",
keys[i] + prefix_len, values[i]));
- } else if (key_matches(keys[i], prefix, prefix_len, key)) {
+ } else if (key && key_matches(keys[i], prefix, prefix_len, key)) {
svec_add(&svec, values[i]);
break;
}
struct vsctl_bridge *br;
get_info(ctx, &info);
+
br = find_real_bridge(&info, ctx->argv[1], true);
verify_controllers(br->br_cfg);
{
size_t i;
- ovsrec_open_vswitch_verify_managers(ovs);
ovsrec_open_vswitch_verify_manager_options(ovs);
for (i = 0; i < ovs->n_manager_options; ++i) {
static void
pre_manager(struct vsctl_context *ctx)
{
- ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_managers);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options);
ovsdb_idl_add_column(ctx->idl, &ovsrec_manager_col_target);
}
/* Print the targets in sorted order for reproducibility. */
svec_init(&targets);
- /* First, add all targets found in deprecated 'managers' column. */
- for (i = 0; i < ovs->n_managers; i++) {
- svec_add(&targets, ovs->managers[i]);
- }
-
- /* Second, add all targets pointed to by 'manager_options' column. */
for (i = 0; i < ovs->n_manager_options; i++) {
svec_add(&targets, ovs->manager_options[i]->target);
}
const struct ovsrec_open_vswitch *ovs = ctx->ovs;
size_t i;
- /* Delete manager targets in deprecated 'managers' column. */
- ovsrec_open_vswitch_set_managers(ovs, NULL, 0);
-
/* Delete Manager rows pointed to by 'manager_options' column. */
for (i = 0; i < ovs->n_manager_options; i++) {
ovsrec_manager_delete(ovs->manager_options[i]);
struct ovsrec_manager **managers;
size_t i;
- /* Store in deprecated 'manager' column. */
- ovsrec_open_vswitch_set_managers(ctx->ovs, targets, n);
-
/* Insert each manager in a new row in Manager table. */
managers = xmalloc(n * sizeof *managers);
for (i = 0; i < n; i++) {
}
}
-static struct uuid *
+static struct ovsdb_symbol *
create_symbol(struct ovsdb_symbol_table *symtab, const char *id, bool *newp)
{
struct ovsdb_symbol *symbol;
}
symbol = ovsdb_symbol_table_insert(symtab, id);
- if (symbol->used) {
+ if (symbol->created) {
vsctl_fatal("row id \"%s\" may only be specified on one --id option",
id);
}
- symbol->used = true;
- return &symbol->uuid;
+ symbol->created = true;
+ return symbol;
}
static void
/* Breaks 'arg' apart into a number of fields in the following order:
*
- * - If 'columnp' is nonnull, the name of a column in 'table'. The column
- * is stored into '*columnp'. The column name may be abbreviated.
+ * - The name of a column in 'table', stored into '*columnp'. The column
+ * name may be abbreviated.
*
- * - If 'keyp' is nonnull, optionally a key string. (If both 'columnp'
- * and 'keyp' are nonnull, then the column and key names are expected to
- * be separated by ':'). The key is stored as a malloc()'d string into
- * '*keyp', or NULL if no key is present in 'arg'.
+ * - Optionally ':' followed by a key string. The key is stored as a
+ * malloc()'d string into '*keyp', or NULL if no key is present in
+ * 'arg'.
*
* - If 'valuep' is nonnull, an operator followed by a value string. The
* allowed operators are the 'n_allowed' string in 'allowed_operators',
* stored as a malloc()'d string into '*valuep', or NULL if no value is
* present in 'arg'.
*
- * At least 'columnp' or 'keyp' must be nonnull.
- *
* 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
char **valuep)
{
const char *p = arg;
+ char *column_name;
char *error;
- assert(columnp || keyp);
assert(!(operatorp && !valuep));
- if (keyp) {
- *keyp = NULL;
- }
+ *keyp = NULL;
if (valuep) {
*valuep = NULL;
}
/* Parse column name. */
- if (columnp) {
- char *column_name;
-
- error = ovsdb_token_parse(&p, &column_name);
- if (error) {
- goto error;
- }
- if (column_name[0] == '\0') {
- free(column_name);
- error = xasprintf("%s: missing column name", arg);
- goto error;
- }
- error = get_column(table, column_name, columnp);
+ error = ovsdb_token_parse(&p, &column_name);
+ if (error) {
+ goto error;
+ }
+ if (column_name[0] == '\0') {
free(column_name);
- if (error) {
- goto error;
- }
+ error = xasprintf("%s: missing column name", arg);
+ goto error;
+ }
+ error = get_column(table, column_name, columnp);
+ free(column_name);
+ if (error) {
+ goto error;
}
/* Parse key string. */
- if (*p == ':' || !columnp) {
- if (columnp) {
- p++;
- } else if (!keyp) {
- error = xasprintf("%s: key not accepted here", arg);
- goto error;
- }
+ if (*p == ':') {
+ p++;
error = ovsdb_token_parse(&p, keyp);
if (error) {
goto error;
}
- } else if (keyp) {
- *keyp = NULL;
}
/* Parse value string. */
}
*valuep = xstrdup(p + best_len);
} else {
- if (valuep) {
- *valuep = NULL;
- }
if (*p != '\0') {
error = xasprintf("%s: trailing garbage \"%s\" in argument",
arg, p);
return NULL;
error:
- if (columnp) {
- *columnp = NULL;
- }
- if (keyp) {
- free(*keyp);
- *keyp = NULL;
- }
+ *columnp = NULL;
+ free(*keyp);
+ *keyp = NULL;
if (valuep) {
free(*valuep);
*valuep = NULL;
table = get_table(table_name);
row = must_get_row(ctx, table, record_id);
if (id) {
+ struct ovsdb_symbol *symbol;
bool new;
- *create_symbol(ctx->symtab, id, &new) = row->uuid;
+ symbol = create_symbol(ctx->symtab, id, &new);
if (!new) {
vsctl_fatal("row id \"%s\" specified on \"get\" command was used "
"before it was defined", id);
}
+ symbol->uuid = row->uuid;
+
+ /* This symbol refers to a row that already exists, so disable warnings
+ * about it being unreferenced. */
+ symbol->strong_ref = true;
}
for (i = 3; i < ctx->argc; i++) {
const struct ovsdb_idl_column *column;
}
} else {
const struct ovsdb_idl_row *row;
- bool first;
- for (row = ovsdb_idl_first_row(ctx->idl, table->class), first = true;
- row != NULL;
- row = ovsdb_idl_next_row(row), first = false) {
+ for (row = ovsdb_idl_first_row(ctx->idl, table->class); row != NULL;
+ row = ovsdb_idl_next_row(row)) {
list_record(row, columns, n_columns, out);
}
}
next_row: ;
}
+ free(columns);
}
static void
}
static void
-cmd_create(struct vsctl_context *ctx)
+pre_create(struct vsctl_context *ctx)
{
const char *id = shash_find_data(&ctx->options, "--id");
const char *table_name = ctx->argv[1];
const struct vsctl_table_class *table;
+
+ table = get_table(table_name);
+ if (!id && !table->class->is_root) {
+ VLOG_WARN("applying \"create\" command to table %s without --id "
+ "option will have no effect", table->class->name);
+ }
+}
+
+static void
+cmd_create(struct vsctl_context *ctx)
+{
+ const char *id = shash_find_data(&ctx->options, "--id");
+ const char *table_name = ctx->argv[1];
+ const struct vsctl_table_class *table = get_table(table_name);
const struct ovsdb_idl_row *row;
const struct uuid *uuid;
int i;
- uuid = id ? create_symbol(ctx->symtab, id, NULL) : NULL;
+ if (id) {
+ struct ovsdb_symbol *symbol = create_symbol(ctx->symtab, id, NULL);
+ if (table->class->is_root) {
+ /* This table is in the root set, meaning that rows created in it
+ * won't disappear even if they are unreferenced, so disable
+ * warnings about that by pretending that there is a reference. */
+ symbol->strong_ref = true;
+ }
+ uuid = &symbol->uuid;
+ } else {
+ uuid = NULL;
+ }
- table = get_table(table_name);
row = ovsdb_idl_txn_insert(ctx->txn, table->class, uuid);
for (i = 2; i < ctx->argc; i++) {
set_column(table, row, ctx->argv[i], ctx->symtab);
const struct uuid *real;
struct uuid dummy;
- uuid_from_string(&dummy, ds_cstr(&ctx->output));
+ if (!uuid_from_string(&dummy, ds_cstr(&ctx->output))) {
+ NOT_REACHED();
+ }
real = ovsdb_idl_txn_get_insert_uuid(ctx->txn, &dummy);
if (real) {
ds_clear(&ctx->output);
const struct ovsrec_open_vswitch *ovs;
enum ovsdb_idl_txn_status status;
struct ovsdb_symbol_table *symtab;
- const char *unused;
struct vsctl_command *c;
+ struct shash_node *node;
int64_t next_cfg = 0;
char *error = NULL;
}
}
+ SHASH_FOR_EACH (node, &symtab->sh) {
+ struct ovsdb_symbol *symbol = node->data;
+ if (!symbol->created) {
+ vsctl_fatal("row id \"%s\" is referenced but never created (e.g. "
+ "with \"-- --id=%s create ...\")",
+ node->name, node->name);
+ }
+ if (!symbol->strong_ref) {
+ if (!symbol->weak_ref) {
+ VLOG_WARN("row id \"%s\" was created but no reference to it "
+ "was inserted, so it will not actually appear in "
+ "the database", node->name);
+ } else {
+ VLOG_WARN("row id \"%s\" was created but only a weak "
+ "reference to it was inserted, so it will not "
+ "actually appear in the database", node->name);
+ }
+ }
+ }
+
status = ovsdb_idl_txn_commit_block(txn);
if (wait_for_reload && status == TXN_SUCCESS) {
next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
ovsdb_idl_txn_destroy(txn);
txn = the_idl_txn = NULL;
- unused = ovsdb_symbol_table_find_unused(symtab);
- if (unused) {
- vsctl_fatal("row id \"%s\" is referenced but never created (e.g. "
- "with \"-- --id=%s create ...\")", unused, unused);
- }
-
switch (status) {
case TXN_INCOMPLETE:
NOT_REACHED();
{"add", 4, INT_MAX, pre_cmd_add, cmd_add, NULL, "", RW},
{"remove", 4, INT_MAX, pre_cmd_remove, cmd_remove, NULL, "", RW},
{"clear", 3, INT_MAX, pre_cmd_clear, cmd_clear, NULL, "", RW},
- {"create", 2, INT_MAX, NULL, cmd_create, post_create, "--id=", 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",
RW},
{"wait-until", 2, INT_MAX, pre_cmd_wait_until, cmd_wait_until, NULL, "",