2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-03 15:55:19 +00:00

ovsdb-idl: Check internal graph in OVSDB tests.

Some upcoming tests will add extra trickiness to the IDL internal graph.
This worries me, because the IDL doesn't have any checks for its graph
consistency.  This commit adds some.

Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Andy Zhou <azhou@ovn.org>
This commit is contained in:
Ben Pfaff
2016-09-07 09:04:46 -07:00
parent 012d37621a
commit 11990a5274
3 changed files with 131 additions and 0 deletions

View File

@@ -629,6 +629,128 @@ ovsdb_idl_set_probe_interval(const struct ovsdb_idl *idl, int probe_interval)
{
jsonrpc_session_set_probe_interval(idl->session, probe_interval);
}
static size_t
find_uuid_in_array(const struct uuid *target,
const struct uuid *array, size_t n)
{
for (size_t i = 0; i < n; i++) {
if (uuid_equals(&array[i], target)) {
return i;
}
}
return SIZE_MAX;
}
static size_t
array_contains_uuid(const struct uuid *target,
const struct uuid *array, size_t n)
{
return find_uuid_in_array(target, array, n) != SIZE_MAX;
}
static bool
remove_uuid_from_array(const struct uuid *target,
struct uuid *array, size_t *n)
{
size_t i = find_uuid_in_array(target, array, *n);
if (i != SIZE_MAX) {
array[i] = array[--*n];
return true;
} else {
return false;
}
}
static void
add_row_references(const struct ovsdb_base_type *type,
const union ovsdb_atom *atoms, size_t n_atoms,
const struct uuid *exclude_uuid,
struct uuid **dstsp, size_t *n_dstsp,
size_t *allocated_dstsp)
{
if (type->type != OVSDB_TYPE_UUID || !type->u.uuid.refTableName) {
return;
}
for (size_t i = 0; i < n_atoms; i++) {
const struct uuid *uuid = &atoms[i].uuid;
if (!uuid_equals(uuid, exclude_uuid)
&& !array_contains_uuid(uuid, *dstsp, *n_dstsp)) {
if (*n_dstsp >= *allocated_dstsp) {
*dstsp = x2nrealloc(*dstsp, allocated_dstsp,
sizeof **dstsp);
}
(*dstsp)[*n_dstsp] = *uuid;
++*n_dstsp;
}
}
}
/* Checks for consistency in 'idl''s graph of arcs between database rows. Each
* reference from one row to a different row should be reflected as a "struct
* ovsdb_idl_arc" between those rows.
*
* This function is slow, big-O wise, and aborts if it finds an inconsistency,
* thus it is only for use in test programs. */
void
ovsdb_idl_check_consistency(const struct ovsdb_idl *idl)
{
/* Consistency is broken while a transaction is in progress. */
if (!idl->txn) {
return;
}
bool ok = true;
struct uuid *dsts = NULL;
size_t allocated_dsts = 0;
for (size_t i = 0; i < idl->class->n_tables; i++) {
const struct ovsdb_idl_table *table = &idl->tables[i];
const struct ovsdb_idl_table_class *class = table->class;
const struct ovsdb_idl_row *row;
HMAP_FOR_EACH (row, hmap_node, &table->rows) {
size_t n_dsts = 0;
if (row->new) {
size_t n_columns = shash_count(&row->table->columns);
for (size_t j = 0; j < n_columns; j++) {
const struct ovsdb_type *type = &class->columns[j].type;
const struct ovsdb_datum *datum = &row->new[j];
add_row_references(&type->key,
datum->keys, datum->n, &row->uuid,
&dsts, &n_dsts, &allocated_dsts);
add_row_references(&type->value,
datum->values, datum->n, &row->uuid,
&dsts, &n_dsts, &allocated_dsts);
}
}
const struct ovsdb_idl_arc *arc;
LIST_FOR_EACH (arc, src_node, &row->src_arcs) {
if (!remove_uuid_from_array(&arc->dst->uuid,
dsts, &n_dsts)) {
VLOG_ERR("unexpected arc from %s row "UUID_FMT" to %s "
"row "UUID_FMT,
table->class->name,
UUID_ARGS(&row->uuid),
arc->dst->table->class->name,
UUID_ARGS(&arc->dst->uuid));
ok = false;
}
}
for (size_t i = 0; i < n_dsts; i++) {
VLOG_ERR("%s row "UUID_FMT" missing arc to row "UUID_FMT,
table->class->name, UUID_ARGS(&row->uuid),
UUID_ARGS(&dsts[i]));
ok = false;
}
}
}
free(dsts);
ovs_assert(ok);
}
static unsigned char *
ovsdb_idl_get_mode(struct ovsdb_idl *idl,

View File

@@ -75,6 +75,8 @@ bool ovsdb_idl_is_alive(const struct ovsdb_idl *);
int ovsdb_idl_get_last_error(const struct ovsdb_idl *);
void ovsdb_idl_set_probe_interval(const struct ovsdb_idl *, int probe_interval);
void ovsdb_idl_check_consistency(const struct ovsdb_idl *);
/* Choosing columns and tables to replicate. */

View File

@@ -2038,6 +2038,7 @@ idl_set(struct ovsdb_idl *idl, char *commands, int step)
bool increment = false;
txn = ovsdb_idl_txn_create(idl);
ovsdb_idl_check_consistency(idl);
for (cmd = strtok_r(commands, ",", &save_ptr1); cmd;
cmd = strtok_r(NULL, ",", &save_ptr1)) {
char *save_ptr2 = NULL;
@@ -2144,14 +2145,17 @@ idl_set(struct ovsdb_idl *idl, char *commands, int step)
increment = true;
} else if (!strcmp(name, "abort")) {
ovsdb_idl_txn_abort(txn);
ovsdb_idl_check_consistency(idl);
break;
} else if (!strcmp(name, "destroy")) {
printf("%03d: destroy\n", step);
ovsdb_idl_txn_destroy(txn);
ovsdb_idl_check_consistency(idl);
return;
} else {
ovs_fatal(0, "unknown command %s", name);
}
ovsdb_idl_check_consistency(idl);
}
status = ovsdb_idl_txn_commit_block(txn);
@@ -2163,6 +2167,7 @@ idl_set(struct ovsdb_idl *idl, char *commands, int step)
}
putchar('\n');
ovsdb_idl_txn_destroy(txn);
ovsdb_idl_check_consistency(idl);
}
static const struct ovsdb_idl_table_class *
@@ -2422,6 +2427,7 @@ do_idl(struct ovs_cmdl_context *ctx)
/* Wait for update. */
for (;;) {
ovsdb_idl_run(idl);
ovsdb_idl_check_consistency(idl);
if (ovsdb_idl_get_seqno(idl) != seqno) {
break;
}
@@ -2474,6 +2480,7 @@ do_idl(struct ovs_cmdl_context *ctx)
}
for (;;) {
ovsdb_idl_run(idl);
ovsdb_idl_check_consistency(idl);
if (ovsdb_idl_get_seqno(idl) != seqno) {
break;
}