X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-vsctl.c;h=0527885b35a77d637ef5eb9d20c1a54dc31757b3;hb=4e0abe6e1a3bc49b11870a90dc5ebffa003e00a0;hp=d8aeb53d8bcb0036a1e6c9c9c09bb7b2bddaa677;hpb=f5cd6874f1e4efcd1d513a294bf7709933959b97;p=sliver-openvswitch.git diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index d8aeb53d8..0527885b3 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ #include -#include #include #include #include @@ -40,6 +39,7 @@ #include "process.h" #include "stream.h" #include "stream-ssl.h" +#include "smap.h" #include "sset.h" #include "svec.h" #include "lib/vswitch-idl.h" @@ -114,11 +114,21 @@ static bool wait_for_reload = true; /* --timeout: Time to wait for a connection to 'db'. */ static int timeout; +/* --retry: If true, ovs-vsctl will retry connecting to the database forever. + * If false and --db says to use an active connection method (e.g. "unix:", + * "tcp:", "ssl:"), then ovs-vsctl will try to connect once and exit with an + * error if the database server cannot be contacted (e.g. ovsdb-server is not + * running). + * + * Regardless of this setting, --timeout always limits how long ovs-vsctl will + * wait. */ +static bool retry; + /* Format for table output. */ static struct table_style table_style = TABLE_STYLE_DEFAULT; /* All supported commands. */ -static const struct vsctl_command_syntax all_commands[]; +static const struct vsctl_command_syntax *get_all_commands(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. @@ -130,12 +140,14 @@ static void vsctl_exit(int status) NO_RETURN; static void vsctl_fatal(const char *, ...) PRINTF_FORMAT(1, 2) NO_RETURN; static char *default_db(void); static void usage(void) NO_RETURN; -static void parse_options(int argc, char *argv[]); +static void parse_options(int argc, char *argv[], struct shash *local_options); static bool might_write_to_db(char **argv); static struct vsctl_command *parse_commands(int argc, char *argv[], + struct shash *local_options, size_t *n_commandsp); -static void parse_command(int argc, char *argv[], struct vsctl_command *); +static void parse_command(int argc, char *argv[], struct shash *local_options, + struct vsctl_command *); static const struct vsctl_command_syntax *find_command(const char *name); static void run_prerequisites(struct vsctl_command[], size_t n_commands, struct ovsdb_idl *); @@ -158,6 +170,7 @@ main(int argc, char *argv[]) extern struct vlog_module VLM_reconnect; struct ovsdb_idl *idl; struct vsctl_command *commands; + struct shash local_options; unsigned int seqno; size_t n_commands; char *args; @@ -173,15 +186,17 @@ main(int argc, char *argv[]) VLOG(might_write_to_db(argv) ? VLL_INFO : VLL_DBG, "Called as %s", args); /* Parse command line. */ - parse_options(argc, argv); - commands = parse_commands(argc - optind, argv + optind, &n_commands); + shash_init(&local_options); + parse_options(argc, argv, &local_options); + commands = parse_commands(argc - optind, argv + optind, &local_options, + &n_commands); if (timeout) { time_alarm(timeout); } /* Initialize IDL. */ - idl = the_idl = ovsdb_idl_create(db, &ovsrec_idl_class, false); + idl = the_idl = ovsdb_idl_create(db, &ovsrec_idl_class, false, retry); run_prerequisites(commands, n_commands, idl); /* Execute the commands. @@ -194,6 +209,11 @@ main(int argc, char *argv[]) seqno = ovsdb_idl_get_seqno(idl); for (;;) { ovsdb_idl_run(idl); + if (!ovsdb_idl_is_alive(idl)) { + int retval = ovsdb_idl_get_last_error(idl); + vsctl_fatal("%s: database connection failed (%s)", + db, ovs_retval_to_string(retval)); + } if (seqno != ovsdb_idl_get_seqno(idl)) { seqno = ovsdb_idl_get_seqno(idl); @@ -207,8 +227,32 @@ main(int argc, char *argv[]) } } +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[]) +parse_options(int argc, char *argv[], struct shash *local_options) { enum { OPT_DB = UCHAR_MAX + 1, @@ -217,16 +261,19 @@ parse_options(int argc, char *argv[]) OPT_NO_WAIT, OPT_DRY_RUN, OPT_PEER_CA_CERT, + OPT_LOCAL, + OPT_RETRY, VLOG_OPTION_ENUMS, TABLE_OPTION_ENUMS }; - static struct option long_options[] = { + static const struct option global_long_options[] = { {"db", required_argument, NULL, OPT_DB}, {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, {"no-wait", no_argument, NULL, OPT_NO_WAIT}, {"dry-run", no_argument, NULL, OPT_DRY_RUN}, {"oneline", no_argument, NULL, OPT_ONELINE}, {"timeout", required_argument, NULL, 't'}, + {"retry", no_argument, NULL, OPT_RETRY}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, VLOG_LONG_OPTIONS, @@ -235,18 +282,75 @@ parse_options(int argc, char *argv[]) {"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; - tmp = long_options_to_short_options(long_options); + const struct vsctl_command_syntax *p; + struct option *options, *o; + size_t allocated_options; + size_t n_options; + size_t i; + + tmp = long_options_to_short_options(global_long_options); short_options = xasprintf("+%s", tmp); free(tmp); + /* We want to parse both global and command-specific options here, but + * getopt_long() isn't too convenient for the job. We copy our global + * options into a dynamic array, then append all of the command-specific + * options. */ + options = xmemdup(global_long_options, sizeof global_long_options); + allocated_options = ARRAY_SIZE(global_long_options); + n_options = n_global_long_options; + for (p = get_all_commands(); p->name; p++) { + 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); + table_style.format = TF_LIST; for (;;) { + int idx; int c; - c = getopt_long(argc, argv, short_options, long_options, NULL); + c = getopt_long(argc, argv, short_options, options, &idx); if (c == -1) { break; } @@ -272,6 +376,16 @@ parse_options(int argc, char *argv[]) dry_run = true; break; + case OPT_LOCAL: + if (shash_find(local_options, options[idx].name)) { + vsctl_fatal("'%s' option specified multiple times", + options[idx].name); + } + shash_add_nocopy(local_options, + xasprintf("--%s", options[idx].name), + optarg ? xstrdup(optarg) : NULL); + break; + case 'h': usage(); @@ -287,6 +401,10 @@ parse_options(int argc, char *argv[]) } break; + case OPT_RETRY: + retry = true; + break; + VLOG_OPTION_HANDLERS TABLE_OPTION_HANDLERS(&table_style) @@ -308,10 +426,16 @@ parse_options(int argc, char *argv[]) if (!db) { db = default_db(); } + + for (i = n_global_long_options; options[i].name; i++) { + free(CONST_CAST(char *, options[i].name)); + } + free(options); } static struct vsctl_command * -parse_commands(int argc, char *argv[], size_t *n_commandsp) +parse_commands(int argc, char *argv[], struct shash *local_options, + size_t *n_commandsp) { struct vsctl_command *commands; size_t n_commands, allocated_commands; @@ -332,8 +456,10 @@ parse_commands(int argc, char *argv[], size_t *n_commandsp) shash_moved(&c->options); } } - parse_command(i - start, &argv[start], + parse_command(i - start, &argv[start], local_options, &commands[n_commands++]); + } else if (!shash_is_empty(local_options)) { + vsctl_fatal("missing command name (use --help for help)"); } start = i + 1; } @@ -346,7 +472,8 @@ parse_commands(int argc, char *argv[], size_t *n_commandsp) } static void -parse_command(int argc, char *argv[], struct vsctl_command *command) +parse_command(int argc, char *argv[], struct shash *local_options, + struct vsctl_command *command) { const struct vsctl_command_syntax *p; struct shash_node *node; @@ -354,6 +481,7 @@ parse_command(int argc, char *argv[], struct vsctl_command *command) int i; shash_init(&command->options); + shash_swap(local_options, &command->options); for (i = 0; i < argc; i++) { const char *option = argv[i]; const char *equals; @@ -378,7 +506,7 @@ parse_command(int argc, char *argv[], struct vsctl_command *command) shash_add_nocopy(&command->options, key, value); } if (i == argc) { - vsctl_fatal("missing command name"); + vsctl_fatal("missing command name (use --help for help)"); } p = find_command(argv[i]); @@ -440,7 +568,7 @@ find_command(const char *name) if (shash_is_empty(&commands)) { const struct vsctl_command_syntax *p; - for (p = all_commands; p->name; p++) { + for (p = get_all_commands(); p->name; p++) { shash_add_assert(&commands, p->name, p); } } @@ -555,6 +683,7 @@ Options:\n\ --db=DATABASE connect to DATABASE\n\ (default: %s)\n\ --no-wait do not wait for ovs-vswitchd to reconfigure\n\ + --retry keep trying to connect to server forever\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", @@ -737,8 +866,8 @@ ovs_delete_bridge(const struct ovsrec_open_vswitch *ovs, static void del_cached_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br) { - assert(list_is_empty(&br->ports)); - assert(hmap_is_empty(&br->children)); + ovs_assert(list_is_empty(&br->ports)); + ovs_assert(hmap_is_empty(&br->children)); if (br->parent) { hmap_remove(&br->parent->children, &br->children_node); } @@ -804,7 +933,7 @@ add_port_to_cache(struct vsctl_context *ctx, struct vsctl_bridge *parent, static void del_cached_port(struct vsctl_context *ctx, struct vsctl_port *port) { - assert(list_is_empty(&port->ifaces)); + ovs_assert(list_is_empty(&port->ifaces)); list_remove(&port->ports_node); shash_find_and_delete(&ctx->ports, port->port_cfg->name); ovsrec_port_delete(port->port_cfg); @@ -1025,7 +1154,7 @@ find_bridge(struct vsctl_context *ctx, const char *name, bool must_exist) { struct vsctl_bridge *br; - assert(ctx->cache_valid); + ovs_assert(ctx->cache_valid); br = shash_find_data(&ctx->bridges, name); if (must_exist && !br) { @@ -1050,7 +1179,7 @@ find_port(struct vsctl_context *ctx, const char *name, bool must_exist) { struct vsctl_port *port; - assert(ctx->cache_valid); + ovs_assert(ctx->cache_valid); port = shash_find_data(&ctx->ports, name); if (port && !strcmp(name, port->bridge->name)) { @@ -1068,7 +1197,7 @@ find_iface(struct vsctl_context *ctx, const char *name, bool must_exist) { struct vsctl_iface *iface; - assert(ctx->cache_valid); + ovs_assert(ctx->cache_valid); iface = shash_find_data(&ctx->ifaces, name); if (iface && !strcmp(name, iface->port->bridge->name)) { @@ -1324,6 +1453,7 @@ pre_cmd_emer_reset(struct vsctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_mirrors); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_netflow); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_sflow); + ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ipfix); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_flood_vlans); ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_other_config); @@ -1348,41 +1478,38 @@ cmd_emer_reset(struct vsctl_context *ctx) const struct ovsrec_netflow *nf, *next_nf; const struct ovsrec_ssl *ssl, *next_ssl; const struct ovsrec_sflow *sflow, *next_sflow; + const struct ovsrec_ipfix *ipfix, *next_ipfix; + const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset; /* Reset the Open_vSwitch table. */ ovsrec_open_vswitch_set_manager_options(ctx->ovs, NULL, 0); ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL); OVSREC_BRIDGE_FOR_EACH (br, idl) { - int i; - char *hw_key = "hwaddr"; - char *hw_val = NULL; + const char *hwaddr; ovsrec_bridge_set_controller(br, NULL, 0); ovsrec_bridge_set_fail_mode(br, NULL); ovsrec_bridge_set_mirrors(br, NULL, 0); ovsrec_bridge_set_netflow(br, NULL); ovsrec_bridge_set_sflow(br, NULL); + ovsrec_bridge_set_ipfix(br, NULL); ovsrec_bridge_set_flood_vlans(br, NULL, 0); /* We only want to save the "hwaddr" key from other_config. */ - for (i=0; i < br->n_other_config; i++) { - if (!strcmp(br->key_other_config[i], hw_key)) { - hw_val = br->value_other_config[i]; - break; - } - } - if (hw_val) { - char *val = xstrdup(hw_val); - ovsrec_bridge_set_other_config(br, &hw_key, &val, 1); - free(val); + hwaddr = smap_get(&br->other_config, "hwaddr"); + if (hwaddr) { + struct smap smap = SMAP_INITIALIZER(&smap); + smap_add(&smap, "hwaddr", hwaddr); + ovsrec_bridge_set_other_config(br, &smap); + smap_destroy(&smap); } else { - ovsrec_bridge_set_other_config(br, NULL, NULL, 0); + ovsrec_bridge_set_other_config(br, NULL); } } OVSREC_PORT_FOR_EACH (port, idl) { - ovsrec_port_set_other_config(port, NULL, NULL, 0); + ovsrec_port_set_other_config(port, NULL); } OVSREC_INTERFACE_FOR_EACH (iface, idl) { @@ -1416,6 +1543,14 @@ cmd_emer_reset(struct vsctl_context *ctx) ovsrec_sflow_delete(sflow); } + OVSREC_IPFIX_FOR_EACH_SAFE (ipfix, next_ipfix, idl) { + ovsrec_ipfix_delete(ipfix); + } + + OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, idl) { + ovsrec_flow_sample_collector_set_delete(fscset); + } + vsctl_context_invalidate_cache(ctx); } @@ -1545,6 +1680,7 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br) { struct vsctl_bridge *child, *next_child; struct vsctl_port *port, *next_port; + const struct ovsrec_flow_sample_collector_set *fscset, *next_fscset; HMAP_FOR_EACH_SAFE (child, next_child, children_node, &br->children) { del_bridge(ctx, child); @@ -1554,6 +1690,13 @@ del_bridge(struct vsctl_context *ctx, struct vsctl_bridge *br) del_port(ctx, port); } + OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH_SAFE (fscset, next_fscset, + ctx->idl) { + if (fscset->bridge == br->br_cfg) { + ovsrec_flow_sample_collector_set_delete(fscset); + } + } + del_cached_bridge(ctx, br); } @@ -1587,13 +1730,23 @@ cmd_list_br(struct vsctl_context *ctx) { struct shash_node *node; struct svec bridges; + bool real = shash_find(&ctx->options, "--real"); + bool fake = shash_find(&ctx->options, "--fake"); + + /* If neither fake nor real were requested, return both. */ + if (!real && !fake) { + real = fake = true; + } vsctl_context_populate_cache(ctx); svec_init(&bridges); SHASH_FOR_EACH (node, &ctx->bridges) { struct vsctl_bridge *br = node->data; - svec_add(&bridges, br->name); + + if (br->parent ? fake : real) { + svec_add(&bridges, br->name); + } } output_sorted(&bridges, &ctx->output); svec_destroy(&bridges); @@ -1608,43 +1761,17 @@ cmd_br_exists(struct vsctl_context *ctx) } } -/* 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) +set_external_id(struct smap *old, struct smap *new, + char *key, char *value) { - char **new_keys; - char **new_values; - size_t new_n; - size_t i; + smap_clone(new, old); - 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++; + smap_replace(new, key, value); + } else { + smap_remove(new, key); } - *new_keysp = new_keys; - *new_valuesp = new_values; - *new_np = new_n; } static void @@ -1659,56 +1786,54 @@ static void cmd_br_set_external_id(struct vsctl_context *ctx) { struct vsctl_bridge *bridge; - char **keys, **values; - size_t n; + struct smap new; vsctl_context_populate_cache(ctx); bridge = find_bridge(ctx, ctx->argv[1], true); 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, - ctx->argv[2], ctx->argc >= 4 ? ctx->argv[3] : NULL, - &keys, &values, &n); + + set_external_id(&bridge->br_cfg->external_ids, &new, ctx->argv[2], + ctx->argc >= 4 ? ctx->argv[3] : NULL); ovsrec_bridge_verify_external_ids(bridge->br_cfg); - ovsrec_bridge_set_external_ids(bridge->br_cfg, keys, values, n); + ovsrec_bridge_set_external_ids(bridge->br_cfg, &new); } else { char *key = xasprintf("fake-bridge-%s", ctx->argv[2]); struct vsctl_port *port = shash_find_data(&ctx->ports, ctx->argv[1]); - set_external_id(port->port_cfg->key_external_ids, - port->port_cfg->value_external_ids, - port->port_cfg->n_external_ids, - key, ctx->argc >= 4 ? ctx->argv[3] : NULL, - &keys, &values, &n); + set_external_id(&port->port_cfg->external_ids, &new, + key, ctx->argc >= 4 ? ctx->argv[3] : NULL); ovsrec_port_verify_external_ids(port->port_cfg); - ovsrec_port_set_external_ids(port->port_cfg, keys, values, n); + ovsrec_port_set_external_ids(port->port_cfg, &new); free(key); } - free(keys); - free(values); + smap_destroy(&new); } static void -get_external_id(char **keys, char **values, size_t n, - const char *prefix, const char *key, +get_external_id(struct smap *smap, const char *prefix, const char *key, struct ds *output) { - size_t prefix_len = strlen(prefix); - struct svec svec; - size_t i; + if (key) { + char *prefix_key = xasprintf("%s%s", prefix, key); + const char *value = smap_get(smap, prefix_key); - 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 && key_matches(keys[i], prefix, prefix_len, key)) { - svec_add(&svec, values[i]); - break; + if (value) { + ds_put_format(output, "%s\n", value); + } + free(prefix_key); + } else { + const struct smap_node **sorted = smap_sort(smap); + size_t prefix_len = strlen(prefix); + size_t i; + + for (i = 0; i < smap_count(smap); i++) { + const struct smap_node *node = sorted[i]; + if (!strncmp(node->key, prefix, prefix_len)) { + ds_put_format(output, "%s=%s\n", node->key + prefix_len, + node->value); + } } + free(sorted); } - output_sorted(&svec, output); - svec_destroy(&svec); } static void @@ -1727,18 +1852,13 @@ cmd_br_get_external_id(struct vsctl_context *ctx) bridge = find_bridge(ctx, ctx->argv[1], true); if (bridge->br_cfg) { ovsrec_bridge_verify_external_ids(bridge->br_cfg); - get_external_id(bridge->br_cfg->key_external_ids, - bridge->br_cfg->value_external_ids, - bridge->br_cfg->n_external_ids, - "", ctx->argc >= 3 ? ctx->argv[2] : NULL, - &ctx->output); + get_external_id(&bridge->br_cfg->external_ids, "", + ctx->argc >= 3 ? ctx->argv[2] : NULL, &ctx->output); } else { struct vsctl_port *port = shash_find_data(&ctx->ports, ctx->argv[1]); ovsrec_port_verify_external_ids(port->port_cfg); - get_external_id(port->port_cfg->key_external_ids, - port->port_cfg->value_external_ids, - port->port_cfg->n_external_ids, - "fake-bridge-", ctx->argc >= 3 ? ctx->argv[2] : NULL, &ctx->output); + get_external_id(&port->port_cfg->external_ids, "fake-bridge-", + ctx->argc >= 3 ? ctx->argv[2] : NULL, &ctx->output); } } @@ -1896,13 +2016,20 @@ cmd_del_port(struct vsctl_context *ctx) { bool must_exist = !shash_find(&ctx->options, "--if-exists"); bool with_iface = shash_find(&ctx->options, "--with-iface") != NULL; + const char *target = ctx->argv[ctx->argc - 1]; struct vsctl_port *port; vsctl_context_populate_cache(ctx); - if (!with_iface) { - port = find_port(ctx, ctx->argv[ctx->argc - 1], must_exist); + if (find_bridge(ctx, target, false)) { + if (must_exist) { + vsctl_fatal("cannot delete port %s because it is the local port " + "for bridge %s (deleting this port requires deleting " + "the entire bridge)", target, target); + } + port = NULL; + } else if (!with_iface) { + port = find_port(ctx, target, must_exist); } else { - const char *target = ctx->argv[ctx->argc - 1]; struct vsctl_iface *iface; port = find_port(ctx, target, false); @@ -2364,7 +2491,8 @@ struct vsctl_table_class { static const struct vsctl_table_class tables[] = { {&ovsrec_table_bridge, {{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL}, - {NULL, NULL, NULL}}}, + {&ovsrec_table_flow_sample_collector_set, NULL, + &ovsrec_flow_sample_collector_set_col_bridge}}}, {&ovsrec_table_controller, {{&ovsrec_table_bridge, @@ -2418,6 +2546,17 @@ static const struct vsctl_table_class tables[] = { {{&ovsrec_table_flow_table, &ovsrec_flow_table_col_name, NULL}, {NULL, NULL, NULL}}}, + {&ovsrec_table_ipfix, + {{&ovsrec_table_bridge, + &ovsrec_bridge_col_name, + &ovsrec_bridge_col_ipfix}, + {&ovsrec_table_flow_sample_collector_set, NULL, + &ovsrec_flow_sample_collector_set_col_ipfix}}}, + + {&ovsrec_table_flow_sample_collector_set, + {{NULL, NULL, NULL}, + {NULL, NULL, NULL}}}, + {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} }; @@ -2567,7 +2706,8 @@ get_row_by_id(struct vsctl_context *ctx, const struct vsctl_table_class *table, static const struct ovsdb_idl_row * get_row (struct vsctl_context *ctx, - const struct vsctl_table_class *table, const char *record_id) + const struct vsctl_table_class *table, const char *record_id, + bool must_exist) { const struct ovsdb_idl_row *row; struct uuid uuid; @@ -2584,15 +2724,7 @@ get_row (struct vsctl_context *ctx, } } } - return row; -} - -static const struct ovsdb_idl_row * -must_get_row(struct vsctl_context *ctx, - const struct vsctl_table_class *table, const char *record_id) -{ - const struct ovsdb_idl_row *row = get_row(ctx, table, record_id); - if (!row) { + if (must_exist && !row) { vsctl_fatal("no row \"%s\" in table %s", record_id, table->class->name); } @@ -2715,7 +2847,7 @@ parse_column_key_value(const char *arg, char *column_name; char *error; - assert(!(operatorp && !valuep)); + ovs_assert(!(operatorp && !valuep)); *keyp = NULL; if (valuep) { *valuep = NULL; @@ -2801,7 +2933,7 @@ error: return error; } -static void +static const struct ovsdb_idl_column * pre_parse_column_key_value(struct vsctl_context *ctx, const char *arg, const struct vsctl_table_class *table) @@ -2818,6 +2950,18 @@ pre_parse_column_key_value(struct vsctl_context *ctx, pre_get_column(ctx, table, column_name, &column); free(column_name); + + return column; +} + +static void +check_mutable(const struct vsctl_table_class *table, + const struct ovsdb_idl_column *column) +{ + if (!column->mutable) { + vsctl_fatal("cannot modify read-only column %s in table %s", + column->name, table->class->name); + } } static void @@ -2852,7 +2996,7 @@ static void cmd_get(struct vsctl_context *ctx) { const char *id = shash_find_data(&ctx->options, "--id"); - bool if_exists = shash_find(&ctx->options, "--if-exists"); + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const char *table_name = ctx->argv[1]; const char *record_id = ctx->argv[2]; const struct vsctl_table_class *table; @@ -2860,8 +3004,16 @@ cmd_get(struct vsctl_context *ctx) struct ds *out = &ctx->output; int i; + if (id && !must_exist) { + vsctl_fatal("--if-exists and --id may not be specified together"); + } + table = get_table(table_name); - row = must_get_row(ctx, table, record_id); + row = get_row(ctx, table, record_id, must_exist); + if (!row) { + return; + } + if (id) { struct ovsdb_symbol *symbol; bool new; @@ -2913,7 +3065,7 @@ cmd_get(struct vsctl_context *ctx) idx = ovsdb_datum_find_key(datum, &key, column->type.key.type); if (idx == UINT_MAX) { - if (!if_exists) { + if (must_exist) { vsctl_fatal("no key \"%s\" in %s record \"%s\" column %s", key_string, table->class->name, record_id, column->name); @@ -3039,6 +3191,10 @@ list_record(const struct ovsdb_idl_row *row, { size_t i; + if (!row) { + return; + } + table_add_row(out); for (i = 0; i < n_columns; i++) { const struct ovsdb_idl_column *column = columns[i]; @@ -3069,6 +3225,7 @@ static void cmd_list(struct vsctl_context *ctx) { const char *column_names = shash_find_data(&ctx->options, "--columns"); + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const struct ovsdb_idl_column **columns; const char *table_name = ctx->argv[1]; const struct vsctl_table_class *table; @@ -3081,7 +3238,7 @@ cmd_list(struct vsctl_context *ctx) out = ctx->table = list_make_table(columns, n_columns); if (ctx->argc > 2) { for (i = 2; i < ctx->argc; i++) { - list_record(must_get_row(ctx, table, ctx->argv[i]), + list_record(get_row(ctx, table, ctx->argv[i], must_exist), columns, n_columns, out); } } else { @@ -3150,7 +3307,10 @@ pre_cmd_set(struct vsctl_context *ctx) table = pre_get_table(ctx, table_name); for (i = 3; i < ctx->argc; i++) { - pre_parse_column_key_value(ctx, ctx->argv[i], table); + const struct ovsdb_idl_column *column; + + column = pre_parse_column_key_value(ctx, ctx->argv[i], table); + check_mutable(table, column); } } @@ -3208,6 +3368,7 @@ set_column(const struct vsctl_table_class *table, static void cmd_set(struct vsctl_context *ctx) { + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const char *table_name = ctx->argv[1]; const char *record_id = ctx->argv[2]; const struct vsctl_table_class *table; @@ -3215,7 +3376,11 @@ cmd_set(struct vsctl_context *ctx) int i; table = get_table(table_name); - row = must_get_row(ctx, table, record_id); + row = get_row(ctx, table, record_id, must_exist); + if (!row) { + return; + } + for (i = 3; i < ctx->argc; i++) { set_column(table, row, ctx->argv[i], ctx->symtab); } @@ -3233,11 +3398,13 @@ pre_cmd_add(struct vsctl_context *ctx) table = pre_get_table(ctx, table_name); pre_get_column(ctx, table, column_name, &column); + check_mutable(table, column); } static void cmd_add(struct vsctl_context *ctx) { + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const char *table_name = ctx->argv[1]; const char *record_id = ctx->argv[2]; const char *column_name = ctx->argv[3]; @@ -3249,8 +3416,11 @@ cmd_add(struct vsctl_context *ctx) int i; table = get_table(table_name); - row = must_get_row(ctx, table, record_id); die_if_error(get_column(table, column_name, &column)); + row = get_row(ctx, table, record_id, must_exist); + if (!row) { + return; + } type = &column->type; ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type); @@ -3289,11 +3459,13 @@ pre_cmd_remove(struct vsctl_context *ctx) table = pre_get_table(ctx, table_name); pre_get_column(ctx, table, column_name, &column); + check_mutable(table, column); } static void cmd_remove(struct vsctl_context *ctx) { + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const char *table_name = ctx->argv[1]; const char *record_id = ctx->argv[2]; const char *column_name = ctx->argv[3]; @@ -3305,8 +3477,11 @@ cmd_remove(struct vsctl_context *ctx) int i; table = get_table(table_name); - row = must_get_row(ctx, table, record_id); die_if_error(get_column(table, column_name, &column)); + row = get_row(ctx, table, record_id, must_exist); + if (!row) { + return; + } type = &column->type; ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type); @@ -3354,12 +3529,14 @@ pre_cmd_clear(struct vsctl_context *ctx) const struct ovsdb_idl_column *column; pre_get_column(ctx, table, ctx->argv[i], &column); + check_mutable(table, column); } } static void cmd_clear(struct vsctl_context *ctx) { + bool must_exist = !shash_find(&ctx->options, "--if-exists"); const char *table_name = ctx->argv[1]; const char *record_id = ctx->argv[2]; const struct vsctl_table_class *table; @@ -3367,7 +3544,11 @@ cmd_clear(struct vsctl_context *ctx) int i; table = get_table(table_name); - row = must_get_row(ctx, table, record_id); + row = get_row(ctx, table, record_id, must_exist); + if (!row) { + return; + } + for (i = 3; i < ctx->argc; i++) { const struct ovsdb_idl_column *column; const struct ovsdb_type *type; @@ -3471,20 +3652,41 @@ static void cmd_destroy(struct vsctl_context *ctx) { bool must_exist = !shash_find(&ctx->options, "--if-exists"); + bool delete_all = shash_find(&ctx->options, "--all"); const char *table_name = ctx->argv[1]; const struct vsctl_table_class *table; int i; table = get_table(table_name); - for (i = 2; i < ctx->argc; i++) { + + if (delete_all && ctx->argc > 2) { + vsctl_fatal("--all and records argument should not be specified together"); + } + + if (delete_all && !must_exist) { + vsctl_fatal("--all and --if-exists should not be specified together"); + } + + if (delete_all) { const struct ovsdb_idl_row *row; + const struct ovsdb_idl_row *next_row; - row = (must_exist ? must_get_row : get_row)(ctx, table, ctx->argv[i]); - if (row) { - ovsdb_idl_txn_delete(row); + for (row = ovsdb_idl_first_row(ctx->idl, table->class); + row;) { + next_row = ovsdb_idl_next_row(row); + ovsdb_idl_txn_delete(row); + row = next_row; } - } + } else { + for (i = 2; i < ctx->argc; i++) { + const struct ovsdb_idl_row *row; + row = get_row(ctx, table, ctx->argv[i], must_exist); + if (row) { + ovsdb_idl_txn_delete(row); + } + } + } vsctl_context_invalidate_cache(ctx); } @@ -3660,7 +3862,7 @@ cmd_wait_until(struct vsctl_context *ctx) table = get_table(table_name); - row = get_row(ctx, table, record_id); + row = get_row(ctx, table, record_id, false); if (!row) { ctx->try_again = true; return; @@ -3756,8 +3958,8 @@ run_prerequisites(struct vsctl_command *commands, size_t n_commands, (c->syntax->prerequisites)(&ctx); vsctl_context_done(&ctx, c); - assert(!c->output.string); - assert(!c->table); + ovs_assert(!c->output.string); + ovs_assert(!c->table); } } } @@ -3915,7 +4117,7 @@ do_vsctl(const char *args, struct vsctl_command *commands, size_t n_commands, table_destroy(c->table); free(c->table); - smap_destroy(&c->options); + shash_destroy_free_data(&c->options); } free(commands); @@ -3942,6 +4144,7 @@ try_again: if (txn) { ovsdb_idl_txn_abort(txn); ovsdb_idl_txn_destroy(txn); + the_idl_txn = NULL; } ovsdb_symbol_table_destroy(symtab); for (c = commands; c < &commands[n_commands]; c++) { @@ -3960,7 +4163,7 @@ static const struct vsctl_command_syntax all_commands[] = { /* Bridge commands. */ {"add-br", 1, 3, pre_get_info, cmd_add_br, NULL, "--may-exist", RW}, {"del-br", 1, 1, pre_get_info, cmd_del_br, NULL, "--if-exists", RW}, - {"list-br", 0, 0, pre_get_info, cmd_list_br, NULL, "", RO}, + {"list-br", 0, 0, pre_get_info, cmd_list_br, NULL, "--real,--fake", RO}, {"br-exists", 1, 1, pre_get_info, cmd_br_exists, NULL, "", RO}, {"br-to-vlan", 1, 1, pre_get_info, cmd_br_to_vlan, NULL, "", RO}, {"br-to-parent", 1, 1, pre_get_info, cmd_br_to_parent, NULL, "", RO}, @@ -3994,7 +4197,7 @@ static const struct vsctl_command_syntax all_commands[] = { /* Manager commands. */ {"get-manager", 0, 0, pre_manager, cmd_get_manager, NULL, "", RO}, - {"del-manager", 0, INT_MAX, pre_manager, cmd_del_manager, NULL, "", RW}, + {"del-manager", 0, 0, pre_manager, cmd_del_manager, NULL, "", RW}, {"set-manager", 1, INT_MAX, pre_manager, cmd_set_manager, NULL, "", RW}, /* SSL commands. */ @@ -4008,18 +4211,24 @@ static const struct vsctl_command_syntax all_commands[] = { /* Database commands. */ {"comment", 0, INT_MAX, NULL, NULL, NULL, "", RO}, {"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}, + {"list", 1, INT_MAX, pre_cmd_list, cmd_list, NULL, + "--if-exists,--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}, - {"clear", 3, INT_MAX, pre_cmd_clear, cmd_clear, NULL, "", RW}, - {"create", 2, INT_MAX, pre_create, cmd_create, post_create, "--id=", RW}, - {"destroy", 1, INT_MAX, pre_cmd_destroy, cmd_destroy, NULL, "--if-exists", + {"set", 3, INT_MAX, pre_cmd_set, cmd_set, NULL, "--if-exists", RW}, + {"add", 4, INT_MAX, pre_cmd_add, cmd_add, NULL, "--if-exists", RW}, + {"remove", 4, INT_MAX, pre_cmd_remove, cmd_remove, NULL, "--if-exists", RW}, + {"clear", 3, INT_MAX, pre_cmd_clear, cmd_clear, NULL, "--if-exists", RW}, + {"create", 2, INT_MAX, pre_create, cmd_create, post_create, "--id=", RW}, + {"destroy", 1, INT_MAX, pre_cmd_destroy, cmd_destroy, NULL, + "--if-exists,--all", RW}, {"wait-until", 2, INT_MAX, pre_cmd_wait_until, cmd_wait_until, NULL, "", RO}, {NULL, 0, 0, NULL, NULL, NULL, NULL, RO}, }; +static const struct vsctl_command_syntax *get_all_commands(void) +{ + return all_commands; +}