xenserver: Replace customized xen-bugtool with plugin to collect qdisc info.
[openvswitch] / utilities / ovs-vsctl.c
index d70cb79c8bce2fb07674f996e5daed40dd257464..61ff5bbd16d1598655586ec87c6d9055f438df13 100644 (file)
@@ -39,6 +39,7 @@
 #include "stream-ssl.h"
 #include "svec.h"
 #include "vswitchd/vswitch-idl.h"
+#include "table.h"
 #include "timeval.h"
 #include "util.h"
 #include "vlog.h"
@@ -61,7 +62,7 @@ struct vsctl_command_syntax {
     void (*prerequisites)(struct vsctl_context *ctx);
 
     /* Does the actual work of the command and puts the command's output, if
-     * any, in ctx->output.
+     * any, in ctx->output or ctx->table.
      *
      * Alternatively, if some prerequisite of the command is not met and the
      * caller should wait for something to change and then retry, it may set
@@ -90,6 +91,7 @@ struct vsctl_command {
 
     /* Data modified by commands. */
     struct ds output;
+    struct table *table;
 };
 
 /* --db: The database server to contact. */
@@ -107,6 +109,9 @@ static bool wait_for_reload = true;
 /* --timeout: Time to wait for a connection to 'db'. */
 static int timeout;
 
+/* Format for table output. */
+static struct table_style table_style = TABLE_STYLE_DEFAULT;
+
 /* All supported commands. */
 static const struct vsctl_command_syntax all_commands[];
 
@@ -138,6 +143,11 @@ static void set_column(const struct vsctl_table_class *,
                        const struct ovsdb_idl_row *, const char *arg,
                        struct ovsdb_symbol_table *);
 
+static bool is_condition_satisfied(const struct vsctl_table_class *,
+                                   const struct ovsdb_idl_row *,
+                                   const char *arg,
+                                   struct ovsdb_symbol_table *);
+
 int
 main(int argc, char *argv[])
 {
@@ -190,7 +200,8 @@ parse_options(int argc, char *argv[])
         OPT_NO_WAIT,
         OPT_DRY_RUN,
         OPT_PEER_CA_CERT,
-        VLOG_OPTION_ENUMS
+        VLOG_OPTION_ENUMS,
+        TABLE_OPTION_ENUMS
     };
     static struct option long_options[] = {
         {"db", required_argument, 0, OPT_DB},
@@ -202,6 +213,7 @@ parse_options(int argc, char *argv[])
         {"help", no_argument, 0, 'h'},
         {"version", no_argument, 0, 'V'},
         VLOG_LONG_OPTIONS,
+        TABLE_LONG_OPTIONS,
 #ifdef HAVE_OPENSSL
         STREAM_SSL_LONG_OPTIONS
         {"peer-ca-cert", required_argument, 0, OPT_PEER_CA_CERT},
@@ -214,6 +226,8 @@ parse_options(int argc, char *argv[])
     short_options = xasprintf("+%s", tmp);
     free(tmp);
 
+    table_style.format = TF_LIST;
+
     for (;;) {
         int c;
 
@@ -259,6 +273,7 @@ parse_options(int argc, char *argv[])
             break;
 
         VLOG_OPTION_HANDLERS
+        TABLE_OPTION_HANDLERS(&table_style)
 
 #ifdef HAVE_OPENSSL
         STREAM_SSL_OPTION_HANDLERS
@@ -508,6 +523,7 @@ Switch commands:\n\
 \n\
 Database commands:\n\
   list TBL [REC]              list RECord (or all records) in TBL\n\
+  find TBL CONDITION...       list records satisfying CONDITION in TBL\n\
   get TBL REC COL[:KEY]       print values of COLumns in RECord in TBL\n\
   set TBL REC COL[:KEY]=VALUE set COLumn values in RECord in TBL\n\
   add TBL REC COL [KEY=]VALUE add (KEY=)VALUE to COLumn in RECord in TBL\n\
@@ -564,6 +580,7 @@ struct vsctl_context {
 
     /* Modifiable state. */
     struct ds output;
+    struct table *table;
     struct ovsdb_idl *idl;
     struct ovsdb_idl_txn *txn;
     struct ovsdb_symbol_table *symtab;
@@ -2650,54 +2667,157 @@ cmd_get(struct vsctl_context *ctx)
     }
 }
 
+static void
+parse_column_names(const char *column_names,
+                   const struct vsctl_table_class *table,
+                   const struct ovsdb_idl_column ***columnsp,
+                   size_t *n_columnsp)
+{
+    const struct ovsdb_idl_column **columns;
+    size_t n_columns;
+
+    if (!column_names) {
+        size_t i;
+
+        n_columns = table->class->n_columns + 1;
+        columns = xmalloc(n_columns * sizeof *columns);
+        columns[0] = NULL;
+        for (i = 0; i < table->class->n_columns; i++) {
+            columns[i + 1] = &table->class->columns[i];
+        }
+    } else {
+        char *s = xstrdup(column_names);
+        size_t allocated_columns;
+        char *save_ptr = NULL;
+        char *column_name;
+
+        columns = NULL;
+        allocated_columns = n_columns = 0;
+        for (column_name = strtok_r(s, ", ", &save_ptr); column_name;
+             column_name = strtok_r(NULL, ", ", &save_ptr)) {
+            const struct ovsdb_idl_column *column;
+
+            if (!strcasecmp(column_name, "_uuid")) {
+                column = NULL;
+            } else {
+                die_if_error(get_column(table, column_name, &column));
+            }
+            if (n_columns >= allocated_columns) {
+                columns = x2nrealloc(columns, &allocated_columns,
+                                     sizeof *columns);
+            }
+            columns[n_columns++] = column;
+        }
+        free(s);
+
+        if (!n_columns) {
+            vsctl_fatal("must specify at least one column name");
+        }
+    }
+    *columnsp = columns;
+    *n_columnsp = n_columns;
+}
+
+
+static void
+pre_list_columns(struct vsctl_context *ctx,
+                 const struct vsctl_table_class *table,
+                 const char *column_names)
+{
+    const struct ovsdb_idl_column **columns;
+    size_t n_columns;
+    size_t i;
+
+    parse_column_names(column_names, table, &columns, &n_columns);
+    for (i = 0; i < n_columns; i++) {
+        if (columns[i]) {
+            ovsdb_idl_add_column(ctx->idl, columns[i]);
+        }
+    }
+    free(columns);
+}
+
 static void
 pre_cmd_list(struct vsctl_context *ctx)
 {
+    const char *column_names = shash_find_data(&ctx->options, "--columns");
     const char *table_name = ctx->argv[1];
     const struct vsctl_table_class *table;
-    size_t i;
 
     table = pre_get_table(ctx, table_name);
-    for (i = 0; i < table->class->n_columns; i++) {
-        ovsdb_idl_add_column(ctx->idl, &table->class->columns[i]);
+    pre_list_columns(ctx, table, column_names);
+}
+
+static struct table *
+list_make_table(const struct ovsdb_idl_column **columns, size_t n_columns)
+{
+    struct table *out;
+    size_t i;
+
+    out = xmalloc(sizeof *out);
+    table_init(out);
+
+    for (i = 0; i < n_columns; i++) {
+        const struct ovsdb_idl_column *column = columns[i];
+        const char *column_name = column ? column->name : "_uuid";
+
+        table_add_column(out, "%s", column_name);
     }
+
+    return out;
 }
 
 static void
-list_record(const struct vsctl_table_class *table,
-            const struct ovsdb_idl_row *row, struct ds *out)
+list_record(const struct ovsdb_idl_row *row,
+            const struct ovsdb_idl_column **columns, size_t n_columns,
+            struct table *out)
 {
     size_t i;
 
-    ds_put_format(out, "%-20s: "UUID_FMT"\n", "_uuid",
-                  UUID_ARGS(&row->uuid));
-    for (i = 0; i < table->class->n_columns; i++) {
-        const struct ovsdb_idl_column *column = &table->class->columns[i];
-        const struct ovsdb_datum *datum;
+    table_add_row(out);
+    for (i = 0; i < n_columns; i++) {
+        const struct ovsdb_idl_column *column = columns[i];
+        struct cell *cell = table_add_cell(out);
 
-        datum = ovsdb_idl_read(row, column);
+        if (!column) {
+            struct ovsdb_datum datum;
+            union ovsdb_atom atom;
 
-        ds_put_format(out, "%-20s: ", column->name);
-        ovsdb_datum_to_string(datum, &column->type, out);
-        ds_put_char(out, '\n');
+            atom.uuid = row->uuid;
+
+            datum.keys = &atom;
+            datum.values = NULL;
+            datum.n = 1;
+
+            cell->json = ovsdb_datum_to_json(&datum, &ovsdb_type_uuid);
+            cell->type = &ovsdb_type_uuid;
+        } else {
+            const struct ovsdb_datum *datum = ovsdb_idl_read(row, column);
+
+            cell->json = ovsdb_datum_to_json(datum, &column->type);
+            cell->type = &column->type;
+        }
     }
 }
 
 static void
 cmd_list(struct vsctl_context *ctx)
 {
+    const char *column_names = shash_find_data(&ctx->options, "--columns");
+    const struct ovsdb_idl_column **columns;
     const char *table_name = ctx->argv[1];
     const struct vsctl_table_class *table;
-    struct ds *out = &ctx->output;
+    struct table *out;
+    size_t n_columns;
     int i;
 
     table = get_table(table_name);
+    parse_column_names(column_names, table, &columns, &n_columns);
+    out = ctx->table = list_make_table(columns, n_columns);
     if (ctx->argc > 2) {
         for (i = 2; i < ctx->argc; i++) {
-            if (i > 2) {
-                ds_put_char(out, '\n');
-            }
-            list_record(table, must_get_row(ctx, table, ctx->argv[i]), out);
+            list_record(must_get_row(ctx, table, ctx->argv[i]),
+                        columns, n_columns, out);
         }
     } else {
         const struct ovsdb_idl_row *row;
@@ -2706,11 +2826,54 @@ cmd_list(struct vsctl_context *ctx)
         for (row = ovsdb_idl_first_row(ctx->idl, table->class), first = true;
              row != NULL;
              row = ovsdb_idl_next_row(row), first = false) {
-            if (!first) {
-                ds_put_char(out, '\n');
+            list_record(row, columns, n_columns, out);
+        }
+    }
+    free(columns);
+}
+
+static void
+pre_cmd_find(struct vsctl_context *ctx)
+{
+    const char *column_names = shash_find_data(&ctx->options, "--columns");
+    const char *table_name = ctx->argv[1];
+    const struct vsctl_table_class *table;
+    int i;
+
+    table = pre_get_table(ctx, table_name);
+    pre_list_columns(ctx, table, column_names);
+    for (i = 2; i < ctx->argc; i++) {
+        pre_parse_column_key_value(ctx, ctx->argv[i], table);
+    }
+}
+
+static void
+cmd_find(struct vsctl_context *ctx)
+{
+    const char *column_names = shash_find_data(&ctx->options, "--columns");
+    const struct ovsdb_idl_column **columns;
+    const char *table_name = ctx->argv[1];
+    const struct vsctl_table_class *table;
+    const struct ovsdb_idl_row *row;
+    struct table *out;
+    size_t n_columns;
+
+    table = get_table(table_name);
+    parse_column_names(column_names, table, &columns, &n_columns);
+    out = ctx->table = list_make_table(columns, n_columns);
+    for (row = ovsdb_idl_first_row(ctx->idl, table->class); row;
+         row = ovsdb_idl_next_row(row)) {
+        int i;
+
+        for (i = 2; i < ctx->argc; i++) {
+            if (!is_condition_satisfied(table, row, ctx->argv[i],
+                                        ctx->symtab)) {
+                goto next_row;
             }
-            list_record(table, row, out);
         }
+        list_record(row, columns, n_columns, out);
+
+    next_row: ;
     }
 }
 
@@ -3162,6 +3325,7 @@ vsctl_context_init(struct vsctl_context *ctx, struct vsctl_command *command,
     ctx->options = command->options;
 
     ds_swap(&ctx->output, &command->output);
+    ctx->table = command->table;
     ctx->idl = idl;
     ctx->txn = txn;
     ctx->ovs = ovs;
@@ -3175,6 +3339,7 @@ static void
 vsctl_context_done(struct vsctl_context *ctx, struct vsctl_command *command)
 {
     ds_swap(&ctx->output, &command->output);
+    command->table = ctx->table;
 }
 
 static void
@@ -3192,12 +3357,14 @@ run_prerequisites(struct vsctl_command *commands, size_t n_commands,
             struct vsctl_context ctx;
 
             ds_init(&c->output);
+            c->table = NULL;
 
             vsctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
             (c->syntax->prerequisites)(&ctx);
             vsctl_context_done(&ctx, c);
 
             assert(!c->output.string);
+            assert(!c->table);
         }
     }
 }
@@ -3237,6 +3404,7 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
     symtab = ovsdb_symbol_table_create();
     for (c = commands; c < &commands[n_commands]; c++) {
         ds_init(&c->output);
+        c->table = NULL;
     }
     for (c = commands; c < &commands[n_commands]; c++) {
         struct vsctl_context ctx;
@@ -3303,7 +3471,9 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
     for (c = commands; c < &commands[n_commands]; c++) {
         struct ds *ds = &c->output;
 
-        if (oneline) {
+        if (c->table) {
+            table_print(c->table, &table_style);
+        } else if (oneline) {
             size_t j;
 
             ds_chomp(ds, '\n');
@@ -3327,6 +3497,8 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands,
             fputs(ds_cstr(ds), stdout);
         }
         ds_destroy(&c->output);
+        table_destroy(c->table);
+        free(c->table);
 
         smap_destroy(&c->options);
     }
@@ -3359,6 +3531,8 @@ try_again:
     ovsdb_symbol_table_destroy(symtab);
     for (c = commands; c < &commands[n_commands]; c++) {
         ds_destroy(&c->output);
+        table_destroy(c->table);
+        free(c->table);
     }
     free(error);
 }
@@ -3417,7 +3591,8 @@ static const struct vsctl_command_syntax all_commands[] = {
 
     /* Parameter commands. */
     {"get", 2, INT_MAX, pre_cmd_get, cmd_get, NULL, "--if-exists,--id=", RO},
-    {"list", 1, INT_MAX, pre_cmd_list, cmd_list, NULL, "", RO},
+    {"list", 1, INT_MAX, pre_cmd_list, cmd_list, NULL, "--columns=", RO},
+    {"find", 1, INT_MAX, pre_cmd_find, cmd_find, NULL, "--columns=", RO},
     {"set", 3, INT_MAX, pre_cmd_set, cmd_set, NULL, "", RW},
     {"add", 4, INT_MAX, pre_cmd_add, cmd_add, NULL, "", RW},
     {"remove", 4, INT_MAX, pre_cmd_remove, cmd_remove, NULL, "", RW},