/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "command-line.h"
#include "compiler.h"
-#include "dirs.h"
#include "dynamic-string.h"
#include "fatal-signal.h"
#include "hash.h"
static struct table_style table_style = TABLE_STYLE_DEFAULT;
static void vsctl_cmd_init(void);
-static char *default_db(void);
+
+/* The IDL we're using and the current transaction, if any.
+ * This is for use by vsctl_exit() only, to allow it to clean up.
+ * Other code should use its context arguments. */
+static struct ovsdb_idl *the_idl;
+static struct ovsdb_idl_txn *the_idl_txn;
+OVS_NO_RETURN static void vsctl_exit(int status);
+
OVS_NO_RETURN static void usage(void);
-OVS_NO_RETURN static void print_vsctl_commands(void);
-OVS_NO_RETURN static void print_vsctl_options(const struct option *options);
static void parse_options(int argc, char *argv[], struct shash *local_options);
static void run_prerequisites(struct ctl_command[], size_t n_commands,
struct ovsdb_idl *);
int
main(int argc, char *argv[])
{
- extern struct vlog_module VLM_reconnect;
struct ovsdb_idl *idl;
struct ctl_command *commands;
struct shash local_options;
set_program_name(argv[0]);
fatal_ignore_sigpipe();
vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
- vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
+ vlog_set_levels_from_string_assert("reconnect:warn");
ovsrec_init();
vsctl_cmd_init();
}
}
-static struct option *
-find_option(const char *name, struct option *options, size_t n_options)
-{
- size_t i;
-
- for (i = 0; i < n_options; i++) {
- if (!strcmp(options[i].name, name)) {
- return &options[i];
- }
- }
- return NULL;
-}
-
-static struct option *
-add_option(struct option **optionsp, size_t *n_optionsp,
- size_t *allocated_optionsp)
-{
- if (*n_optionsp >= *allocated_optionsp) {
- *optionsp = x2nrealloc(*optionsp, allocated_optionsp,
- sizeof **optionsp);
- }
- return &(*optionsp)[(*n_optionsp)++];
-}
-
static void
parse_options(int argc, char *argv[], struct shash *local_options)
{
OPT_NO_SYSLOG,
OPT_NO_WAIT,
OPT_DRY_RUN,
+ OPT_BOOTSTRAP_CA_CERT,
OPT_PEER_CA_CERT,
OPT_LOCAL,
OPT_RETRY,
VLOG_LONG_OPTIONS,
TABLE_LONG_OPTIONS,
STREAM_SSL_LONG_OPTIONS,
+ {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
{"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
{NULL, 0, NULL, 0},
};
const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
char *tmp, *short_options;
- const struct shash_node *node;
- struct option *options, *o;
+ struct option *options;
size_t allocated_options;
size_t n_options;
size_t i;
options = xmemdup(global_long_options, sizeof global_long_options);
allocated_options = ARRAY_SIZE(global_long_options);
n_options = n_global_long_options;
- SHASH_FOR_EACH (node, ctl_get_all_commands()) {
- const struct ctl_command_syntax *p = node->data;
-
- if (p->options[0]) {
- char *save_ptr = NULL;
- char *name;
- char *s;
-
- s = xstrdup(p->options);
- for (name = strtok_r(s, ",", &save_ptr); name != NULL;
- name = strtok_r(NULL, ",", &save_ptr)) {
- char *equals;
- int has_arg;
-
- ovs_assert(name[0] == '-' && name[1] == '-' && name[2]);
- name += 2;
-
- equals = strchr(name, '=');
- if (equals) {
- has_arg = required_argument;
- *equals = '\0';
- } else {
- has_arg = no_argument;
- }
-
- o = find_option(name, options, n_options);
- if (o) {
- ovs_assert(o - options >= n_global_long_options);
- ovs_assert(o->has_arg == has_arg);
- } else {
- o = add_option(&options, &n_options, &allocated_options);
- o->name = xstrdup(name);
- o->has_arg = has_arg;
- o->flag = NULL;
- o->val = OPT_LOCAL;
- }
- }
-
- free(s);
- }
- }
- o = add_option(&options, &n_options, &allocated_options);
- memset(o, 0, sizeof *o);
-
+ ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
table_style.format = TF_LIST;
for (;;) {
break;
case OPT_NO_SYSLOG:
- vlog_set_levels(&VLM_vsctl, VLF_SYSLOG, VLL_WARN);
+ vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
break;
case OPT_NO_WAIT:
usage();
case OPT_COMMANDS:
- print_vsctl_commands();
+ ctl_print_commands();
case OPT_OPTIONS:
- print_vsctl_options(global_long_options);
+ ctl_print_options(global_long_options);
case 'V':
ovs_print_version(0, 0);
stream_ssl_set_peer_ca_cert_file(optarg);
break;
+ case OPT_BOOTSTRAP_CA_CERT:
+ stream_ssl_set_ca_cert_file(optarg, true);
+ break;
+
case '?':
exit(EXIT_FAILURE);
free(short_options);
if (!db) {
- db = default_db();
+ db = ctl_default_db();
}
for (i = n_global_long_options; options[i].name; i++) {
-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, ctl_get_db_cmd_usage(), default_db());
+ program_name, program_name, ctl_get_db_cmd_usage(), ctl_default_db());
vlog_usage();
printf("\
--no-syslog equivalent to --verbose=vsctl:syslog:warn\n");
exit(EXIT_SUCCESS);
}
-/* Converts the command arguments into format that can be parsed by
- * bash completion script.
- *
- * Therein, arguments will be attached with following prefixes:
- *
- * !argument :: The argument is required
- * ?argument :: The argument is optional
- * *argument :: The argument may appear any number (0 or more) times
- * +argument :: The argument may appear one or more times
- *
- */
-static void
-print_command_arguments(const struct ctl_command_syntax *command)
-{
- /*
- * The argument string is parsed in reverse. We use a stack 'oew_stack' to
- * keep track of nested optionals. Whenever a ']' is encountered, we push
- * a bit to 'oew_stack'. The bit is set to 1 if the ']' is not nested.
- * Subsequently, we pop an entry everytime '[' is met.
- *
- * We use 'whole_word_is_optional' value to decide whether or not a ! or +
- * should be added on encountering a space: if the optional surrounds the
- * whole word then it shouldn't be, but if it is only a part of the word
- * (i.e. [key=]value), it should be.
- */
- uint32_t oew_stack = 0;
-
- const char *arguments = command->arguments;
- int length = strlen(arguments);
- if (!length) {
- return;
- }
-
- /* Output buffer, written backward from end. */
- char *output = xmalloc(2 * length);
- char *outp = output + 2 * length;
- *--outp = '\0';
-
- bool in_repeated = false;
- bool whole_word_is_optional = false;
-
- for (const char *inp = arguments + length; inp > arguments; ) {
- switch (*--inp) {
- case ']':
- oew_stack <<= 1;
- if (inp[1] == '\0' || inp[1] == ' ' || inp[1] == '.') {
- oew_stack |= 1;
- }
- break;
- case '[':
- /* Checks if the whole word is optional, and sets the
- * 'whole_word_is_optional' accordingly. */
- if ((inp == arguments || inp[-1] == ' ') && oew_stack & 1) {
- *--outp = in_repeated ? '*' : '?';
- whole_word_is_optional = true;
- } else {
- *--outp = '?';
- whole_word_is_optional = false;
- }
- oew_stack >>= 1;
- break;
- case ' ':
- if (!whole_word_is_optional) {
- *--outp = in_repeated ? '+' : '!';
- }
- *--outp = ' ';
- in_repeated = false;
- whole_word_is_optional = false;
- break;
- case '.':
- in_repeated = true;
- break;
- default:
- *--outp = *inp;
- break;
- }
- }
- if (arguments[0] != '[' && outp != output + 2 * length - 1) {
- *--outp = in_repeated ? '+' : '!';
- }
- printf("%s", outp);
- free(output);
-}
-
-static void
-print_vsctl_commands(void)
-{
- const struct shash_node *node;
-
- SHASH_FOR_EACH (node, ctl_get_all_commands()) {
- const struct ctl_command_syntax *p = node->data;
- char *options = xstrdup(p->options);
- char *options_begin = options;
- char *item;
-
- for (item = strsep(&options, ","); item != NULL;
- item = strsep(&options, ",")) {
- if (item[0] != '\0') {
- printf("[%s] ", item);
- }
- }
- printf(",%s,", p->name);
- print_command_arguments(p);
- printf("\n");
-
- free(options_begin);
- }
-
- exit(EXIT_SUCCESS);
-}
-
-static void
-print_vsctl_options(const struct option *options)
-{
- for (; options->name; options++) {
- const struct option *o = options;
-
- printf("--%s%s\n", o->name, o->has_arg ? "=ARG" : "");
- if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
- printf("-%c%s\n", o->val, o->has_arg ? " ARG" : "");
- }
- }
-
- exit(EXIT_SUCCESS);
-}
-
-static char *
-default_db(void)
-{
- static char *def;
- if (!def) {
- def = xasprintf("unix:%s/db.sock", ovs_rundir());
- }
- return def;
-}
-
\f
/* ovs-vsctl specific context. Inherits the 'struct ctl_context' as base. */
struct vsctl_context {
struct vsctl_port *port;
};
-/* Casts 'base' into 'strcut vsctl_context'. */
+/* Casts 'base' into 'struct vsctl_context'. */
static struct vsctl_context *
vsctl_context_cast(struct ctl_context *base)
{
continue;
}
br = add_bridge_to_cache(vsctl_ctx, br_cfg, br_cfg->name, NULL, 0);
- if (!br) {
- continue;
- }
for (j = 0; j < br_cfg->n_ports; j++) {
struct ovsrec_port *port_cfg = br_cfg->ports[j];
{
}
-struct cmd_show_table {
- const struct ovsdb_idl_table_class *table;
- const struct ovsdb_idl_column *name_column;
- const struct ovsdb_idl_column *columns[3];
- bool recurse;
-};
-
static struct cmd_show_table cmd_show_tables[] = {
{&ovsrec_table_open_vswitch,
NULL,
{&ovsrec_open_vswitch_col_manager_options,
&ovsrec_open_vswitch_col_bridges,
&ovsrec_open_vswitch_col_ovs_version},
- false},
+ {NULL, NULL, NULL}
+ },
{&ovsrec_table_bridge,
&ovsrec_bridge_col_name,
{&ovsrec_bridge_col_controller,
&ovsrec_bridge_col_fail_mode,
&ovsrec_bridge_col_ports},
- false},
+ {NULL, NULL, NULL}
+ },
{&ovsrec_table_port,
&ovsrec_port_col_name,
{&ovsrec_port_col_tag,
&ovsrec_port_col_trunks,
&ovsrec_port_col_interfaces},
- false},
+ {NULL, NULL, NULL}
+ },
{&ovsrec_table_interface,
&ovsrec_interface_col_name,
{&ovsrec_interface_col_type,
&ovsrec_interface_col_options,
&ovsrec_interface_col_error},
- false},
+ {NULL, NULL, NULL}
+ },
{&ovsrec_table_controller,
&ovsrec_controller_col_target,
{&ovsrec_controller_col_is_connected,
NULL,
NULL},
- false},
+ {NULL, NULL, NULL}
+ },
{&ovsrec_table_manager,
&ovsrec_manager_col_target,
{&ovsrec_manager_col_is_connected,
NULL,
NULL},
- false},
-};
-
-static void
-pre_cmd_show(struct ctl_context *ctx)
-{
- struct cmd_show_table *show;
-
- for (show = cmd_show_tables;
- show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
- show++) {
- size_t i;
-
- ovsdb_idl_add_table(ctx->idl, show->table);
- if (show->name_column) {
- ovsdb_idl_add_column(ctx->idl, show->name_column);
- }
- for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
- const struct ovsdb_idl_column *column = show->columns[i];
- if (column) {
- ovsdb_idl_add_column(ctx->idl, column);
- }
- }
- }
-}
-
-static struct cmd_show_table *
-cmd_show_find_table_by_row(const struct ovsdb_idl_row *row)
-{
- struct cmd_show_table *show;
-
- for (show = cmd_show_tables;
- show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
- show++) {
- if (show->table == row->table->class) {
- return show;
- }
- }
- return NULL;
-}
-
-static struct cmd_show_table *
-cmd_show_find_table_by_name(const char *name)
-{
- struct cmd_show_table *show;
-
- for (show = cmd_show_tables;
- show < &cmd_show_tables[ARRAY_SIZE(cmd_show_tables)];
- show++) {
- if (!strcmp(show->table->name, name)) {
- return show;
- }
- }
- return NULL;
-}
-
-static void
-cmd_show_row(struct ctl_context *ctx, const struct ovsdb_idl_row *row,
- int level)
-{
- struct cmd_show_table *show = cmd_show_find_table_by_row(row);
- size_t i;
-
- ds_put_char_multiple(&ctx->output, ' ', level * 4);
- if (show && show->name_column) {
- const struct ovsdb_datum *datum;
-
- ds_put_format(&ctx->output, "%s ", show->table->name);
- datum = ovsdb_idl_read(row, show->name_column);
- ovsdb_datum_to_string(datum, &show->name_column->type, &ctx->output);
- } else {
- ds_put_format(&ctx->output, UUID_FMT, UUID_ARGS(&row->uuid));
- }
- ds_put_char(&ctx->output, '\n');
-
- if (!show || show->recurse) {
- return;
- }
-
- show->recurse = true;
- for (i = 0; i < ARRAY_SIZE(show->columns); i++) {
- const struct ovsdb_idl_column *column = show->columns[i];
- const struct ovsdb_datum *datum;
-
- if (!column) {
- break;
- }
+ {NULL, NULL, NULL}
+ },
- 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;
- size_t j;
-
- ref_show = cmd_show_find_table_by_name(
- column->type.key.u.uuid.refTableName);
- if (ref_show) {
- for (j = 0; j < datum->n; j++) {
- const struct ovsdb_idl_row *ref_row;
-
- ref_row = ovsdb_idl_get_row_for_uuid(ctx->idl,
- ref_show->table,
- &datum->keys[j].uuid);
- if (ref_row) {
- cmd_show_row(ctx, ref_row, level + 1);
- }
- }
- continue;
- }
- }
-
- if (!ovsdb_datum_is_default(datum, &column->type)) {
- ds_put_char_multiple(&ctx->output, ' ', (level + 1) * 4);
- ds_put_format(&ctx->output, "%s: ", column->name);
- ovsdb_datum_to_string(datum, &column->type, &ctx->output);
- ds_put_char(&ctx->output, '\n');
- }
- }
- show->recurse = false;
-}
-
-static void
-cmd_show(struct ctl_context *ctx)
-{
- const struct ovsdb_idl_row *row;
-
- 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);
- }
-}
+ {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}}
+};
static void
pre_cmd_emer_reset(struct ctl_context *ctx)
/* We only want to save the "hwaddr" key from other_config. */
hwaddr = smap_get(&br->other_config, "hwaddr");
if (hwaddr) {
- struct smap smap = SMAP_INITIALIZER(&smap);
- smap_add(&smap, "hwaddr", hwaddr);
+ const struct smap smap = SMAP_CONST1(&smap, "hwaddr", hwaddr);
ovsrec_bridge_set_other_config(br, &smap);
- smap_destroy(&smap);
} else {
ovsrec_bridge_set_other_config(br, NULL);
}
vsctl_context_populate_cache(ctx);
if (!find_bridge(vsctl_ctx, ctx->argv[1], false)) {
- ctl_exit(2);
+ vsctl_exit(2);
}
}
}
for (i = 0; i < n_settings; i++) {
- set_column(get_table("Port"), &port->header_, settings[i],
- ctx->symtab);
+ ctl_set_column("Port", &port->header_, settings[i],
+ ctx->symtab);
}
bridge_insert_port((bridge->parent ? bridge->parent->br_cfg
br = br->parent;
}
- if (br && br->br_cfg) {
+ if (br->br_cfg) {
if (!br->br_cfg->auto_attach) {
struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn);
ovsrec_bridge_set_auto_attach(br->br_cfg, aa);
br = br->parent;
}
- if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ if (br->br_cfg && br->br_cfg->auto_attach &&
br->br_cfg->auto_attach->key_mappings &&
br->br_cfg->auto_attach->value_mappings) {
size_t i;
verify_auto_attach(br->br_cfg);
- if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ if (br->br_cfg && br->br_cfg->auto_attach &&
br->br_cfg->auto_attach->key_mappings &&
br->br_cfg->auto_attach->value_mappings) {
size_t i;
}
\f
-const struct ctl_table_class tables[] = {
+static const struct ctl_table_class tables[] = {
{&ovsrec_table_bridge,
{{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL},
{&ovsrec_table_flow_sample_collector_set, NULL,
}
}
+static char *
+vsctl_parent_process_info(void)
+{
+#ifdef __linux__
+ pid_t parent_pid;
+ char *procfile;
+ struct ds s;
+ FILE *f;
+
+ parent_pid = getppid();
+ procfile = xasprintf("/proc/%d/cmdline", parent_pid);
+
+ f = fopen(procfile, "r");
+ if (!f) {
+ VLOG_WARN("%s: open failed (%s)", procfile, ovs_strerror(errno));
+ free(procfile);
+ return NULL;
+ }
+ free(procfile);
+
+ ds_init(&s);
+ for (;;) {
+ int c = getc(f);
+ if (!c || c == EOF) {
+ break;
+ }
+ ds_put_char(&s, c);
+ }
+ fclose(f);
+
+ ds_put_format(&s, " (pid %d)", parent_pid);
+
+ return ds_steal_cstr(&s);
+#else
+ return NULL;
+#endif
+}
+
static void
do_vsctl(const char *args, struct ctl_command *commands, size_t n_commands,
struct ovsdb_idl *idl)
struct shash_node *node;
int64_t next_cfg = 0;
char *error = NULL;
+ char *ppid_info = NULL;
txn = the_idl_txn = ovsdb_idl_txn_create(idl);
if (dry_run) {
ovsdb_idl_txn_set_dry_run(txn);
}
- ovsdb_idl_txn_add_comment(txn, "ovs-vsctl: %s", args);
+ ppid_info = vsctl_parent_process_info();
+ if (ppid_info) {
+ ovsdb_idl_txn_add_comment(txn, "ovs-vsctl (invoked by %s): %s",
+ ppid_info, args);
+ free(ppid_info);
+ } else {
+ ovsdb_idl_txn_add_comment(txn, "ovs-vsctl: %s", args);
+ }
ovs = ovsrec_open_vswitch_first(idl);
if (!ovs) {
free(error);
}
+/* Frees the current transaction and the underlying IDL and then calls
+ * exit(status).
+ *
+ * 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. */
+static void
+vsctl_exit(int status)
+{
+ if (the_idl_txn) {
+ ovsdb_idl_txn_abort(the_idl_txn);
+ ovsdb_idl_txn_destroy(the_idl_txn);
+ }
+ ovsdb_idl_destroy(the_idl);
+ exit(status);
+}
+
/*
* Developers who add new commands to the 'struct ctl_command_syntax' must
* define the 'arguments' member of the struct. The following keywords are
static const struct ctl_command_syntax vsctl_commands[] = {
/* Open vSwitch commands. */
{"init", 0, 0, "", NULL, cmd_init, NULL, "", RW},
- {"show", 0, 0, "", pre_cmd_show, cmd_show, NULL, "", RO},
/* Bridge commands. */
{"add-br", 1, 3, "NEW-BRIDGE [PARENT] [NEW-VLAN]", pre_get_info,
static void
vsctl_cmd_init(void)
{
- ctl_init();
+ ctl_init(tables, cmd_show_tables, vsctl_exit);
ctl_register_commands(vsctl_commands);
}