#include "ovsdb-idl.h"
#include "poll-loop.h"
#include "process.h"
+#include "stream.h"
#include "stream-ssl.h"
#include "svec.h"
#include "vswitchd/vswitch-idl.h"
+#include "table.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
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
/* Data modified by commands. */
struct ds output;
+ struct table *table;
};
/* --db: The database server to contact. */
/* --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[];
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[])
{
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},
{"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},
short_options = xasprintf("+%s", tmp);
free(tmp);
+ table_style.format = TF_LIST;
+
for (;;) {
int c;
break;
VLOG_OPTION_HANDLERS
+ TABLE_OPTION_HANDLERS(&table_style)
#ifdef HAVE_OPENSSL
STREAM_SSL_OPTION_HANDLERS
%s: ovs-vswitchd management utility\n\
usage: %s [OPTIONS] COMMAND [ARG...]\n\
\n\
+Open vSwitch commands:\n\
+ init initialize database, if not yet initialized\n\
+ emer-reset reset configuration to clean state\n\
+\n\
Bridge commands:\n\
add-br BRIDGE create a new bridge named BRIDGE\n\
add-br BRIDGE PARENT VLAN create new fake BRIDGE in PARENT on VLAN\n\
br-get-external-id BRIDGE KEY print value of KEY on BRIDGE\n\
br-get-external-id BRIDGE list key-value pairs on BRIDGE\n\
\n\
-Port commands:\n\
+Port commands (a bond is considered to be a single port):\n\
list-ports BRIDGE print the names of all the ports on BRIDGE\n\
add-port BRIDGE PORT add network device PORT to BRIDGE\n\
add-bond BRIDGE PORT IFACE... add bonded port PORT in BRIDGE from IFACES\n\
del-port [BRIDGE] PORT delete PORT (which may be bonded) from BRIDGE\n\
port-to-br PORT print name of bridge that contains PORT\n\
-A bond is considered to be a single port.\n\
\n\
Interface commands (a bond consists of multiple interfaces):\n\
list-ifaces BRIDGE print the names of all interfaces on BRIDGE\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\
Options:\n\
--db=DATABASE connect to DATABASE\n\
(default: %s)\n\
+ --no-wait do not wait for ovs-vswitchd to reconfigure\n\
+ -t, --timeout=SECS wait at most SECS seconds for ovs-vswitchd\n\
+ --dry-run do not commit changes to database\n\
--oneline print exactly one line of output per command\n",
program_name, program_name, default_db());
vlog_usage();
+ printf("\
+ --no-syslog equivalent to --verbose=vsctl:syslog:warn\n");
+ stream_usage("database", true, true, false);
printf("\n\
Other options:\n\
-h, --help display this help message\n\
/* Modifiable state. */
struct ds output;
+ struct table *table;
struct ovsdb_idl *idl;
struct ovsdb_idl_txn *txn;
struct ovsdb_symbol_table *symtab;
static void
pre_cmd_emer_reset(struct vsctl_context *ctx)
{
- ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_managers);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_ssl);
const struct ovsrec_sflow *sflow, *next_sflow;
/* Reset the Open_vSwitch table. */
- ovsrec_open_vswitch_set_managers(ctx->ovs, NULL, 0);
ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0);
ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL);
{
size_t i;
- ovsrec_open_vswitch_verify_managers(ovs);
ovsrec_open_vswitch_verify_manager_options(ovs);
for (i = 0; i < ovs->n_manager_options; ++i) {
static void
pre_manager(struct vsctl_context *ctx)
{
- ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_managers);
ovsdb_idl_add_column(ctx->idl, &ovsrec_open_vswitch_col_manager_options);
ovsdb_idl_add_column(ctx->idl, &ovsrec_manager_col_target);
}
/* Print the targets in sorted order for reproducibility. */
svec_init(&targets);
- /* First, add all targets found in deprecated 'managers' column. */
- for (i = 0; i < ovs->n_managers; i++) {
- svec_add(&targets, ovs->managers[i]);
- }
-
- /* Second, add all targets pointed to by 'manager_options' column. */
for (i = 0; i < ovs->n_manager_options; i++) {
svec_add(&targets, ovs->manager_options[i]->target);
}
const struct ovsrec_open_vswitch *ovs = ctx->ovs;
size_t i;
- /* Delete manager targets in deprecated 'managers' column. */
- ovsrec_open_vswitch_set_managers(ovs, NULL, 0);
-
/* Delete Manager rows pointed to by 'manager_options' column. */
for (i = 0; i < ovs->n_manager_options; i++) {
ovsrec_manager_delete(ovs->manager_options[i]);
struct ovsrec_manager **managers;
size_t i;
- /* Store in deprecated 'manager' column. */
- ovsrec_open_vswitch_set_managers(ctx->ovs, targets, n);
-
/* Insert each manager in a new row in Manager table. */
managers = xmalloc(n * sizeof *managers);
for (i = 0; i < n; 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 ovsdb_idl_row *row,
const struct ovsdb_idl_column **columns, size_t n_columns,
- struct ds *out)
+ struct table *out)
{
size_t i;
+ 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);
if (!column) {
- ds_put_format(out, "%-20s: "UUID_FMT"\n", "_uuid",
- UUID_ARGS(&row->uuid));
+ struct ovsdb_datum datum;
+ union ovsdb_atom atom;
+
+ 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);
- ds_put_format(out, "%-20s: ", column->name);
- ovsdb_datum_to_string(datum, &column->type, out);
- ds_put_char(out, '\n');
+
+ cell->json = ovsdb_datum_to_json(datum, &column->type);
+ cell->type = &column->type;
}
}
}
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(must_get_row(ctx, table, ctx->argv[i]),
columns, n_columns, out);
}
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(row, columns, n_columns, out);
+
+ next_row: ;
+ }
+}
+
static void
pre_cmd_set(struct vsctl_context *ctx)
{
ctx->options = command->options;
ds_swap(&ctx->output, &command->output);
+ ctx->table = command->table;
ctx->idl = idl;
ctx->txn = txn;
ctx->ovs = ovs;
vsctl_context_done(struct vsctl_context *ctx, struct vsctl_command *command)
{
ds_swap(&ctx->output, &command->output);
+ command->table = ctx->table;
}
static void
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);
}
}
}
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;
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');
fputs(ds_cstr(ds), stdout);
}
ds_destroy(&c->output);
+ table_destroy(c->table);
+ free(c->table);
smap_destroy(&c->options);
}
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);
}
/* 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, "--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},