X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fdb-ctl-base.c;h=e3a1de95a62b7ed074f8b363bf5de56f853b941f;hb=d0a46cb4608e632f5028034762f0adde2ce947a0;hp=64c01e6249de937305752109f53a48ba2519cde9;hpb=15ffc2028265d073d526ea08010ba3365cb16d5d;p=cascardo%2Fovs.git diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c index 64c01e624..e3a1de95a 100644 --- a/lib/db-ctl-base.c +++ b/lib/db-ctl-base.c @@ -34,17 +34,37 @@ #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 + * with an all-NULL entry. */ +static const struct ctl_table_class *tables; static struct shash all_commands = SHASH_INITIALIZER(&all_commands); static const struct ctl_table_class *get_table(const char *table_name); @@ -983,6 +1003,35 @@ cmd_list(struct ctl_context *ctx) free(columns); } +/* Finds and returns the "struct ctl_table_class *" with 'table_name' by + * searching the 'tables'. */ +static const struct ctl_table_class * +get_table(const char *table_name) +{ + const struct ctl_table_class *table; + const struct ctl_table_class *best_match = NULL; + unsigned int best_score = 0; + + for (table = tables; table->class; table++) { + unsigned int score = score_partial_match(table->class->name, + table_name); + if (score > best_score) { + best_match = table; + best_score = score; + } else if (score == best_score) { + best_match = NULL; + } + } + if (best_match) { + return best_match; + } else if (best_score) { + ctl_fatal("multiple table names match \"%s\"", table_name); + } else { + ctl_fatal("unknown table \"%s\"", table_name); + } + return NULL; +} + static void pre_cmd_find(struct ctl_context *ctx) { @@ -1029,6 +1078,60 @@ cmd_find(struct ctl_context *ctx) free(columns); } +/* Sets the column of 'row' in 'table'. */ +static void +set_column(const struct ctl_table_class *table, + const struct ovsdb_idl_row *row, const char *arg, + struct ovsdb_symbol_table *symtab) +{ + const struct ovsdb_idl_column *column; + char *key_string, *value_string; + char *error; + + error = parse_column_key_value(arg, table, &column, &key_string, + NULL, NULL, 0, &value_string); + die_if_error(error); + if (!value_string) { + ctl_fatal("%s: missing value", arg); + } + check_mutable(row, column); + + if (key_string) { + union ovsdb_atom key, value; + struct ovsdb_datum datum; + + if (column->type.value.type == OVSDB_TYPE_VOID) { + ctl_fatal("cannot specify key to set for non-map column %s", + column->name); + } + + die_if_error(ovsdb_atom_from_string(&key, &column->type.key, + key_string, symtab)); + die_if_error(ovsdb_atom_from_string(&value, &column->type.value, + value_string, symtab)); + + ovsdb_datum_init_empty(&datum); + ovsdb_datum_add_unsafe(&datum, &key, &value, &column->type); + + ovsdb_atom_destroy(&key, column->type.key.type); + ovsdb_atom_destroy(&value, column->type.value.type); + + ovsdb_datum_union(&datum, ovsdb_idl_read(row, column), + &column->type, false); + ovsdb_idl_txn_verify(row, column); + ovsdb_idl_txn_write(row, column, &datum); + } else { + struct ovsdb_datum datum; + + die_if_error(ovsdb_datum_from_string(&datum, &column->type, + value_string, symtab)); + ovsdb_idl_txn_write(row, column, &datum); + } + + free(key_string); + free(value_string); +} + static void pre_cmd_set(struct ctl_context *ctx) { @@ -1048,7 +1151,7 @@ cmd_set(struct ctl_context *ctx) 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; @@ -1502,7 +1605,7 @@ parse_command(int argc, char *argv[], struct shash *local_options, 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; @@ -1517,13 +1620,22 @@ pre_cmd_show(struct ctl_context *ctx) 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) { @@ -1533,10 +1645,10 @@ cmd_show_find_table_by_row(const struct ovsdb_idl_row *row) 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)) { @@ -1546,11 +1658,47 @@ cmd_show_find_table_by_name(const char *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); @@ -1565,11 +1713,11 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row, } 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; @@ -1581,7 +1729,7 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row, 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( @@ -1594,7 +1742,7 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row, 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; @@ -1602,7 +1750,7 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row, } 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 @@ -1647,18 +1795,23 @@ cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row, 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); } @@ -1674,7 +1827,7 @@ ctl_add_cmd_options(struct option **options_p, size_t *n_options_p, 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]) { @@ -1764,7 +1917,7 @@ ctl_print_commands(void) { 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; @@ -1820,7 +1973,8 @@ bool 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; } @@ -1838,7 +1992,7 @@ ctl_fatal(const char *format, ...) message = xvasprintf(format, args); va_end(args); - vlog_set_levels(&VLM_db_ctl_base, VLF_CONSOLE, VLL_OFF); + vlog_set_levels(&this_module, VLF_CONSOLE, VLL_OFF); VLOG_ERR("%s", message); ovs_error(0, "%s", message); ctl_exit(EXIT_FAILURE); @@ -1850,23 +2004,15 @@ ctl_fatal(const char *format, ...) * 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}, @@ -1893,6 +2039,12 @@ static const struct ctl_command_syntax db_ctl_commands[] = { {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. */ @@ -1902,23 +2054,26 @@ ctl_register_commands(const struct ctl_command_syntax *commands) 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(void) +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. */ @@ -1992,89 +2147,6 @@ ctl_context_done(struct ctl_context *ctx, invalidate_cache(ctx); } -/* Finds and returns the "struct ctl_table_class *" with 'table_name' by - * searching the 'tables'. */ -static const struct ctl_table_class * -get_table(const char *table_name) -{ - const struct ctl_table_class *table; - const struct ctl_table_class *best_match = NULL; - unsigned int best_score = 0; - - for (table = tables; table->class; table++) { - unsigned int score = score_partial_match(table->class->name, - table_name); - if (score > best_score) { - best_match = table; - best_score = score; - } else if (score == best_score) { - best_match = NULL; - } - } - if (best_match) { - return best_match; - } else if (best_score) { - ctl_fatal("multiple table names match \"%s\"", table_name); - } else { - ctl_fatal("unknown table \"%s\"", table_name); - } - return NULL; -} - -/* Sets the column of 'row' in 'table'. */ -static void -set_column(const struct ctl_table_class *table, - const struct ovsdb_idl_row *row, const char *arg, - struct ovsdb_symbol_table *symtab) -{ - const struct ovsdb_idl_column *column; - char *key_string, *value_string; - char *error; - - error = parse_column_key_value(arg, table, &column, &key_string, - NULL, NULL, 0, &value_string); - die_if_error(error); - if (!value_string) { - ctl_fatal("%s: missing value", arg); - } - check_mutable(row, column); - - if (key_string) { - union ovsdb_atom key, value; - struct ovsdb_datum datum; - - if (column->type.value.type == OVSDB_TYPE_VOID) { - ctl_fatal("cannot specify key to set for non-map column %s", - column->name); - } - - die_if_error(ovsdb_atom_from_string(&key, &column->type.key, - key_string, symtab)); - die_if_error(ovsdb_atom_from_string(&value, &column->type.value, - value_string, symtab)); - - ovsdb_datum_init_empty(&datum); - ovsdb_datum_add_unsafe(&datum, &key, &value, &column->type); - - ovsdb_atom_destroy(&key, column->type.key.type); - ovsdb_atom_destroy(&value, column->type.value.type); - - ovsdb_datum_union(&datum, ovsdb_idl_read(row, column), - &column->type, false); - ovsdb_idl_txn_verify(row, column); - ovsdb_idl_txn_write(row, column, &datum); - } else { - struct ovsdb_datum datum; - - die_if_error(ovsdb_datum_from_string(&datum, &column->type, - value_string, symtab)); - ovsdb_idl_txn_write(row, column, &datum); - } - - free(key_string); - free(value_string); -} - void ctl_set_column(const char *table_name, const struct ovsdb_idl_row *row, const char *arg, struct ovsdb_symbol_table *symtab)