#include "dynamic-string.h"
#include "ovsdb-idl.h"
#include "poll-loop.h"
+#include "svec.h"
#include "vswitchd/vswitch-idl.h"
#include "timeval.h"
#include "util.h"
static void usage(void) NO_RETURN;
static void parse_options(int argc, char *argv[]);
+static void check_vsctl_command(int argc, char *argv[]);
static void do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl);
int
{
struct ovsdb_idl *idl;
unsigned int seqno;
+ struct ds args;
+ int start, n_commands;
int trials;
+ int i;
set_program_name(argv[0]);
signal(SIGPIPE, SIG_IGN);
time_init();
vlog_init();
+ vlog_set_levels(VLM_ANY_MODULE, VLF_CONSOLE, VLL_WARN);
+ vlog_set_levels(VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
parse_options(argc, argv);
+ /* Log our arguments. This is often valuable for debugging systems. */
+ ds_init(&args);
+ for (i = 1; i < argc; i++) {
+ ds_put_format(&args, " %s", argv[i]);
+ }
+ VLOG_INFO("Called as%s", ds_cstr(&args));
+ ds_destroy(&args);
+
+ /* Do basic command syntax checking. */
+ n_commands = 0;
+ for (start = i = optind; i <= argc; i++) {
+ if (i == argc || !strcmp(argv[i], "--")) {
+ if (i > start) {
+ check_vsctl_command(i - start, &argv[start]);
+ n_commands++;
+ }
+ start = i + 1;
+ }
+ }
+ if (!n_commands) {
+ ovs_fatal(0, "missing command name (use --help for help)");
+ }
+
+ /* Now execut the commands. */
idl = ovsdb_idl_create(db, &ovsrec_idl_class);
seqno = ovsdb_idl_get_seqno(idl);
trials = 0;
enum {
OPT_DB = UCHAR_MAX + 1,
OPT_ONELINE,
+ OPT_NO_SYSLOG
};
static struct option long_options[] = {
{"db", required_argument, 0, OPT_DB},
+ {"no-syslog", no_argument, 0, OPT_NO_SYSLOG},
{"oneline", no_argument, 0, OPT_ONELINE},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
};
- char *short_options;
- short_options = xasprintf ("+%s",
- long_options_to_short_options(long_options));
for (;;) {
int c;
- c = getopt_long(argc, argv, short_options, long_options, NULL);
+ c = getopt_long(argc, argv, "+v::hV", long_options, NULL);
if (c == -1) {
break;
}
oneline = true;
break;
+ case OPT_NO_SYSLOG:
+ vlog_set_levels(VLM_vsctl, VLF_SYSLOG, VLL_WARN);
+ break;
+
case 'h':
usage();
abort();
}
}
- free(short_options);
if (!db) {
db = default_db();
{
static char *def;
if (!def) {
- def = xasprintf("%s/ovsdb-server", ovs_rundir);
+ def = xasprintf("unix:%s/ovsdb-server", ovs_rundir);
}
return def;
}
}
if (port_is_fake_bridge(port_cfg)
- && shash_add_once(&bridges, br_cfg->name, NULL)) {
+ && shash_add_once(&bridges, port_cfg->name, NULL)) {
add_bridge(info, NULL, port_cfg->name, br, *port_cfg->tag);
}
}
}
if (port_is_fake_bridge(port_cfg)
- && !shash_add_once(&bridges, br_cfg->name, NULL)) {
+ && !shash_add_once(&bridges, port_cfg->name, NULL)) {
continue;
}
iface = xmalloc(sizeof *iface);
iface->iface_cfg = iface_cfg;
iface->port = port;
+ shash_add(&info->ifaces, iface_cfg->name, iface);
}
}
}
find_iface(struct vsctl_info *info, const char *name)
{
struct vsctl_iface *iface = shash_find_data(&info->ifaces, name);
- if (!iface) {
+ if (!iface || !strcmp(name, iface->port->bridge->name)) {
ovs_fatal(0, "no interface named %s", name);
}
return iface;
for (i = 0; i < br->n_ports; i++) {
ports[i] = br->ports[i];
}
- printf("bridge has %zu ports, adding 1\n", br->n_ports);
ports[br->n_ports] = port;
ovsrec_bridge_set_ports(br, ports, br->n_ports + 1);
free(ports);
ovs_insert_bridge(ovs, br);
} else if (argc == 3) {
ovs_fatal(0, "'%s' comamnd takes exactly 1 or 3 arguments", argv[0]);
- } else if (argc >= 4) {
+ } else if (argc == 4) {
const char *parent_name = argv[2];
int vlan = atoi(argv[3]);
struct ovsrec_bridge *br;
ovsrec_port_set_interfaces(port, &iface, 1);
ovsrec_port_set_fake_bridge(port, true);
ovsrec_port_set_tag(port, &tag, 1);
+
+ bridge_insert_port(br, port);
} else {
NOT_REACHED();
}
bridge = find_bridge(&info, argv[1]);
SHASH_FOR_EACH (node, &info.ports) {
struct vsctl_port *port = node->data;
- if (port->bridge == bridge) {
+ if (port->bridge == bridge
+ || !strcmp(port->port_cfg->name, bridge->name)) {
del_port(&info, port);
}
}
free_info(&info);
}
+static void
+output_sorted(struct svec *svec, struct ds *output)
+{
+ const char *name;
+ size_t i;
+
+ svec_sort(svec);
+ SVEC_FOR_EACH (i, name, svec) {
+ ds_put_format(output, "%s\n", name);
+ }
+}
+
static void
cmd_list_br(int argc UNUSED, char *argv[] UNUSED,
const struct ovsrec_open_vswitch *ovs, struct ds *output)
{
struct shash_node *node;
struct vsctl_info info;
+ struct svec bridges;
get_info(ovs, &info);
+
+ svec_init(&bridges);
SHASH_FOR_EACH (node, &info.bridges) {
struct vsctl_bridge *br = node->data;
- ds_put_format(output, "%s\n", br->name);
+ svec_add(&bridges, br->name);
}
+ output_sorted(&bridges, output);
+ svec_destroy(&bridges);
+
free_info(&info);
}
free_info(&info);
}
+/* Returns true if 'b_prefix' (of length 'b_prefix_len') concatenated with 'b'
+ * equals 'a', false otherwise. */
+static bool
+key_matches(const char *a,
+ const char *b_prefix, size_t b_prefix_len, const char *b)
+{
+ return !strncmp(a, b_prefix, b_prefix_len) && !strcmp(a + b_prefix_len, b);
+}
+
+static void
+set_external_id(char **old_keys, char **old_values, size_t old_n,
+ char *key, char *value,
+ char ***new_keysp, char ***new_valuesp, size_t *new_np)
+{
+ char **new_keys;
+ char **new_values;
+ size_t new_n;
+ size_t i;
+
+ new_keys = xmalloc(sizeof *new_keys * (old_n + 1));
+ new_values = xmalloc(sizeof *new_values * (old_n + 1));
+ new_n = 0;
+ for (i = 0; i < old_n; i++) {
+ if (strcmp(key, old_keys[i])) {
+ new_keys[new_n] = old_keys[i];
+ new_values[new_n] = old_values[i];
+ new_n++;
+ }
+ }
+ if (value) {
+ new_keys[new_n] = key;
+ new_values[new_n] = value;
+ new_n++;
+ }
+ *new_keysp = new_keys;
+ *new_valuesp = new_values;
+ *new_np = new_n;
+}
+
+static void
+cmd_br_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_bridge *bridge;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ bridge = find_bridge(&info, argv[1]);
+ if (bridge->br_cfg) {
+ set_external_id(bridge->br_cfg->key_external_ids,
+ bridge->br_cfg->value_external_ids,
+ bridge->br_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_bridge_set_external_ids(bridge->br_cfg, keys, values, n);
+ } else {
+ char *key = xasprintf("fake-bridge-%s", argv[2]);
+ struct vsctl_port *port = shash_find_data(&info.ports, argv[1]);
+ set_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ key, argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_port_set_external_ids(port->port_cfg, keys, values, n);
+ free(key);
+ }
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+get_external_id(char **keys, char **values, size_t n,
+ const char *prefix, const char *key,
+ struct ds *output)
+{
+ size_t prefix_len = strlen(prefix);
+ struct svec svec;
+ size_t i;
+
+ svec_init(&svec);
+ for (i = 0; i < n; i++) {
+ if (!key && !strncmp(keys[i], prefix, prefix_len)) {
+ svec_add_nocopy(&svec, xasprintf("%s=%s",
+ keys[i] + prefix_len, values[i]));
+ } else if (key_matches(keys[i], prefix, prefix_len, key)) {
+ svec_add(&svec, values[i]);
+ break;
+ }
+ }
+ output_sorted(&svec, output);
+ svec_destroy(&svec);
+}
+
+static void
+cmd_br_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_bridge *bridge;
+
+ get_info(ovs, &info);
+ bridge = find_bridge(&info, argv[1]);
+ if (bridge->br_cfg) {
+ get_external_id(bridge->br_cfg->key_external_ids,
+ bridge->br_cfg->value_external_ids,
+ bridge->br_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ } else {
+ struct vsctl_port *port = shash_find_data(&info.ports, argv[1]);
+ get_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ "fake-bridge-", argc >= 3 ? argv[2] : NULL, output);
+ }
+ free_info(&info);
+}
+
+
static void
cmd_list_ports(int argc UNUSED, char *argv[],
const struct ovsrec_open_vswitch *ovs, struct ds *output)
struct vsctl_bridge *br;
struct shash_node *node;
struct vsctl_info info;
+ struct svec ports;
get_info(ovs, &info);
br = find_bridge(&info, argv[1]);
+
+ svec_init(&ports);
SHASH_FOR_EACH (node, &info.ports) {
struct vsctl_port *port = node->data;
if (strcmp(port->port_cfg->name, br->name) && br == port->bridge) {
- ds_put_format(output, "%s\n", port->port_cfg->name);
+ svec_add(&ports, port->port_cfg->name);
}
}
+ output_sorted(&ports, output);
+ svec_destroy(&ports);
+
free_info(&info);
}
free_info(&info);
}
+static void
+cmd_port_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_port *port;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ port = find_port(&info, argv[1]);
+ set_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_port_set_external_ids(port->port_cfg, keys, values, n);
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+cmd_port_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_port *port;
+
+ get_info(ovs, &info);
+ port = find_port(&info, argv[1]);
+ get_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ free_info(&info);
+}
+
static void
cmd_br_to_vlan(int argc UNUSED, char *argv[],
const struct ovsrec_open_vswitch *ovs, struct ds *output)
struct vsctl_bridge *br;
struct shash_node *node;
struct vsctl_info info;
+ struct svec ifaces;
get_info(ovs, &info);
br = find_bridge(&info, argv[1]);
+
+ svec_init(&ifaces);
SHASH_FOR_EACH (node, &info.ifaces) {
struct vsctl_iface *iface = node->data;
- if (br == iface->port->bridge) {
- ds_put_format(output, "%s\n", iface->iface_cfg->name);
+ if (strcmp(iface->iface_cfg->name, br->name)
+ && br == iface->port->bridge) {
+ svec_add(&ifaces, iface->iface_cfg->name);
}
}
+ output_sorted(&ifaces, output);
+ svec_destroy(&ifaces);
+
free_info(&info);
}
ds_put_format(output, "%s\n", iface->port->bridge->name);
free_info(&info);
}
+
+static void
+cmd_iface_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_iface *iface;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ iface = find_iface(&info, argv[1]);
+ set_external_id(iface->iface_cfg->key_external_ids,
+ iface->iface_cfg->value_external_ids,
+ iface->iface_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_interface_set_external_ids(iface->iface_cfg, keys, values, n);
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+cmd_iface_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_iface *iface;
+
+ get_info(ovs, &info);
+ iface = find_iface(&info, argv[1]);
+ get_external_id(iface->iface_cfg->key_external_ids,
+ iface->iface_cfg->value_external_ids,
+ iface->iface_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ free_info(&info);
+}
\f
+typedef void vsctl_handler_func(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *,
+ struct ds *output);
+
struct vsctl_command {
const char *name;
int min_args;
int max_args;
- void (*handler)(int argc, char *argv[],
- const struct ovsrec_open_vswitch *ovs, struct ds *output);
+ vsctl_handler_func *handler;
};
static void run_vsctl_command(int argc, char *argv[],
txn = ovsdb_idl_txn_create(idl);
output = xmalloc(argc * sizeof *output);
n_output = 0;
- for (start = i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "--")) {
+ for (start = i = 0; i <= argc; i++) {
+ if (i == argc || !strcmp(argv[i], "--")) {
if (i > start) {
ds_init(&output[n_output]);
run_vsctl_command(i - start, &argv[start], ovs,
start = i + 1;
}
}
- if (i > start) {
- ds_init(&output[n_output]);
- run_vsctl_command(i - start, &argv[start], ovs, &output[n_output++]);
- }
while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
ovsdb_idl_run(idl);
ovsdb_idl_wait(idl);
+ ovsdb_idl_txn_wait(txn);
poll_block();
}
ovsdb_idl_txn_destroy(txn);
exit(EXIT_SUCCESS);
}
-static void
-run_vsctl_command(int argc, char *argv[],
- const struct ovsrec_open_vswitch *ovs, struct ds *output)
+static vsctl_handler_func *
+get_vsctl_handler(int argc, char *argv[])
{
static const struct vsctl_command all_commands[] = {
+ /* Bridge commands. */
{"add-br", 1, 3, cmd_add_br},
{"del-br", 1, 1, cmd_del_br},
{"list-br", 0, 0, cmd_list_br},
{"br-exists", 1, 1, cmd_br_exists},
+ {"br-to-vlan", 1, 1, cmd_br_to_vlan},
+ {"br-to-parent", 1, 1, cmd_br_to_parent},
+ {"br-set-external-id", 2, 3, cmd_br_set_external_id},
+ {"br-get-external-id", 1, 2, cmd_br_get_external_id},
+
+ /* Port commands. */
{"list-ports", 1, 1, cmd_list_ports},
{"add-port", 2, 2, cmd_add_port},
{"add-bond", 4, INT_MAX, cmd_add_bond},
{"del-port", 1, 2, cmd_del_port},
{"port-to-br", 1, 1, cmd_port_to_br},
- {"br-to-vlan", 1, 1, cmd_br_to_vlan},
- {"br-to-parent", 1, 1, cmd_br_to_parent},
+ {"port-set-external-id", 2, 3, cmd_port_set_external_id},
+ {"port-get-external-id", 1, 2, cmd_port_get_external_id},
+
+ /* Interface commands. */
{"list-ifaces", 1, 1, cmd_list_ifaces},
{"iface-to-br", 1, 1, cmd_iface_to_br},
+ {"iface-set-external-id", 2, 3, cmd_iface_set_external_id},
+ {"iface-get-external-id", 1, 2, cmd_iface_get_external_id},
};
const struct vsctl_command *p;
assert(argc > 0);
- for (p = all_commands; p->name != NULL; p++) {
+ for (p = all_commands; p < &all_commands[ARRAY_SIZE(all_commands)]; p++) {
if (!strcmp(p->name, argv[0])) {
int n_arg = argc - 1;
if (n_arg < p->min_args) {
ovs_fatal(0, "'%s' command takes at most %d arguments",
p->name, p->max_args);
} else {
- p->handler(argc, argv, ovs, output);
- return;
+ return p->handler;
}
}
}
ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
}
+
+static void
+check_vsctl_command(int argc, char *argv[])
+{
+ get_vsctl_handler(argc, argv);
+}
+
+static void
+run_vsctl_command(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs, struct ds *output)
+{
+ get_vsctl_handler(argc, argv)(argc, argv, ovs, output);
+}