db-ctl-base: Allow print rows that weak reference to table in
[cascardo/ovs.git] / lib / db-ctl-base.c
index e3c0373..b018bad 100644 (file)
@@ -34,6 +34,7 @@
 #include "ovsdb-idl.h"
 #include "ovsdb-idl-provider.h"
 #include "shash.h"
+#include "sset.h"
 #include "string.h"
 #include "table.h"
 #include "util.h"
@@ -51,7 +52,7 @@ VLOG_DEFINE_THIS_MODULE(db_ctl_base);
  * when ctl_init() is called.
  *
  * */
-extern struct cmd_show_table cmd_show_tables[];
+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
@@ -1604,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;
@@ -1619,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) {
@@ -1635,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)) {
@@ -1648,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);
@@ -1667,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;
@@ -1683,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(
@@ -1696,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;
@@ -1704,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
@@ -1749,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);
 }
 
 \f
@@ -1953,7 +2004,7 @@ 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 (ctl_exit_func) {
@@ -2005,9 +2056,11 @@ ctl_register_commands(const struct ctl_command_syntax *commands)
 /* Registers the 'db_ctl_commands' to 'all_commands'. */
 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_;
+    cmd_show_tables = cmd_show_tables_;
     ctl_exit_func = ctl_exit_func_;
     ctl_register_commands(db_ctl_commands);
 }