#include "ovsdb-idl.h"
#include "ovsdb-idl-provider.h"
#include "shash.h"
+#include "sset.h"
#include "string.h"
#include "table.h"
#include "util.h"
VLOG_DEFINE_THIS_MODULE(db_ctl_base);
-/* The IDL we're using and the current transaction, if any.
- * This is for use by ctl_exit() only, to allow it to clean up.
- * Other code should use its context arguments. */
-struct ovsdb_idl *the_idl;
-struct ovsdb_idl_txn *the_idl_txn;
+/* This array defines the 'show' command output format. User can check the
+ * definition in utilities/ovs-vsctl.c as reference.
+ *
+ * Particularly, if an element in 'columns[]' represents a reference to
+ * another table, the referred table must also be defined as an entry in
+ * in 'cmd_show_tables[]'.
+ *
+ * The definition must end with an all-NULL entry. It is initalized once
+ * when ctl_init() is called.
+ *
+ * */
+static const struct cmd_show_table *cmd_show_tables;
+
+/* ctl_exit() is called by ctl_fatal(). User can optionally supply an exit
+ * function ctl_exit_func() via ctl_init. If supplied, this function will
+ * be called by ctl_exit()
+ */
+static void (*ctl_exit_func)(int status) = NULL;
+OVS_NO_RETURN static void ctl_exit(int status);
/* Represents all tables in the schema. User must define 'tables'
* in implementation and supply via clt_init(). The definition must end
bool must_exist = !shash_find(&ctx->options, "--if-exists");
const char *table_name = ctx->argv[1];
const char *record_id = ctx->argv[2];
- const struct ctl_table_class*table;
+ const struct ctl_table_class *table;
const struct ovsdb_idl_row *row;
int i;
static void
pre_cmd_show(struct ctl_context *ctx)
{
- struct cmd_show_table *show;
+ const struct cmd_show_table *show;
for (show = cmd_show_tables; show->table; show++) {
size_t i;
ovsdb_idl_add_column(ctx->idl, column);
}
}
+ if (show->wref_table.table) {
+ ovsdb_idl_add_table(ctx->idl, show->wref_table.table);
+ }
+ if (show->wref_table.name_column) {
+ ovsdb_idl_add_column(ctx->idl, show->wref_table.name_column);
+ }
+ if (show->wref_table.wref_column) {
+ ovsdb_idl_add_column(ctx->idl, show->wref_table.wref_column);
+ }
}
}
-static struct cmd_show_table *
+static const struct cmd_show_table *
cmd_show_find_table_by_row(const struct ovsdb_idl_row *row)
{
- struct cmd_show_table *show;
+ const struct cmd_show_table *show;
for (show = cmd_show_tables; show->table; show++) {
if (show->table == row->table->class) {
return NULL;
}
-static struct cmd_show_table *
+static const struct cmd_show_table *
cmd_show_find_table_by_name(const char *name)
{
- struct cmd_show_table *show;
+ const struct cmd_show_table *show;
for (show = cmd_show_tables; show->table; show++) {
if (!strcmp(show->table->name, name)) {
return NULL;
}
+/* Prints table entries that weak reference the 'cur_row'. */
+static void
+cmd_show_weak_ref(struct ctl_context *ctx, const struct cmd_show_table *show,
+ const struct ovsdb_idl_row *cur_row, int level)
+{
+ const struct ovsdb_idl_row *row_wref;
+ const struct ovsdb_idl_table_class *table = show->wref_table.table;
+ const struct ovsdb_idl_column *name_column
+ = show->wref_table.name_column;
+ const struct ovsdb_idl_column *wref_column
+ = show->wref_table.wref_column;
+
+ if (!table || !name_column || !wref_column) {
+ return;
+ }
+
+ for (row_wref = ovsdb_idl_first_row(ctx->idl, table); row_wref;
+ row_wref = ovsdb_idl_next_row(row_wref)) {
+ const struct ovsdb_datum *wref_datum
+ = ovsdb_idl_read(row_wref, wref_column);
+ /* If weak reference refers to the 'cur_row', prints it. */
+ if (wref_datum->n
+ && uuid_equals(&cur_row->uuid, &wref_datum->keys[0].uuid)) {
+ const struct ovsdb_datum *name_datum
+ = ovsdb_idl_read(row_wref, name_column);
+ ds_put_char_multiple(&ctx->output, ' ', (level + 1) * 4);
+ ds_put_format(&ctx->output, "%s ", table->name);
+ ovsdb_datum_to_string(name_datum, &name_column->type, &ctx->output);
+ ds_put_char(&ctx->output, '\n');
+ }
+ }
+}
+
+/* 'shown' records the tables that has been displayed by the current
+ * command to avoid duplicated prints.
+ */
static void
cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
- int level)
+ int level, struct sset *shown)
{
- struct cmd_show_table *show = cmd_show_find_table_by_row(row);
+ const struct cmd_show_table *show = cmd_show_find_table_by_row(row);
size_t i;
ds_put_char_multiple(&ctx->output, ' ', level * 4);
}
ds_put_char(&ctx->output, '\n');
- if (!show || show->recurse) {
+ if (!show || sset_find(shown, show->table->name)) {
return;
}
- show->recurse = true;
+ sset_add(shown, show->table->name);
for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
const struct ovsdb_idl_column *column = show->columns[i];
const struct ovsdb_datum *datum;
datum = ovsdb_idl_read(row, column);
if (column->type.key.type == OVSDB_TYPE_UUID &&
column->type.key.u.uuid.refTableName) {
- struct cmd_show_table *ref_show;
+ const struct cmd_show_table *ref_show;
size_t j;
ref_show = cmd_show_find_table_by_name(
ref_show->table,
&datum->keys[j].uuid);
if (ref_row) {
- cmd_show_row(ctx, ref_row, level + 1);
+ cmd_show_row(ctx, ref_row, level + 1, shown);
}
}
continue;
} else if (ovsdb_type_is_map(&column->type) &&
column->type.value.type == OVSDB_TYPE_UUID &&
column->type.value.u.uuid.refTableName) {
- struct cmd_show_table *ref_show;
+ const struct cmd_show_table *ref_show;
size_t j;
/* Prints the key to ref'ed table name map if the ref'ed table
ds_put_char(&ctx->output, '\n');
}
}
- show->recurse = false;
+ cmd_show_weak_ref(ctx, show, row, level);
+ sset_find_and_delete_assert(shown, show->table->name);
}
static void
cmd_show(struct ctl_context *ctx)
{
const struct ovsdb_idl_row *row;
+ struct sset shown = SSET_INITIALIZER(&shown);
for (row = ovsdb_idl_first_row(ctx->idl, cmd_show_tables[0].table);
row; row = ovsdb_idl_next_row(row)) {
- cmd_show_row(ctx, row, 0);
+ cmd_show_row(ctx, row, 0, &shown);
}
+
+ ovs_assert(sset_is_empty(&shown));
+ sset_destroy(&shown);
}
\f
const struct shash_node *node;
size_t n_existing_options = *n_options_p;
- SHASH_FOR_EACH (node, ctl_get_all_commands()) {
+ SHASH_FOR_EACH (node, &all_commands) {
const struct ctl_command_syntax *p = node->data;
if (p->options[0]) {
{
const struct shash_node *node;
- SHASH_FOR_EACH (node, ctl_get_all_commands()) {
+ SHASH_FOR_EACH (node, &all_commands) {
const struct ctl_command_syntax *p = node->data;
char *options = xstrdup(p->options);
char *options_begin = options;
ctl_might_write_to_db(char **argv)
{
for (; *argv; argv++) {
- const struct ctl_command_syntax *p = shash_find_data(&all_commands, *argv);
+ const struct ctl_command_syntax *p = shash_find_data(&all_commands,
+ *argv);
if (p && p->mode == RW) {
return true;
}
* Freeing the transaction and the IDL is not strictly necessary, but it makes
* for a clean memory leak report from valgrind in the normal case. That makes
* it easier to notice real memory leaks. */
-void
+static void
ctl_exit(int status)
{
- if (the_idl_txn) {
- ovsdb_idl_txn_abort(the_idl_txn);
- ovsdb_idl_txn_destroy(the_idl_txn);
+ if (ctl_exit_func) {
+ ctl_exit_func(status);
}
- ovsdb_idl_destroy(the_idl);
exit(status);
}
-/* Command for showing overview of database contents. */
-static const struct ctl_command_syntax db_ctl_show_command[] = {
- {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
- {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
-};
-
/* Comman database commands to be registered. */
static const struct ctl_command_syntax db_ctl_commands[] = {
{"comment", 0, INT_MAX, "[ARG]...", NULL, NULL, NULL, "", RO},
{NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
};
+static void
+ctl_register_command(const struct ctl_command_syntax *command)
+{
+ shash_add_assert(&all_commands, command->name, command);
+}
+
/* Registers commands represented by 'struct ctl_command_syntax's to
* 'all_commands'. The last element of 'commands' must be an all-NULL
* element. */
const struct ctl_command_syntax *p;
for (p = commands; p->name; p++) {
- shash_add_assert(&all_commands, p->name, p);
+ ctl_register_command(p);
}
}
/* Registers the 'db_ctl_commands' to 'all_commands'. */
void
-ctl_init(const struct ctl_table_class tables_[])
+ctl_init(const struct ctl_table_class tables_[],
+ const struct cmd_show_table cmd_show_tables_[],
+ void (*ctl_exit_func_)(int status))
{
tables = tables_;
+ ctl_exit_func = ctl_exit_func_;
ctl_register_commands(db_ctl_commands);
- ctl_register_commands(db_ctl_show_command);
-}
-/* Returns 'all_commands'. */
-const struct shash *
-ctl_get_all_commands(void)
-{
- return &all_commands;
+ cmd_show_tables = cmd_show_tables_;
+ if (cmd_show_tables) {
+ static const struct ctl_command_syntax show =
+ {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO};
+ ctl_register_command(&show);
+ }
}
/* Returns the text for the database commands usage. */