cksum=`ovsdb-tool db-cksum "$conf_file" | awk '{print $1}'`
cp "$conf_file" "$conf_file.backup$version-$cksum"
+ # Compact database. This is important if the old schema did not
+ # enable garbage collection (i.e. if it did not have any tables
+ # with "isRoot": true) but the new schema does. In that situation
+ # the old database may contain a transaction that creates a record
+ # followed by a transaction that creates the first use of the
+ # record. Replaying that series of transactions against the new
+ # database schema (as "convert" does) would cause the record to be
+ # dropped by the first transaction, then the second transaction
+ # would cause a referential integrity failure (for a strong
+ # reference).
+ ovsdb-tool -vANY:console:emer compact $conf_file
+
# Upgrade or downgrade schema and compact database.
ovsdb-tool -vANY:console:emer convert $conf_file $schema_file
fi
return NULL;
}
+static void
+ovsdb_symbol_referenced(struct ovsdb_symbol *symbol,
+ const struct ovsdb_base_type *base)
+{
+ assert(base->type == OVSDB_TYPE_UUID);
+
+ if (base->u.uuid.refTableName) {
+ switch (base->u.uuid.refType) {
+ case OVSDB_REF_STRONG:
+ symbol->strong_ref = true;
+ break;
+ case OVSDB_REF_WEAK:
+ symbol->weak_ref = true;
+ break;
+ }
+ }
+}
+
static struct ovsdb_error * WARN_UNUSED_RESULT
ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
- struct ovsdb_symbol_table *symtab)
+ struct ovsdb_symbol_table *symtab,
+ const struct ovsdb_base_type *base)
{
struct ovsdb_error *error0;
const struct json *value;
error1 = unwrap_json(json, "named-uuid", JSON_STRING, &value);
if (!error1) {
- const char *name = json_string(value);
+ struct ovsdb_symbol *symbol;
ovsdb_error_destroy(error0);
- *uuid = ovsdb_symbol_table_insert(symtab, name)->uuid;
if (!ovsdb_parser_is_id(json_string(value))) {
return ovsdb_syntax_error(json, NULL, "named-uuid string is "
"not a valid <id>");
}
+
+ symbol = ovsdb_symbol_table_insert(symtab, json_string(value));
+ *uuid = symbol->uuid;
+ ovsdb_symbol_referenced(symbol, base);
return NULL;
}
ovsdb_error_destroy(error1);
}
static struct ovsdb_error * WARN_UNUSED_RESULT
-ovsdb_atom_from_json__(union ovsdb_atom *atom, enum ovsdb_atomic_type type,
+ovsdb_atom_from_json__(union ovsdb_atom *atom,
+ const struct ovsdb_base_type *base,
const struct json *json,
struct ovsdb_symbol_table *symtab)
{
+ enum ovsdb_atomic_type type = base->type;
+
switch (type) {
case OVSDB_TYPE_VOID:
NOT_REACHED();
break;
case OVSDB_TYPE_UUID:
- return ovsdb_atom_parse_uuid(&atom->uuid, json, symtab);
+ return ovsdb_atom_parse_uuid(&atom->uuid, json, symtab, base);
case OVSDB_N_TYPES:
default:
*
* If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted. Refer to
* ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts. */
+ * function accepts. If 'base' is a reference and a symbol is parsed, then the
+ * symbol's 'strong_ref' or 'weak_ref' member is set to true, as
+ * appropriate. */
struct ovsdb_error *
ovsdb_atom_from_json(union ovsdb_atom *atom,
const struct ovsdb_base_type *base,
{
struct ovsdb_error *error;
- error = ovsdb_atom_from_json__(atom, base->type, json, symtab);
+ error = ovsdb_atom_from_json__(atom, base, json, symtab);
if (error) {
return error;
}
}
static char *
-ovsdb_atom_from_string__(union ovsdb_atom *atom, enum ovsdb_atomic_type type,
- const char *s, struct ovsdb_symbol_table *symtab)
+ovsdb_atom_from_string__(union ovsdb_atom *atom,
+ const struct ovsdb_base_type *base, const char *s,
+ struct ovsdb_symbol_table *symtab)
{
+ enum ovsdb_atomic_type type = base->type;
+
switch (type) {
case OVSDB_TYPE_VOID:
NOT_REACHED();
case OVSDB_TYPE_UUID:
if (*s == '@') {
- atom->uuid = ovsdb_symbol_table_insert(symtab, s)->uuid;
+ struct ovsdb_symbol *symbol = ovsdb_symbol_table_insert(symtab, s);
+ atom->uuid = symbol->uuid;
+ ovsdb_symbol_referenced(symbol, base);
} else if (!uuid_from_string(&atom->uuid, s)) {
return xasprintf("\"%s\" is not a valid UUID", s);
}
* then an identifier beginning with '@' is also acceptable. If the
* named identifier is already in 'symtab', then the associated UUID is
* used; otherwise, a new, random UUID is used and added to the symbol
- * table.
+ * table. If 'base' is a reference and a symbol is parsed, then the
+ * symbol's 'strong_ref' or 'weak_ref' member is set to true, as
+ * appropriate.
*
* Returns a null pointer if successful, otherwise an error message describing
* the problem. On failure, the contents of 'atom' are indeterminate. The
struct ovsdb_error *error;
char *msg;
- msg = ovsdb_atom_from_string__(atom, base->type, s, symtab);
+ msg = ovsdb_atom_from_string__(atom, base, s, symtab);
if (msg) {
return msg;
}
symbol = xmalloc(sizeof *symbol);
symbol->uuid = *uuid;
symbol->created = created;
+ symbol->strong_ref = false;
+ symbol->weak_ref = false;
shash_add(&symtab->sh, name, symbol);
return symbol;
}
struct ovsdb_symbol {
struct uuid uuid; /* The UUID that the symbol represents. */
bool created; /* Already used to create row? */
+ bool strong_ref; /* Parsed a strong reference to this row? */
+ bool weak_ref; /* Parsed a weak reference to this row? */
};
struct ovsdb_symbol_table *ovsdb_symbol_table_create(void);
-/* Copyright (c) 2009, 2010 Nicira Networks.
+/* Copyright (c) 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct ovsdb_idl_table_class {
char *name;
+ bool is_root;
const struct ovsdb_idl_column *columns;
size_t n_columns;
size_t allocation_size;
"columns": {<id>: <column-schema>, ...} required
"maxRows": <integer> optional
+ "isRoot": <boolean> optional
The value of "columns" is a JSON object whose names are column
names and whose values are <column-schema>s.
the database process is stopped and then started again, each
"_version" also changes to a new random value.
+ If "isRoot" is omitted or specified as false, then any given row
+ in the table may exist only when there is at least one reference
+ to it, with refType "strong", from a different row (in the same
+ table or a different table). This is a "deferred" action:
+ unreferenced rows in the table are deleted just before transaction
+ commit. If "isRoot" is specified as true, then rows in the table
+ exist independent of any references (they can be thought of as
+ part of the "root set" in a garbage collector).
+
+ For compatibility with schemas created before "isRoot" was
+ introduced, if "isRoot" is omitted or false in every
+ <table-schema> in a given <database-schema>, then every table is
+ part of the root set.
+
If "maxRows" is specified, as a positive integer, it limits the
maximum number of rows that may be present in the table. This is
a "deferred" constraint, enforced only at transaction commit time
(see the "transact" request below). If "maxRows" is not
specified, the size of the table is limited only by the resources
- available to the database server.
+ available to the database server. "maxRows" constraints are
+ enforced after unreferenced rows are deleted from tables with a
+ false "isRoot".
<column-schema>
#! /usr/bin/perl
-# Copyright (c) 2009, 2010 Nicira Networks
+# Copyright (c) 2009, 2010, 2011 Nicira Networks
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
$y *= $scale;
$width *= $scale;
$height *= $scale;
+ print "linethick = ", ($style eq 'bold' ? 0.5 : 1.0), ";\n";
print "box at $x,$y wid $width height $height \"$name\"\n";
+ if ($style eq 'bold') {
+ my $inset = 2.0 / 72.0;
+ $width -= $inset * 2;
+ $height -= $inset * 2;
+ print "box at $x,$y wid $width height $height\n";
+ }
} elsif (/edge/) {
my (undef, $tail, $head, $n, $rest) = split(' ', $_, 5);
my @xy;
}
my ($style, $color) = split(' ', $rest);
+ print "linethick = ", ($style eq 'dotted' ? 0.5 : 1), ";\n";
+
print "spline -> from $xy[0][0],$xy[0][1]";
for (my ($i) = 0; $i <= $#xy; $i++) {
print " to $xy[$i][0],$xy[$i][1]";
.SH "TABLE RELATIONSHIPS"
.PP
The following diagram shows the relationship among tables in the
-database. Each node represents a table. Each edge leads from the
+database. Each node represents a table. Tables that are part of the
+``root set'' are shown with double borders. Each edge leads from the
table that contains it and points to the table that its value
-represents. Edges are labeled with their column names.
+represents. Edges are labeled with their column names. Thick lines
+represent strong references; thin lines represent weak references.
.RS -1in
"""
erStream = open(erFile, "r")
options['label'] = '"%s"' % label
if baseType.ref_type == 'weak':
options['constraint'] = 'false'
+ options['style'] = 'dotted'
print "\t%s -> %s [%s];" % (
tableName,
baseType.ref_table,
schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile))
print "digraph %s {" % schema.name
+ print '\tsize="6.5,4";'
+ print '\tmargin="0";'
+ print "\tnode [shape=box];"
+ print "\tedge [dir=none, arrowhead=none, arrowtail=none];"
for tableName, table in schema.tables.iteritems():
- print '\tsize="6.5,4";'
- print '\tmargin="0";'
- print "\tnode [shape=box];"
- print "\tedge [dir=none, arrowhead=none, arrowtail=none];"
- print "\t%s;" % tableName
+ options = {}
+ if table.is_root:
+ options['style'] = 'bold'
+ print "\t%s [%s];" % (
+ tableName,
+ ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))
for columnName, column in table.columns.iteritems():
if column.type.value:
printEdge(tableName, column.type.key, "%s key" % columnName)
print "struct ovsdb_idl_table_class %stable_classes[%sN_TABLES] = {" % (prefix, prefix.upper())
for tableName, table in sorted(schema.tables.iteritems()):
structName = "%s%s" % (prefix, tableName.lower())
- print " {\"%s\"," % tableName
+ if table.is_root:
+ is_root = "true"
+ else:
+ is_root = "false"
+ print " {\"%s\", %s," % (tableName, is_root)
print " %s_columns, ARRAY_SIZE(%s_columns)," % (
structName, structName)
print " sizeof(struct %s)}," % structName
return n != -1 && s[n] == '\0';
}
+/* Returns the number of tables in 'schema''s root set. */
+static size_t
+root_set_size(const struct ovsdb_schema *schema)
+{
+ struct shash_node *node;
+ size_t n_root;
+
+ SHASH_FOR_EACH (node, &schema->tables) {
+ struct ovsdb_table_schema *table = node->data;
+
+ n_root += table->is_root;
+ }
+ return n_root;
+}
+
struct ovsdb_error *
ovsdb_schema_from_json(struct json *json, struct ovsdb_schema **schemap)
{
}
}
+ /* "isRoot" was not part of the original schema definition. Before it was
+ * added, there was no support for garbage collection. So, for backward
+ * compatibility, if the root set is empty then assume that every table is
+ * in the root set. */
+ if (root_set_size(schema) == 0) {
+ SHASH_FOR_EACH (node, &schema->tables) {
+ struct ovsdb_table_schema *table = node->data;
+
+ table->is_root = true;
+ }
+ }
+
*schemap = schema;
return 0;
}
{
struct json *json, *tables;
struct shash_node *node;
+ bool default_is_root;
json = json_object_create();
json_object_put_string(json, "name", schema->name);
json_object_put_string(json, "cksum", schema->cksum);
}
+ /* "isRoot" was not part of the original schema definition. Before it was
+ * added, there was no support for garbage collection. So, for backward
+ * compatibility, if every table is in the root set then do not output
+ * "isRoot" in table schemas. */
+ default_is_root = root_set_size(schema) == shash_count(&schema->tables);
+
tables = json_object_create();
SHASH_FOR_EACH (node, &schema->tables) {
struct ovsdb_table_schema *table = node->data;
json_object_put(tables, table->name,
- ovsdb_table_schema_to_json(table));
+ ovsdb_table_schema_to_json(table, default_is_root));
}
json_object_put(json, "tables", tables);
-/* Copyright (c) 2009, 2010 Nicira Networks
+/* Copyright (c) 2009, 2010, 2011 Nicira Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
struct ovsdb_table_schema *
ovsdb_table_schema_create(const char *name, bool mutable,
- unsigned int max_rows)
+ unsigned int max_rows, bool is_root)
{
struct ovsdb_column *uuid, *version;
struct ovsdb_table_schema *ts;
ts->mutable = mutable;
shash_init(&ts->columns);
ts->max_rows = max_rows;
+ ts->is_root = is_root;
uuid = ovsdb_column_create("_uuid", false, true, &ovsdb_type_uuid);
add_column(ts, uuid);
struct ovsdb_table_schema *new;
struct shash_node *node;
- new = ovsdb_table_schema_create(old->name, old->mutable, old->max_rows);
+ new = ovsdb_table_schema_create(old->name, old->mutable,
+ old->max_rows, old->is_root);
SHASH_FOR_EACH (node, &old->columns) {
const struct ovsdb_column *column = node->data;
struct ovsdb_table_schema **tsp)
{
struct ovsdb_table_schema *ts;
- const struct json *columns, *mutable, *max_rows;
+ const struct json *columns, *mutable, *max_rows, *is_root;
struct shash_node *node;
struct ovsdb_parser parser;
struct ovsdb_error *error;
OP_TRUE | OP_FALSE | OP_OPTIONAL);
max_rows = ovsdb_parser_member(&parser, "maxRows",
OP_INTEGER | OP_OPTIONAL);
+ is_root = ovsdb_parser_member(&parser, "isRoot", OP_BOOLEAN | OP_OPTIONAL);
error = ovsdb_parser_finish(&parser);
if (error) {
return error;
ts = ovsdb_table_schema_create(name,
mutable ? json_boolean(mutable) : true,
- MIN(n_max_rows, UINT_MAX));
+ MIN(n_max_rows, UINT_MAX),
+ is_root ? json_boolean(is_root) : false);
SHASH_FOR_EACH (node, json_object(columns)) {
struct ovsdb_column *column;
return 0;
}
+/* Returns table schema 'ts' serialized into JSON.
+ *
+ * The "isRoot" member is included in the JSON only if its value would differ
+ * from 'default_is_root'. Ordinarily 'default_is_root' should be false,
+ * because ordinarily a table would be not be part of the root set if its
+ * "isRoot" member is omitted. However, garbage collection was not orginally
+ * included in OVSDB, so in older schemas that do not include any "isRoot"
+ * members, every table is implicitly part of the root set. To serialize such
+ * a schema in a way that can be read by older OVSDB tools, specify
+ * 'default_is_root' as true. */
struct json *
-ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts)
+ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts,
+ bool default_is_root)
{
struct json *json, *columns;
struct shash_node *node;
if (!ts->mutable) {
json_object_put(json, "mutable", json_boolean_create(false));
}
+ if (default_is_root != ts->is_root) {
+ json_object_put(json, "isRoot", json_boolean_create(ts->is_root));
+ }
columns = json_object_create();
-/* Copyright (c) 2009, 2010 Nicira Networks
+/* Copyright (c) 2009, 2010, 2011 Nicira Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
bool mutable;
struct shash columns; /* Contains "struct ovsdb_column *"s. */
unsigned int max_rows; /* Maximum number of rows. */
+ bool is_root; /* Part of garbage collection root set? */
};
-struct ovsdb_table_schema *ovsdb_table_schema_create(const char *name,
- bool mutable,
- unsigned int max_rows);
+struct ovsdb_table_schema *ovsdb_table_schema_create(
+ const char *name, bool mutable, unsigned int max_rows, bool is_root);
struct ovsdb_table_schema *ovsdb_table_schema_clone(
const struct ovsdb_table_schema *);
void ovsdb_table_schema_destroy(struct ovsdb_table_schema *);
const char *name,
struct ovsdb_table_schema **)
WARN_UNUSED_RESULT;
-struct json *ovsdb_table_schema_to_json(const struct ovsdb_table_schema *);
+struct json *ovsdb_table_schema_to_json(const struct ovsdb_table_schema *,
+ bool default_is_root);
const struct ovsdb_column *ovsdb_table_schema_get_column(
const struct ovsdb_table_schema *, const char *name);
unsigned long changed[]; /* Bits set to 1 for columns that changed. */
};
+static struct ovsdb_error * WARN_UNUSED_RESULT
+delete_garbage_row(struct ovsdb_txn *txn, struct ovsdb_txn_row *r);
static void ovsdb_txn_row_prefree(struct ovsdb_txn_row *);
static struct ovsdb_error * WARN_UNUSED_RESULT
for_each_txn_row(struct ovsdb_txn *txn,
return NULL;
}
+static struct ovsdb_txn_row *
+find_or_make_txn_row(struct ovsdb_txn *txn, const struct ovsdb_table *table,
+ const struct uuid *uuid)
+{
+ struct ovsdb_txn_row *txn_row = find_txn_row(table, uuid);
+ if (!txn_row) {
+ const struct ovsdb_row *row = ovsdb_table_get_row(table, uuid);
+ if (row) {
+ txn_row = ovsdb_txn_row_modify(txn, row)->txn_row;
+ }
+ }
+ return txn_row;
+}
+
static struct ovsdb_error * WARN_UNUSED_RESULT
ovsdb_txn_adjust_atom_refs(struct ovsdb_txn *txn, const struct ovsdb_row *r,
const struct ovsdb_column *c,
table = base->u.uuid.refTable;
for (i = 0; i < n; i++) {
const struct uuid *uuid = &atoms[i].uuid;
- struct ovsdb_txn_row *txn_row = find_txn_row(table, uuid);
+ struct ovsdb_txn_row *txn_row;
+
if (uuid_equals(uuid, ovsdb_row_get_uuid(r))) {
/* Self-references don't count. */
continue;
}
+
+ txn_row = find_or_make_txn_row(txn, table, uuid);
if (!txn_row) {
- const struct ovsdb_row *row = ovsdb_table_get_row(table, uuid);
- if (row) {
- txn_row = ovsdb_txn_row_modify(txn, row)->txn_row;
- } else {
- return ovsdb_error("referential integrity violation",
- "Table %s column %s row "UUID_FMT" "
- "references nonexistent row "UUID_FMT" in "
- "table %s.",
- r->table->schema->name, c->name,
- UUID_ARGS(ovsdb_row_get_uuid(r)),
- UUID_ARGS(uuid), table->schema->name);
- }
+ return ovsdb_error("referential integrity violation",
+ "Table %s column %s row "UUID_FMT" "
+ "references nonexistent row "UUID_FMT" in "
+ "table %s.",
+ r->table->schema->name, c->name,
+ UUID_ARGS(ovsdb_row_get_uuid(r)),
+ UUID_ARGS(uuid), table->schema->name);
}
txn_row->n_refs += delta;
}
}
}
+static struct ovsdb_error * WARN_UNUSED_RESULT
+delete_row_refs(struct ovsdb_txn *txn, const struct ovsdb_row *row,
+ const struct ovsdb_base_type *base,
+ const union ovsdb_atom *atoms, unsigned int n)
+{
+ const struct ovsdb_table *table;
+ unsigned int i;
+
+ if (!ovsdb_base_type_is_strong_ref(base)) {
+ return NULL;
+ }
+
+ table = base->u.uuid.refTable;
+ for (i = 0; i < n; i++) {
+ const struct uuid *uuid = &atoms[i].uuid;
+ struct ovsdb_txn_row *txn_row;
+
+ if (uuid_equals(uuid, ovsdb_row_get_uuid(row))) {
+ /* Self-references don't count. */
+ continue;
+ }
+
+ txn_row = find_or_make_txn_row(txn, table, uuid);
+ if (!txn_row) {
+ return OVSDB_BUG("strong ref target missing");
+ } else if (!txn_row->n_refs) {
+ return OVSDB_BUG("strong ref target has zero n_refs");
+ } else if (!txn_row->new) {
+ return OVSDB_BUG("deleted strong ref target");
+ }
+
+ if (--txn_row->n_refs == 0) {
+ struct ovsdb_error *error = delete_garbage_row(txn, txn_row);
+ if (error) {
+ return error;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static struct ovsdb_error * WARN_UNUSED_RESULT
+delete_garbage_row(struct ovsdb_txn *txn, struct ovsdb_txn_row *txn_row)
+{
+ struct shash_node *node;
+ struct ovsdb_row *row;
+
+ if (txn_row->table->schema->is_root) {
+ return NULL;
+ }
+
+ row = txn_row->new;
+ txn_row->new = NULL;
+ hmap_remove(&txn_row->table->rows, &row->hmap_node);
+ SHASH_FOR_EACH (node, &txn_row->table->schema->columns) {
+ const struct ovsdb_column *column = node->data;
+ const struct ovsdb_datum *field = &row->fields[column->index];
+ struct ovsdb_error *error;
+
+ error = delete_row_refs(txn, row,
+ &column->type.key, field->keys, field->n);
+ if (error) {
+ return error;
+ }
+
+ error = delete_row_refs(txn, row,
+ &column->type.value, field->values, field->n);
+ if (error) {
+ return error;
+ }
+ }
+ ovsdb_row_destroy(row);
+
+ return NULL;
+}
+
+static struct ovsdb_error * WARN_UNUSED_RESULT
+collect_garbage(struct ovsdb_txn *txn, struct ovsdb_txn_row *txn_row)
+{
+ if (txn_row->new && !txn_row->n_refs) {
+ return delete_garbage_row(txn, txn_row);
+ }
+ return NULL;
+}
+
static struct ovsdb_error * WARN_UNUSED_RESULT
update_ref_counts(struct ovsdb_txn *txn)
{
return NULL;
}
- /* Check maximum rows table constraints. */
- error = check_max_rows(txn);
+ /* Update reference counts and check referential integrity. */
+ error = update_ref_counts(txn);
if (error) {
ovsdb_txn_abort(txn);
return error;
}
- /* Update reference counts and check referential integrity. */
- error = update_ref_counts(txn);
+ /* Delete unreferenced, non-root rows. */
+ error = for_each_txn_row(txn, collect_garbage);
+ if (error) {
+ ovsdb_txn_abort(txn);
+ return OVSDB_WRAP_BUG("can't happen", error);
+ }
+
+ /* Check maximum rows table constraints. */
+ error = check_max_rows(txn);
if (error) {
ovsdb_txn_abort(txn);
return error;
-# Copyright (c) 2009, 2010 Nicira Networks
+# Copyright (c) 2009, 2010, 2011 Nicira Networks
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
self.__check_ref_table(column, column.type.key, "key")
self.__check_ref_table(column, column.type.value, "value")
+ # "isRoot" was not part of the original schema definition. Before it
+ # was added, there was no support for garbage collection. So, for
+ # backward compatibility, if the root set is empty then assume that
+ # every table is in the root set.
+ if self.__root_set_size() == 0:
+ for table in self.tables.itervalues():
+ table.is_root = True
+
+ def __root_set_size(self):
+ """Returns the number of tables in the schema's root set."""
+ n_root = 0
+ for table in self.tables.itervalues():
+ if table.is_root:
+ n_root += 1
+ return n_root
+
@staticmethod
def from_json(json):
parser = ovs.db.parser.Parser(json, "database schema")
return DbSchema(name, version, tables)
def to_json(self):
+ # "isRoot" was not part of the original schema definition. Before it
+ # was added, there was no support for garbage collection. So, for
+ # backward compatibility, if every table is in the root set then do not
+ # output "isRoot" in table schemas.
+ default_is_root = self.__root_set_size() == len(self.tables)
+
tables = {}
for table in self.tables.itervalues():
- tables[table.name] = table.to_json()
+ tables[table.name] = table.to_json(default_is_root)
json = {"name": self.name, "tables": tables}
if self.version:
json["version"] = self.version
idlPrefix, idlHeader)
class TableSchema(object):
- def __init__(self, name, columns, mutable=True, max_rows=sys.maxint):
+ def __init__(self, name, columns, mutable=True, max_rows=sys.maxint,
+ is_root=True):
self.name = name
self.columns = columns
self.mutable = mutable
- self.max_rows = max_rows
+ self.max_rows = max_rows
+ self.is_root = is_root
@staticmethod
def from_json(json, name):
columnsJson = parser.get("columns", [dict])
mutable = parser.get_optional("mutable", [bool], True)
max_rows = parser.get_optional("maxRows", [int])
+ is_root = parser.get_optional("isRoot", [bool], False)
parser.finish()
if max_rows == None:
columns[columnName] = ColumnSchema.from_json(columnJson,
columnName)
- return TableSchema(name, columns, mutable, max_rows)
+ return TableSchema(name, columns, mutable, max_rows, is_root)
- def to_json(self):
+ def to_json(self, default_is_root=False):
+ """Returns this table schema serialized into JSON.
+
+ The "isRoot" member is included in the JSON only if its value would
+ differ from 'default_is_root'. Ordinarily 'default_is_root' should be
+ false, because ordinarily a table would be not be part of the root set
+ if its "isRoot" member is omitted. However, garbage collection was not
+ orginally included in OVSDB, so in older schemas that do not include
+ any "isRoot" members, every table is implicitly part of the root set.
+ To serialize such a schema in a way that can be read by older OVSDB
+ tools, specify 'default_is_root' as True.
+ """
json = {}
if not self.mutable:
json["mutable"] = False
+ if default_is_root != self.is_root:
+ json["isRoot"] = self.is_root
json["columns"] = columns = {}
for column in self.columns.itervalues():
AT_SETUP([database commands -- positive checks])
AT_KEYWORDS([ovs-vsctl])
OVS_VSCTL_SETUP
-AT_CHECK([RUN_OVS_VSCTL([create b name=br0])],
+AT_CHECK(
+ [RUN_OVS_VSCTL_TOGETHER([--id=@br0 create b name=br0],
+ [set o . bridges=@br0])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
cp stdout out1
AT_CHECK([RUN_OVS_VSCTL([list b], [get b br0 _uuid])],
cp stdout out2
AT_CHECK([perl $srcdir/uuidfilt.pl out1 out2], [0],
[[<0>
+
_uuid : <0>
controller : []
datapath_id : []
name : "br0"
datapath_type : ""
]], [ignore], [test ! -e pid || kill `cat pid`])
-AT_CHECK([RUN_OVS_VSCTL([create b name=br1 datapath_type="foo"],
- [create b name=br2 external-ids:bar=quux])],
+AT_CHECK([
+ RUN_OVS_VSCTL_TOGETHER([--id=@br1 create b name=br1 datapath_type="foo"],
+ [--id=@br2 create b name=br2 external-ids:bar=quux],
+ [add o . bridges @br1 @br2])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
AT_CHECK(
[RUN_OVS_VSCTL([--columns=name find b datapath_type!=foo])], [0], [stdout],
], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL_TOGETHER([destroy b br0],
[destroy b br1],
- [destroy b br2])],
+ [destroy b br2],
+ [clear o . bridges])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([list b])],
[0], [], [], [OVS_VSCTL_CLEANUP])
AT_SETUP([database commands -- negative checks])
AT_KEYWORDS([ovs-vsctl])
OVS_VSCTL_SETUP
-AT_CHECK([RUN_OVS_VSCTL([create b name=br0])],
+AT_CHECK([RUN_OVS_VSCTL([add-br br0])],
[0], [ignore], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([add-br br1])],
[0], [ignore], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([set-controller br1 tcp:127.0.0.1])],
[0], [ignore], [], [OVS_VSCTL_CLEANUP])
-AT_CHECK([RUN_OVS_VSCTL([create n targets='"1.2.3.4:567"'])],
+AT_CHECK([
+ RUN_OVS_VSCTL_TOGETHER([--id=@n create n targets='"1.2.3.4:567"'],
+ [set bridge br0 netflow=@n])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
cp stdout netflow-uuid
AT_CHECK([RUN_OVS_VSCTL([list n `cat netflow-uuid`])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([perl $srcdir/uuidfilt.pl netflow-uuid stdout], [0],
[[<0>
+
_uuid : <0>
active_timeout : 0
add_id_to_interface : false
OVS_VSCTL_CLEANUP
AT_CLEANUP
+AT_SETUP([unreferenced record warnings])
+AT_KEYWORDS([ovs-vsctl])
+OVS_VSCTL_SETUP
+AT_CHECK(
+ [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket \
+ -- create Bridge name=br0 | $srcdir/uuidfilt.pl],
+ [0], [<0>
+], [vsctl|WARN|applying "create" command to table Bridge without --id option will have no effect
+], [OVS_VSCTL_CLEANUP])
+AT_CHECK(
+ [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket \
+ -- --id=@br0 create Bridge name=br0 | $srcdir/uuidfilt.pl],
+ [0], [<0>
+], [vsctl|WARN|row id "@br0" was created but no reference to it was inserted, so it will not actually appear in the database
+], [OVS_VSCTL_CLEANUP])
+AT_CHECK(
+ [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:ANY:emer --db=unix:socket \
+ -- --id=@eth0_iface create Interface name=eth0 \
+ -- --id=@eth0 create Port name=eth0 interfaces=@eth0_iface \
+ -- --id=@m0 create Mirror name=m0 output_port=@eth0 \
+ -- --id=@br0 create Bridge name=br0 mirrors=@m0 \
+ -- set Open_vSwitch . bridges=@br0 | $srcdir/uuidfilt.pl],
+ [0], [<0>
+<1>
+<2>
+<3>
+], [vsctl|WARN|row id "@eth0" was created but only a weak reference to it was inserted, so it will not actually appear in the database
+], [OVS_VSCTL_CLEANUP])
+OVS_VSCTL_CLEANUP
+AT_CLEANUP
+
dnl This test really shows a bug -- "create" followed by "list" in
dnl the same execution shows the wrong UUID on the "list" command.
dnl The bug is documented in ovs-vsctl.8.
AT_SETUP([created row UUID is wrong in same execution])
AT_KEYWORDS([ovs-vsctl])
OVS_VSCTL_SETUP
-AT_CHECK([RUN_OVS_VSCTL([create Bridge name=br0 -- list b])],
+AT_CHECK([RUN_OVS_VSCTL([--id=@br0 create Bridge name=br0 -- add Open_vSwitch . bridges @br0 -- list b])],
[0], [stdout], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0],
[[<0>
"refType": "weak"},
"min": 0, "max": "unlimited"}}}}}}]])
+m4_define([GC_SCHEMA],
+ [[{"name": "gc",
+ "tables": {
+ "root": {
+ "columns": {
+ "a": {"type": {"key": {"type": "uuid",
+ "refTable": "a"},
+ "min": 0, "max": "unlimited"}}},
+ "isRoot": true},
+ "a": {
+ "columns": {
+ "a": {"type": "integer"},
+ "a2a": {"type": {"key": {"type": "uuid",
+ "refTable": "a"},
+ "min": 0, "max": "unlimited"}},
+ "a2b": {"type": {"key": {"type": "uuid",
+ "refTable": "b"},
+ "min": 0, "max": "unlimited"}},
+ "wa2a": {"type": {"key": {"type": "uuid",
+ "refTable": "a",
+ "refType": "weak"},
+ "min": 0, "max": "unlimited"}},
+ "wa2b": {"type": {"key": {"type": "uuid",
+ "refTable": "b",
+ "refType": "weak"},
+ "min": 0, "max": "unlimited"}}}},
+ "b": {
+ "columns": {
+ "b": {"type": "integer"},
+ "b2a": {"type": {"key": {"type": "uuid",
+ "refTable": "a"},
+ "min": 0, "max": "unlimited"}},
+ "wb2a": {"type": {"key": {"type": "uuid",
+ "refTable": "a",
+ "refType": "weak"},
+ "min": 0, "max": "unlimited"}}},
+ "isRoot": false}}}]])
+
# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
#
# Runs "test-ovsdb execute" with the given SCHEMA and each of the
[{"count":1}]
[{"rows":[]}]
[{"rows":[{"_uuid":["uuid","<3>"],"b":2,"b2a":["set",[]]},{"_uuid":["uuid","<4>"],"b":3,"b2a":["set",[]]}]}]
+]])
+
+OVSDB_CHECK_EXECUTION([garbage collection],
+ [GC_SCHEMA],
+ [dnl Check that inserting a row without any references is a no-op.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 0}}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]],
+ dnl Check that inserting a chain of rows that reference each other
+ dnl in turn is also a no-op.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 0, "a2a": ["named-uuid", "row1"]},
+ "uuid-name": "row0"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 1, "a2a": ["named-uuid", "row2"]},
+ "uuid-name": "row1"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 2, "a2a": ["named-uuid", "row3"]},
+ "uuid-name": "row2"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 3},
+ "uuid-name": "row3"}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]],
+ dnl Check that inserting a pair of rows that mutually reference each
+ dnl other causes the rows to be retained.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 4, "a2a": ["named-uuid", "row5"]},
+ "uuid-name": "row4"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 5, "a2a": ["named-uuid", "row4"]},
+ "uuid-name": "row5"}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"],
+ "sort": ["a"]}]]],
+ dnl Check that unreferencing one of the rows causes the other to be deleted.
+ [[["gc",
+ {"op": "update",
+ "table": "a",
+ "where": [["a", "==", 4]],
+ "row": {"a2a": ["set", []]}}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]],
+ dnl Check that inserting a pair of rows that mutually weak reference each
+ dnl other is a no-op.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 6, "wa2a": ["named-uuid", "row7"]},
+ "uuid-name": "row6"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 7, "wa2a": ["named-uuid", "row6"]},
+ "uuid-name": "row7"}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]],
+ dnl Check that a circular chain of rows is retained.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 8, "a2a": ["named-uuid", "row9"]},
+ "uuid-name": "row8"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 9, "a2a": ["named-uuid", "row10"]},
+ "uuid-name": "row9"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 10, "a2a": ["named-uuid", "row11"]},
+ "uuid-name": "row10"},
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 11, "a2a": ["named-uuid", "row8"]},
+ "uuid-name": "row11"}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"],
+ "sort": ["a"]}]]],
+ dnl Check that breaking the chain causes all of the rows to be deleted.
+ [[["gc",
+ {"op": "update",
+ "table": "a",
+ "where": [["a", "==", 9]],
+ "row": {"a2a": ["set", []]}}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]],
+ dnl Check that inserting a row only referenced by itself is a no-op.
+ [[["gc",
+ {"op": "insert",
+ "table": "a",
+ "row": {"a": 12, "a2a": ["named-uuid", "self"]},
+ "uuid-name": "self"}]]],
+ [[["gc",
+ {"op": "select",
+ "table": "a",
+ "where": [],
+ "columns": ["a"]}]]]],
+ [[[{"uuid":["uuid","<0>"]}]
+[{"rows":[]}]
+[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]},{"uuid":["uuid","<4>"]}]
+[{"rows":[]}]
+[{"uuid":["uuid","<5>"]},{"uuid":["uuid","<6>"]}]
+[{"rows":[{"a":4},{"a":5}]}]
+[{"count":1}]
+[{"rows":[]}]
+[{"uuid":["uuid","<7>"]},{"uuid":["uuid","<8>"]}]
+[{"rows":[]}]
+[{"uuid":["uuid","<9>"]},{"uuid":["uuid","<10>"]},{"uuid":["uuid","<11>"]},{"uuid":["uuid","<12>"]}]
+[{"rows":[{"a":8},{"a":9},{"a":10},{"a":11}]}]
+[{"count":1}]
+[{"rows":[]}]
+[{"uuid":["uuid","<13>"]}]
+[{"rows":[]}]
]])])
EXECUTION_EXAMPLES
AT_BANNER([OVSDB -- tables])
-OVSDB_CHECK_POSITIVE_CPY([table with one column],
+OVSDB_CHECK_POSITIVE_CPY([non-root table with one column],
[[parse-table mytable '{"columns": {"name": {"type": "string"}}}']],
[[{"columns":{"name":{"type":"string"}}}]])
"mutable": false}']],
[[{"columns":{"name":{"type":"string"}},"mutable":false}]])
+OVSDB_CHECK_POSITIVE_CPY([root table with one column],
+ [[parse-table mytable \
+ '{"columns": {"name": {"type": "string"}},
+ "isRoot": true}']],
+ [[{"columns":{"name":{"type":"string"}},"isRoot":true}]])
+
+OVSDB_CHECK_POSITIVE_CPY([non-root table with default_is_root=true],
+ [[parse-table mytable '{"columns": {"name": {"type": "string"}}}' true]],
+ [[{"columns":{"name":{"type":"string"}},"isRoot":false}]])
+
+OVSDB_CHECK_POSITIVE_CPY([root table with default_is_root=true],
+ [[parse-table mytable \
+ '{"columns": {"name": {"type": "string"}},
+ "isRoot": true}' true]],
+ [[{"columns":{"name":{"type":"string"}}}]])
+
OVSDB_CHECK_POSITIVE_CPY([table with maxRows of 2],
[[parse-table mytable '{"columns": {"name": {"type": "string"}},
"maxRows": 2}']],
" parse string DATUMs as data of given TYPE, and re-serialize\n"
" parse-column NAME OBJECT\n"
" parse column NAME with info OBJECT, and re-serialize\n"
- " parse-table NAME OBJECT\n"
+ " parse-table NAME OBJECT [DEFAULT-IS-ROOT]\n"
" parse table NAME with info OBJECT\n"
" parse-row TABLE ROW..., and re-serialize\n"
" parse each ROW of defined TABLE\n"
do_parse_table(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_table_schema *ts;
+ bool default_is_root;
struct json *json;
+ default_is_root = argc > 3 && !strcmp(argv[3], "true");
+
json = parse_json(argv[2]);
check_ovsdb_error(ovsdb_table_schema_from_json(json, argv[1], &ts));
json_destroy(json);
- print_and_free_json(ovsdb_table_schema_to_json(ts));
+ print_and_free_json(ovsdb_table_schema_to_json(ts, default_is_root));
ovsdb_table_schema_destroy(ts);
}
{ "parse-data-strings", 2, INT_MAX, do_parse_data_strings },
{ "sort-atoms", 2, 2, do_sort_atoms },
{ "parse-column", 2, 2, do_parse_column },
- { "parse-table", 2, 2, do_parse_table },
+ { "parse-table", 2, 3, do_parse_table },
{ "parse-rows", 2, INT_MAX, do_parse_rows },
{ "compare-rows", 2, INT_MAX, do_compare_rows },
{ "parse-conditions", 2, INT_MAX, do_parse_conditions },
-# Copyright (c) 2009, 2010 Nicira Networks
+# Copyright (c) 2009, 2010, 2011 Nicira Networks
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
print ovs.json.to_string(column.to_json(), sort_keys=True)
-def do_parse_table(name, table_string):
+def do_parse_table(name, table_string, default_is_root_string='false'):
+ default_is_root = default_is_root_string == 'true'
table_json = unbox_json(ovs.json.from_string(table_string))
table = ovs.db.schema.TableSchema.from_json(table_json, name)
- print ovs.json.to_string(table.to_json(), sort_keys=True)
+ print ovs.json.to_string(table.to_json(default_is_root), sort_keys=True)
def do_parse_rows(table_string, *rows):
table_json = unbox_json(ovs.json.from_string(table_string))
parse JSON DATUMs as data of given TYPE, and re-serialize
parse-column NAME OBJECT
parse column NAME with info OBJECT, and re-serialize
-parse-table NAME OBJECT
+parse-table NAME OBJECT [DEFAULT-IS-ROOT]
parse table NAME with info OBJECT
parse-schema JSON
parse JSON as an OVSDB schema, and re-serialize
"parse-data": (do_parse_data, (2,)),
"sort-atoms": (do_sort_atoms, 2),
"parse-column": (do_parse_column, 2),
- "parse-table": (do_parse_table, 2),
+ "parse-table": (do_parse_table, (2, 3)),
"parse-schema": (do_parse_schema, 1),
"idl": (do_idl, (1,))}
A network device attached to a port. Records may be identified by
name.
.IP "\fBQoS\fR"
-Quality-of-service configuration for an \fBInterface\fR.
+Quality-of-service configuration for a \fBPort\fR. Records may be
+identified by port name.
.IP "\fBQueue\fR"
-Configuration for one queue within a \fBQoS\fR configuration.
+Configuration for one queue within a \fBQoS\fR configuration. Records
+may only be identified by UUID.
.IP "\fBMonitor\fR"
Connectivity Monitoring attached to an \fBInterface\fR. Records may be
identified by \fBInterface\fR name.
referred to by that name elsewhere in the same \fBovs\-vsctl\fR
invocation in contexts where a UUID is expected. Such references may
precede or follow the \fBcreate\fR command.
+.IP
+Records in the Open vSwitch database are significant only when they
+can be reached directly or indirectly from the \fBOpen_vSwitch\fR
+table. Except for records in the \fBQoS\fR or \fBQueue\fR tables,
+records that are not reachable from the \fBOpen_vSwitch\fR table are
+automatically deleted from the database. This deletion happens
+immediately, without waiting for additional \fBovs\-vsctl\fR commands
+or other database activity. Thus, a \fBcreate\fR command must
+generally be accompanied by additional commands \fIwithin the same
+\fBovs\-vsctl\fI invocation\fR to add a chain of references to the
+newly created record from the top-level \fBOpen_vSwitch\fR record.
+The \fBEXAMPLES\fR section gives some examples that show how to do
+this.
.
.IP "\fR[\fB\-\-if\-exists\fR] \fBdestroy \fItable record\fR..."
Deletes each specified \fIrecord\fR from \fItable\fR. Unless
\fB\-\-if\-exists\fR is specified, each \fIrecord\fRs must exist.
+.IP
+It is often unnecessary to specify explicit \fBdestroy\fR commands,
+because (except for records in the \fBQoS\fR or \fBQueue\fR tables)
+records that are not reachable from the \fBOpen_vSwitch\fR table are
+automatically deleted from the database. This means that deleting the
+last reference to a record is sufficient for deleting the record
+itself. See the \fBEXAMPLES\fR section below for more information.
.
.IP "\fBwait\-until \fItable record \fR[\fIcolumn\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR]..."
Waits until \fItable\fR contains a record named \fIrecord\fR whose
.IP
.B "\-\- \-\-id=@m create Mirror name=mymirror select-dst-port=@eth0,@eth1 select-src-port=@eth0,@eth1 output-port=@eth2"
.PP
-Remove the mirror created above from \fBbr0\fR and destroy the Mirror
-record (to avoid having an unreferenced record in the database):
+Remove the mirror created above from \fBbr0\fR, which also destroys
+the Mirror record (since it is now unreferenced):
.IP
-.B "ovs\-vsctl destroy Mirror mymirror \-\- clear Bridge br0 mirrors"
+.B "remove Bridge br0 mirrors mymirror"
.SS "Quality of Service (QoS)"
.PP
Create a \fBlinux\-htb\fR QoS record that points to a few queues and
.B "ovs\-vsctl clear Port eth1 qos"
.PP
To deconfigure the QoS record from both \fBeth0\fR and \fBeth1\fR and
-then delete the QoS record:
+then delete the QoS record (which must be done explicitly because
+unreferenced QoS records are not automatically destroyed):
.IP
.B "ovs\-vsctl \-\- destroy QoS eth0 \-\- clear Port eth0 qos \-\- clear Port eth1 qos"
.PP
.IP
.B "ovs\-vsctl set NetFlow br0 active_timeout=60"
.PP
-Deconfigure the NetFlow settings from \fBbr0\fR and delete the NetFlow
-record (to avoid having an unreferenced record in the database):
+Deconfigure the NetFlow settings from \fBbr0\fR, which also destroys
+the NetFlow record (since it is now unreferenced):
.IP
-.B "ovs\-vsctl destroy NetFlow br0 \-\- clear Bridge br0 netflow"
+.B "ovs\-vsctl clear Bridge br0 netflow"
.SS "sFlow"
.PP
Configure bridge \fBbr0\fR to send sFlow records to a collector on
.IP
.B "\-\- set Bridge br0 sflow=@s"
.PP
-Deconfigure sFlow from br0 and destroy the sFlow record (to avoid
-having an unreferenced record in the database):
+Deconfigure sFlow from br0, which also destroys the sFlow record
+(since it is now unreferenced):
.IP
-.B "ovs\-vsctl \-\- destroy sFlow br0 \-\- clear Bridge br0 sflow"
+.B "ovs\-vsctl \-\- clear Bridge br0 sflow"
.SH "EXIT STATUS"
.IP "0"
Successful program execution.
const struct ovsrec_bridge *br;
const struct ovsrec_port *port;
const struct ovsrec_interface *iface;
- const struct ovsrec_mirror *mirror, *next_mirror;
- const struct ovsrec_controller *ctrl, *next_ctrl;
- const struct ovsrec_manager *mgr, *next_mgr;
- const struct ovsrec_netflow *nf, *next_nf;
- const struct ovsrec_ssl *ssl, *next_ssl;
- const struct ovsrec_sflow *sflow, *next_sflow;
/* Reset the Open_vSwitch table. */
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
ovsrec_interface_set_ingress_policing_rate(iface, 0);
ovsrec_interface_set_ingress_policing_burst(iface, 0);
}
-
- OVSREC_MIRROR_FOR_EACH_SAFE (mirror, next_mirror, idl) {
- ovsrec_mirror_delete(mirror);
- }
-
- OVSREC_CONTROLLER_FOR_EACH_SAFE (ctrl, next_ctrl, idl) {
- ovsrec_controller_delete(ctrl);
- }
-
- OVSREC_MANAGER_FOR_EACH_SAFE (mgr, next_mgr, idl) {
- ovsrec_manager_delete(mgr);
- }
-
- OVSREC_NETFLOW_FOR_EACH_SAFE (nf, next_nf, idl) {
- ovsrec_netflow_delete(nf);
- }
-
- OVSREC_SSL_FOR_EACH_SAFE (ssl, next_ssl, idl) {
- ovsrec_ssl_delete(ssl);
- }
-
- OVSREC_SFLOW_FOR_EACH_SAFE (sflow, next_sflow, idl) {
- ovsrec_sflow_delete(sflow);
- }
}
static void
}
static void
-del_port(struct vsctl_info *info, struct vsctl_port *port)
+del_port(struct vsctl_port *port)
{
- struct shash_node *node;
-
- SHASH_FOR_EACH (node, &info->ifaces) {
- struct vsctl_iface *iface = node->data;
- if (iface->port == port) {
- ovsrec_interface_delete(iface->iface_cfg);
- }
- }
- ovsrec_port_delete(port->port_cfg);
-
bridge_delete_port((port->bridge->parent
? port->bridge->parent->br_cfg
: port->bridge->br_cfg), port->port_cfg);
get_info(ctx, &info);
bridge = find_bridge(&info, ctx->argv[1], must_exist);
if (bridge) {
- struct shash_node *node;
-
- SHASH_FOR_EACH (node, &info.ports) {
- struct vsctl_port *port = node->data;
- if (port->bridge == bridge || port->bridge->parent == bridge
- || !strcmp(port->port_cfg->name, bridge->name)) {
- del_port(&info, port);
- }
- }
if (bridge->br_cfg) {
- ovsrec_bridge_delete(bridge->br_cfg);
ovs_delete_bridge(ctx->ovs, bridge->br_cfg);
+ } else {
+ struct shash_node *node;
+
+ SHASH_FOR_EACH (node, &info.ports) {
+ struct vsctl_port *port = node->data;
+ if (port->bridge == bridge || port->bridge->parent == bridge
+ || !strcmp(port->port_cfg->name, bridge->name)) {
+ del_port(port);
+ }
+ }
}
}
free_info(&info);
}
}
- del_port(&info, port);
+ del_port(port);
}
free_info(&info);
free_info(&info);
}
-static void
-delete_controllers(struct ovsrec_controller **controllers,
- size_t n_controllers)
-{
- size_t i;
-
- for (i = 0; i < n_controllers; i++) {
- ovsrec_controller_delete(controllers[i]);
- }
-}
-
static void
cmd_del_controller(struct vsctl_context *ctx)
{
struct vsctl_bridge *br;
get_info(ctx, &info);
- br = find_real_bridge(&info, ctx->argv[1], true);
- verify_controllers(br->br_cfg);
- if (br->ctrl) {
- delete_controllers(br->ctrl, br->n_ctrl);
- ovsrec_bridge_set_controller(br->br_cfg, NULL, 0);
- }
+ br = find_real_bridge(&info, ctx->argv[1], true);
+ ovsrec_bridge_set_controller(br->br_cfg, NULL, 0);
free_info(&info);
}
get_info(ctx, &info);
br = find_real_bridge(&info, ctx->argv[1], true);
- verify_controllers(br->br_cfg);
-
- delete_controllers(br->ctrl, br->n_ctrl);
n = ctx->argc - 2;
controllers = insert_controllers(ctx->txn, &ctx->argv[2], n);
svec_destroy(&targets);
}
-static void
-delete_managers(const struct vsctl_context *ctx)
-{
- const struct ovsrec_open_vswitch *ovs = ctx->ovs;
- size_t i;
-
- /* 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]);
- }
-
- /* Delete 'Manager' row refs in 'manager_options' column. */
- ovsrec_open_vswitch_set_manager_options(ovs, NULL, 0);
-}
-
static void
cmd_del_manager(struct vsctl_context *ctx)
{
const struct ovsrec_open_vswitch *ovs = ctx->ovs;
- verify_managers(ovs);
- delete_managers(ctx);
+ ovsrec_open_vswitch_set_manager_options(ovs, NULL, 0);
}
static void
{
const size_t n = ctx->argc - 1;
- verify_managers(ctx->ovs);
- delete_managers(ctx);
insert_managers(ctx, &ctx->argv[1], n);
}
static void
cmd_del_ssl(struct vsctl_context *ctx)
{
- struct ovsrec_ssl *ssl = ctx->ovs->ssl;
-
- if (ssl) {
- ovsrec_open_vswitch_verify_ssl(ctx->ovs);
- ovsrec_ssl_delete(ssl);
- ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL);
- }
+ ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL);
}
static void
cmd_set_ssl(struct vsctl_context *ctx)
{
bool bootstrap = shash_find(&ctx->options, "--bootstrap");
- struct ovsrec_ssl *ssl = ctx->ovs->ssl;
+ struct ovsrec_ssl *ssl;
- ovsrec_open_vswitch_verify_ssl(ctx->ovs);
- if (ssl) {
- ovsrec_ssl_delete(ssl);
- }
ssl = ovsrec_ssl_insert(ctx->txn);
ovsrec_ssl_set_private_key(ssl, ctx->argv[1]);
}
}
-static struct uuid *
+static struct ovsdb_symbol *
create_symbol(struct ovsdb_symbol_table *symtab, const char *id, bool *newp)
{
struct ovsdb_symbol *symbol;
id);
}
symbol->created = true;
- return &symbol->uuid;
+ return symbol;
}
static void
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;
}
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);
"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);
{"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, "",
}
ovsrec_bridge_set_ports(br, ports, n);
free(ports);
-
- /* Delete all of the port's interfaces. */
- for (i = 0; i < port->n_interfaces; i++) {
- ovsrec_interface_delete(port->interfaces[i]);
- }
-
- /* Delete the port itself. */
- ovsrec_port_delete(port);
}
/* Delete 'iface' from 'port' (which must be within 'br'). If 'iface' was
}
ovsrec_port_set_interfaces(port, ifaces, n);
free(ifaces);
- ovsrec_interface_delete(iface);
}
}
ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name);
- /* Delete everything that the bridge points to, then delete the bridge
- * itself. */
- while (br->n_ports > 0) {
- del_port(br, br->ports[0]);
- }
- for (i = 0; i < br->n_mirrors; i++) {
- ovsrec_mirror_delete(br->mirrors[i]);
- }
- if (br->netflow) {
- ovsrec_netflow_delete(br->netflow);
- }
- if (br->sflow) {
- ovsrec_sflow_delete(br->sflow);
- }
- for (i = 0; i < br->n_controller; i++) {
- ovsrec_controller_delete(br->controller[i]);
- }
-
/* Remove 'br' from the vswitch's list of bridges. */
bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges);
for (i = n = 0; i < ovs->n_bridges; i++) {
ovsrec_open_vswitch_set_bridges(ovs, bridges, n);
free(bridges);
- /* Delete the bridge itself. */
- ovsrec_bridge_delete(br);
-
return commit_txn(txn, true);
}
margin="0";
node [shape=box];
edge [dir=none, arrowhead=none, arrowtail=none];
- Bridge;
+ Bridge [style=bold];
Bridge -> sFlow [label="sflow"];
Bridge -> Mirror [label="mirrors"];
Bridge -> Port [label="ports"];
Bridge -> Controller [label="controller"];
Bridge -> NetFlow [label="netflow"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- QoS;
+ QoS [style=bold];
QoS -> Queue [label="queues value"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Monitor;
+ Monitor [style=bold];
Monitor -> Maintenance_Point [label="remote_mps"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- sFlow;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Open_vSwitch;
+ sFlow [style=bold];
+ Open_vSwitch [style=bold];
Open_vSwitch -> Bridge [label="bridges"];
Open_vSwitch -> Capability [label="capabilities value"];
Open_vSwitch -> SSL [label="ssl"];
Open_vSwitch -> Manager [label="manager_options"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Controller;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Queue;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- SSL;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Manager;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Capability;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Mirror;
- Mirror -> Port [constraint=false, label="select_src_port"];
- Mirror -> Port [constraint=false, label="output_port"];
- Mirror -> Port [constraint=false, label="select_dst_port"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Interface;
+ Controller [style=bold];
+ Queue [style=bold];
+ SSL [style=bold];
+ Manager [style=bold];
+ Capability [style=bold];
+ Mirror [style=bold];
+ Mirror -> Port [style=dotted, constraint=false, label="select_src_port"];
+ Mirror -> Port [style=dotted, constraint=false, label="output_port"];
+ Mirror -> Port [style=dotted, constraint=false, label="select_dst_port"];
+ Interface [style=bold];
Interface -> Monitor [label="monitor"];
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- NetFlow;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Maintenance_Point;
- size="6.5,4";
- margin="0";
- node [shape=box];
- edge [dir=none, arrowhead=none, arrowtail=none];
- Port;
+ NetFlow [style=bold];
+ Maintenance_Point [style=bold];
+ Port [style=bold];
Port -> QoS [label="qos"];
Port -> Interface [label="interfaces"];
}
{"name": "Open_vSwitch",
- "version": "2.0.0",
- "cksum": "4107852581 15651",
+ "version": "2.1.0",
+ "cksum": "1990266641 15714",
"tables": {
"Open_vSwitch": {
"columns": {
"system_version": {
"type": {"key": {"type": "string"},
"min": 0, "max": 1}}},
+ "isRoot": true,
"maxRows": 1},
"Capability": {
"columns": {
"min": 0, "max": "unlimited"}},
"external_ids": {
"type": {"key": "string", "value": "string",
- "min": 0, "max": "unlimited"}}}},
+ "min": 0, "max": "unlimited"}}},
+ "isRoot": true},
"Queue": {
"columns": {
"other_config": {
"min": 0, "max": "unlimited"}},
"external_ids": {
"type": {"key": "string", "value": "string",
- "min": 0, "max": "unlimited"}}}},
+ "min": 0, "max": "unlimited"}}},
+ "isRoot": true},
"Mirror": {
"columns": {
"name": {
-.\" Generated from vswitch.gv with cksum "3734436941 2390"
+.\" Generated from vswitch.gv with cksum "1122829786 1269"
.PS
linethick = 1;
+linethick = 0.5;
box at 2.320997253,3.1110975 wid 0.5020540998 height 0.296295 "Bridge"
+box at 2.320997253,3.1110975 wid 0.446498544244444 height 0.240739444444444
+linethick = 0.5;
box at 0.2304523251,2.37036 wid 0.4609046502 height 0.296295 "sFlow"
+box at 0.2304523251,2.37036 wid 0.405349094644444 height 0.240739444444444
+linethick = 0.5;
box at 0.847759254,2.37036 wid 0.4855919496 height 0.296295 "Mirror"
+box at 0.847759254,2.37036 wid 0.430036394044444 height 0.240739444444444
+linethick = 0.5;
box at 2.320997253,2.37036 wid 0.4444425 height 0.296295 "Port"
+box at 2.320997253,2.37036 wid 0.388886944444444 height 0.240739444444444
+linethick = 0.5;
box at 3.045260751,2.37036 wid 0.707789496 height 0.296295 "Controller"
+box at 3.045260751,2.37036 wid 0.652233940444444 height 0.240739444444444
+linethick = 0.5;
box at 3.851835,2.37036 wid 0.609064002 height 0.296295 "NetFlow"
+box at 3.851835,2.37036 wid 0.553508446444444 height 0.240739444444444
+linethick = 0.5;
box at 2.057590998,1.6296225 wid 0.4444425 height 0.296295 "QoS"
+box at 2.057590998,1.6296225 wid 0.388886944444444 height 0.240739444444444
+linethick = 0.5;
box at 1.991754249,0.888885 wid 0.5102851749 height 0.296295 "Queue"
+box at 1.991754249,0.888885 wid 0.454729619344444 height 0.240739444444444
+linethick = 0.5;
box at 2.938238997,0.888885 wid 0.5761278498 height 0.296295 "Monitor"
+box at 2.938238997,0.888885 wid 0.520572294244444 height 0.240739444444444
+linethick = 0.5;
box at 2.938238997,0.1481475 wid 1.218128004 height 0.296295 "Maintenance_Point"
+box at 2.938238997,0.1481475 wid 1.16257244844444 height 0.240739444444444
+linethick = 0.5;
box at 3.637850751,3.851835 wid 0.954721749 height 0.296295 "Open_vSwitch"
+box at 3.637850751,3.851835 wid 0.899166193444444 height 0.240739444444444
+linethick = 0.5;
box at 3.061734753,3.1110975 wid 0.699611754 height 0.296295 "Capability"
+box at 3.061734753,3.1110975 wid 0.644056198444444 height 0.240739444444444
+linethick = 0.5;
box at 4.22220375,3.1110975 wid 0.4444425 height 0.296295 "SSL"
+box at 4.22220375,3.1110975 wid 0.388886944444444 height 0.240739444444444
+linethick = 0.5;
box at 4.905341502,3.1110975 wid 0.633715746 height 0.296295 "Manager"
+box at 4.905341502,3.1110975 wid 0.578160190444444 height 0.240739444444444
+linethick = 0.5;
box at 2.872402248,1.6296225 wid 0.641952747 height 0.296295 "Interface"
+box at 2.872402248,1.6296225 wid 0.586397191444444 height 0.240739444444444
+linethick = 1;
spline -> from 2.072227971,3.066534732 to 2.072227971,3.066534732 to 1.825829049,3.018534942 to 1.439934441,2.932787169 to 1.119343251,2.8148025 to 0.887818338,2.729588058 to 0.637567581,2.60087751 to 0.4617876093,2.503870527
"sflow" at 1.271579622,2.74072875
+linethick = 1;
spline -> from 2.071042791,2.98546842 to 2.071042791,2.98546842 to 1.796021772,2.847157914 to 1.357208877,2.626536657 to 1.086632283,2.490477993
"mirrors" at 1.9259175,2.74072875
+linethick = 1;
spline -> from 2.320997253,2.96117223 to 2.320997253,2.96117223 to 2.320997253,2.832698718 to 2.320997253,2.648462487 to 2.320997253,2.520048234
"ports" at 2.469144753,2.74072875
+linethick = 1;
spline -> from 2.495218713,2.960816676 to 2.495218713,2.960816676 to 2.546240712,2.915068728 to 2.601410841,2.863868952 to 2.650180998,2.8148025 to 2.743336146,2.721054762 to 2.842120899,2.609944137 to 2.917557606,2.522300076
"controller" at 3.065823624,2.74072875
+linethick = 1;
spline -> from 2.571070233,2.988964701 to 2.571070233,2.988964701 to 2.594773833,2.979424002 to 2.61865521,2.970594411 to 2.641943997,2.96295 to 2.957675949,2.859720822 to 3.079038381,2.966624058 to 3.374444496,2.8148025 to 3.514473513,2.742862074 to 3.643184061,2.618003361 to 3.731598489,2.518922313
"netflow" at 3.802472253,2.74072875
+linethick = 0.5;
spline -> from 1.091017449,2.37036 to 1.091017449,2.37036 to 1.370542152,2.37036 to 1.825414236,2.37036 to 2.096701938,2.37036
"select_src_port" at 1.588496754,2.44443375
+linethick = 0.5;
spline -> from 1.067787921,2.221501392 to 1.067787921,2.221501392 to 1.095284097,2.208345894 to 1.123787676,2.197086684 to 1.152231996,2.189264496 to 1.526156286,2.08650939 to 1.651429812,2.084257548 to 2.024702253,2.189264496 to 2.052553983,2.197145943 to 2.080346454,2.208405153 to 2.107190781,2.221501392
"output_port" at 1.588496754,2.263338246
+linethick = 0.5;
spline -> from 0.905240484,2.221264356 to 0.905240484,2.221264356 to 0.953892123,2.117798142 to 1.034780658,1.987843155 to 1.152231996,1.9259175 to 1.495282347,1.745118291 to 1.682837082,1.742984967 to 2.024702253,1.9259175 to 2.140790634,1.988080191 to 2.21924955,2.117975919 to 2.266123419,2.221442133
"select_dst_port" at 1.588496754,1.99999125
+linethick = 1;
spline -> from 2.267664153,2.22043473 to 2.267664153,2.22043473 to 2.221975464,2.091961218 to 2.156494269,1.907724987 to 2.11080558,1.779310734
"qos" at 2.312760252,1.99999125
+linethick = 1;
spline -> from 2.43258195,2.22043473 to 2.43258195,2.22043473 to 2.528225976,2.091961218 to 2.665351302,1.907724987 to 2.760995328,1.779310734
"interfaces" at 2.930001996,1.99999125
+linethick = 1;
spline -> from 2.023220778,1.479637971 to 2.023220778,1.479637971 to 2.013917115,1.433001138 to 2.005028265,1.381268031 to 1.99999125,1.3333275 to 1.989620925,1.235076078 to 1.98754686,1.123965453 to 1.988080191,1.037447313
"queues value" at 2.378597001,1.25925375
+linethick = 1;
spline -> from 2.938238997,0.73895973 to 2.938238997,0.73895973 to 2.938238997,0.610486218 to 2.938238997,0.4262736906 to 2.938238997,0.2978238822
"remote_mps" at 3.288044874,0.51851625
+linethick = 1;
spline -> from 3.159808398,3.796309317 to 3.159808398,3.796309317 to 2.96591295,3.754828017 to 2.749321305,3.682295001 to 2.584344249,3.55554 to 2.486211345,3.480162552 to 2.417352387,3.356903832 to 2.374685907,3.259245
"bridges" at 2.790091497,3.48146625
+linethick = 1;
spline -> from 3.219067398,3.702146766 to 3.219067398,3.702146766 to 3.159926916,3.663332121 to 3.106830852,3.615095295 to 3.069971754,3.55554 to 3.015927546,3.468251493 to 3.015809028,3.35168904 to 3.028194159,3.25983759
"capabilities value" at 3.55554,3.48146625
+linethick = 1;
spline -> from 3.884901522,3.703568982 to 3.884901522,3.703568982 to 3.941612385,3.661080279 to 3.997849176,3.611065683 to 4.041108246,3.55554 to 4.109256096,3.468132975 to 4.155478116,3.351570522 to 4.184159472,3.259778331
"ssl" at 4.205729748,3.48146625
+linethick = 1;
spline -> from 4.020249078,3.702146766 to 4.020249078,3.702146766 to 4.117848651,3.659065473 to 4.22101857,3.609110136 to 4.312751502,3.55554 to 4.46042493,3.469258896 to 4.614616848,3.352696443 to 4.728690423,3.260548698
"manager_options" at 5.024689128,3.48146625
+linethick = 1;
spline -> from 2.885735523,1.47969723 to 2.885735523,1.47969723 to 2.89717251,1.351223718 to 2.913527994,1.166987487 to 2.924964981,1.038573234
"monitor" at 3.139897374,1.25925375
.PE
<?xml version="1.0" encoding="utf-8"?>
<database title="Open vSwitch Configuration Database">
- <p>A database with this schema holds the configuration for one Open
- vSwitch daemon. The root of the configuration for the daemon is
- the <ref table="Open_vSwitch"/> table, which must have exactly one
+ <p>
+ A database with this schema holds the configuration for one Open
+ vSwitch daemon. The top-level configuration for the daemon is the
+ <ref table="Open_vSwitch"/> table, which must have exactly one
record. Records in other tables are significant only when they
- can be reached directly or indirectly from the
- <ref table="Open_vSwitch"/> table.</p>
+ can be reached directly or indirectly from the <ref
+ table="Open_vSwitch"/> table. Records that are not reachable from
+ the <ref table="Open_vSwitch"/> table are automatically deleted
+ from the database, except for records in a few distinguished
+ ``root set'' tables noted below.
+ </p>
<table name="Open_vSwitch" title="Open vSwitch configuration.">
- Configuration for an Open vSwitch daemon. There must be exactly one record
- in the <ref table="Open_vSwitch"/> table.
+ Configuration for an Open vSwitch daemon. There must be exactly
+ one record in the <ref table="Open_vSwitch"/> table.
<group title="Configuration">
<column name="bridges">
cksum=`$ovsdb_tool db-cksum "$OVSDB_SERVER_DB" | awk '{print $1}'`
cp "$OVSDB_SERVER_DB" "$OVSDB_SERVER_DB.backup$version-$cksum"
- # Upgrade or downgrade schema and compact database.
+ # Compact database. This is important if the old schema did not enable
+ # garbage collection (i.e. if it did not have any tables with "isRoot":
+ # true) but the new schema does. In that situation the old database
+ # may contain a transaction that creates a record followed by a
+ # transaction that creates the first use of the record. Replaying that
+ # series of transactions against the new database schema (as "convert"
+ # does) would cause the record to be dropped by the first transaction,
+ # then the second transaction would cause a referential integrity
+ # failure (for a strong reference).
+ $ovsdb_tool -vANY:console:emer compact "$OVSDB_SERVER_DB"
+
+ # Upgrade or downgrade schema.
$ovsdb_tool -vANY:console:emer convert "$OVSDB_SERVER_DB" "$VSWITCHD_OVSDB_SCHEMA"
fi