On 11 September 2015 at 20:29, Ben Pfaff <b...@nicira.com> wrote: > This makes ovn-nbctl into a pretty slavish imitation of ovn-nbctl, using > almost the same code. It has two immediate benefits. First, multiple > commands can now be chained together into a single ovn-nbctl invocation. > Second, the database commands such as "create", "set", and so on allow > queries and modifications that don't have specific commands already. > In the following commit, this allows testing the OVN ACL feature. > > Signed-off-by: Ben Pfaff <b...@nicira.com> >
imitation of ovn-sbctl? Also, one thing I noticed is that there is no implementation for 'struct nbctl_context' and 'cache'. so, there is no guarantee that in a long cmd chain, the later cmd will never see the invalid db states. Thanks, Alex Wang, > --- > ovn/utilities/ovn-nbctl.8.xml | 4 +- > ovn/utilities/ovn-nbctl.c | 1043 > ++++++++++++++++++++++++----------------- > tests/ovn-nbctl.at | 4 +- > 3 files changed, 608 insertions(+), 443 deletions(-) > > diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml > index f9f58e5..ad340ec 100644 > --- a/ovn/utilities/ovn-nbctl.8.xml > +++ b/ovn/utilities/ovn-nbctl.8.xml > @@ -68,13 +68,13 @@ > > <h1>ACL Commands</h1> > <dl> > - <dt><code>acl-add</code> <var>lswitch</var> <var>direction</var> > <var>priority</var> <var>match</var> <var>action</var> > [<code>log</code>]</dt> > + <dt>[<code>--log</code>] <code>acl-add</code> <var>lswitch</var> > <var>direction</var> <var>priority</var> <var>match</var> > <var>action</var></dt> > <dd> > Adds the specified ACL to <var>lswitch</var>. > <var>direction</var> must be either <code>from-lport</code> or > <code>to-lport</code>. <var>priority</var> must be between > <code>1</code> and <code>65534</code>, inclusive. If > - <code>log</code> is supplied, packet logging is enabled for the > + <code>--log</code> is specified, packet logging is enabled for the > ACL. A full description of the fields are in > <code>ovn-nb</code>(5). > </dd> > > diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c > index 6eae0e1..c308ddc 100644 > --- a/ovn/utilities/ovn-nbctl.c > +++ b/ovn/utilities/ovn-nbctl.c > @@ -20,8 +20,10 @@ > #include <stdio.h> > > #include "command-line.h" > +#include "db-ctl-base.h" > #include "dirs.h" > #include "fatal-signal.h" > +#include "json.h" > #include "ovn/lib/ovn-nb-idl.h" > #include "poll-loop.h" > #include "process.h" > @@ -29,19 +31,253 @@ > #include "stream.h" > #include "stream-ssl.h" > #include "svec.h" > +#include "table.h" > +#include "timeval.h" > #include "util.h" > #include "openvswitch/vlog.h" > > -VLOG_DEFINE_THIS_MODULE(ovn_nbctl); > +VLOG_DEFINE_THIS_MODULE(nbctl); > > -struct nbctl_context { > +/* --db: The database server to contact. */ > +static const char *db; > + > +/* --oneline: Write each command's output as a single line? */ > +static bool oneline; > + > +/* --dry-run: Do not commit any changes. */ > +static bool dry_run; > + > +/* --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; > + > +/* The IDL we're using and the current transaction, if any. > + * This is for use by nbctl_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 nbctl_exit(int status); > + > +static void nbctl_cmd_init(void); > +OVS_NO_RETURN static void usage(void); > +static void parse_options(int argc, char *argv[], struct shash > *local_options); > +static const char *nbctl_default_db(void); > +static void run_prerequisites(struct ctl_command[], size_t n_commands, > + struct ovsdb_idl *); > +static void do_nbctl(const char *args, struct ctl_command *, size_t n, > + struct ovsdb_idl *); > + > +int > +main(int argc, char *argv[]) > +{ > + extern struct vlog_module VLM_reconnect; > struct ovsdb_idl *idl; > - struct ovsdb_idl_txn *txn; > -}; > + struct ctl_command *commands; > + struct shash local_options; > + unsigned int seqno; > + size_t n_commands; > + char *args; > > -static const char *db; > + 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); > + nbrec_init(); > + > + nbctl_cmd_init(); > + > + /* Log our arguments. This is often valuable for debugging systems. > */ > + args = process_escape_args(argv); > + VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG, > + "Called as %s", args); > + > + /* Parse command line. */ > + shash_init(&local_options); > + parse_options(argc, argv, &local_options); > + commands = ctl_parse_commands(argc - optind, argv + optind, > &local_options, > + &n_commands); > + > + if (timeout) { > + time_alarm(timeout); > + } > + > + /* Initialize IDL. */ > + idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false); > + run_prerequisites(commands, n_commands, idl); > + > + /* Execute the commands. > + * > + * 'seqno' is the database sequence number for which we last tried to > + * execute our transaction. There's no point in trying to commit > more than > + * once for any given sequence number, because if the transaction > fails > + * it's because the database changed and we need to obtain an > up-to-date > + * view of the database before we try the transaction again. */ > + 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); > + ctl_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); > + do_nbctl(args, commands, n_commands, idl); > + } > > -static const char *default_db(void); > + if (seqno == ovsdb_idl_get_seqno(idl)) { > + ovsdb_idl_wait(idl); > + poll_block(); > + } > + } > +} > + > +static const char * > +nbctl_default_db(void) > +{ > + static char *def; > + if (!def) { > + def = getenv("OVN_NB_DB"); > + if (!def) { > + def = xasprintf("unix:%s/db.sock", ovs_rundir()); > + } > + } > + return def; > +} > + > +static void > +parse_options(int argc, char *argv[], struct shash *local_options) > +{ > + enum { > + OPT_DB = UCHAR_MAX + 1, > + OPT_NO_SYSLOG, > + OPT_DRY_RUN, > + OPT_ONELINE, > + OPT_LOCAL, > + OPT_COMMANDS, > + OPT_OPTIONS, > + VLOG_OPTION_ENUMS, > + TABLE_OPTION_ENUMS > + }; > + static const struct option global_long_options[] = { > + {"db", required_argument, NULL, OPT_DB}, > + {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, > + {"dry-run", no_argument, NULL, OPT_DRY_RUN}, > + {"oneline", no_argument, NULL, OPT_ONELINE}, > + {"timeout", required_argument, NULL, 't'}, > + {"help", no_argument, NULL, 'h'}, > + {"commands", no_argument, NULL, OPT_COMMANDS}, > + {"options", no_argument, NULL, OPT_OPTIONS}, > + {"version", no_argument, NULL, 'V'}, > + VLOG_LONG_OPTIONS, > + STREAM_SSL_LONG_OPTIONS, > + TABLE_LONG_OPTIONS, > + {NULL, 0, NULL, 0}, > + }; > + const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; > + char *tmp, *short_options; > + > + struct option *options; > + size_t allocated_options; > + size_t n_options; > + size_t i; > + > + tmp = ovs_cmdl_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; > + ctl_add_cmd_options(&options, &n_options, &allocated_options, > OPT_LOCAL); > + table_style.format = TF_LIST; > + > + for (;;) { > + int idx; > + int c; > + > + c = getopt_long(argc, argv, short_options, options, &idx); > + if (c == -1) { > + break; > + } > + > + switch (c) { > + case OPT_DB: > + db = optarg; > + break; > + > + case OPT_ONELINE: > + oneline = true; > + break; > + > + case OPT_NO_SYSLOG: > + vlog_set_levels(&VLM_nbctl, VLF_SYSLOG, VLL_WARN); > + break; > + > + case OPT_DRY_RUN: > + dry_run = true; > + break; > + > + case OPT_LOCAL: > + if (shash_find(local_options, options[idx].name)) { > + ctl_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(); > + exit(EXIT_SUCCESS); > + > + case OPT_COMMANDS: > + ctl_print_commands(); > + > + case OPT_OPTIONS: > + ctl_print_options(global_long_options); > + > + case 'V': > + ovs_print_version(0, 0); > + printf("DB Schema %s\n", nbrec_get_db_version()); > + exit(EXIT_SUCCESS); > + > + case 't': > + timeout = strtoul(optarg, NULL, 10); > + if (timeout < 0) { > + ctl_fatal("value %s on -t or --timeout is invalid", > optarg); > + } > + break; > + > + VLOG_OPTION_HANDLERS > + TABLE_OPTION_HANDLERS(&table_style) > + STREAM_SSL_OPTION_HANDLERS > + > + case '?': > + exit(EXIT_FAILURE); > + > + default: > + abort(); > + } > + } > + > + if (!db) { > + db = nbctl_default_db(); > + } > + > + for (i = n_global_long_options; options[i].name; i++) { > + free(CONST_CAST(char *, options[i].name)); > + } > + free(options); > +} > > static void > usage(void) > @@ -102,18 +338,24 @@ Logical port commands:\n\ > lport-get-options LPORT Get the type specific options for LPORT\n\ > \n\ > Options:\n\ > - --db=DATABASE connect to DATABASE\n\ > - (default: %s)\n\ > - -h, --help display this help message\n\ > - -o, --options list available options\n\ > - -V, --version display version information\n\ > -", program_name, program_name, default_db()); > + --db=DATABASE connect to DATABASE\n\ > + (default: %s)\n\ > + -t, --timeout=SECS wait at most SECS seconds\n\ > + --dry-run do not commit changes to database\n\ > + --oneline print exactly one line of output per > command\n", > + program_name, program_name, nbctl_default_db()); > vlog_usage(); > - stream_usage("database", true, true, false); > + printf("\ > + --no-syslog equivalent to --verbose=nbctl:syslog:warn\n"); > + printf("\n\ > +Other options:\n\ > + -h, --help display this help message\n\ > + -V, --version display version information\n"); > + exit(EXIT_SUCCESS); > } > > static const struct nbrec_logical_switch * > -lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id) > +lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id) > { > const struct nbrec_logical_switch *lswitch = NULL; > bool is_uuid = false; > @@ -122,14 +364,14 @@ lswitch_by_name_or_uuid(struct nbctl_context > *nb_ctx, const char *id) > > if (uuid_from_string(&lswitch_uuid, id)) { > is_uuid = true; > - lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl, > + lswitch = nbrec_logical_switch_get_for_uuid(ctx->idl, > &lswitch_uuid); > } > > if (!lswitch) { > const struct nbrec_logical_switch *iter; > > - NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) { > + NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) { > if (strcmp(iter->name, id)) { > continue; > } > @@ -153,67 +395,64 @@ lswitch_by_name_or_uuid(struct nbctl_context > *nb_ctx, const char *id) > } > > static void > -print_lswitch(const struct nbrec_logical_switch *lswitch) > +print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s) > { > - printf(" lswitch "UUID_FMT" (%s)\n", > - UUID_ARGS(&lswitch->header_.uuid), lswitch->name); > + ds_put_format(s, " lswitch "UUID_FMT" (%s)\n", > + UUID_ARGS(&lswitch->header_.uuid), lswitch->name); > > for (size_t i = 0; i < lswitch->n_ports; i++) { > const struct nbrec_logical_port *lport = lswitch->ports[i]; > > - printf(" lport %s\n", lport->name); > + ds_put_format(s, " lport %s\n", lport->name); > if (lport->parent_name && lport->n_tag) { > - printf(" parent: %s, tag:%"PRIu64"\n", > - lport->parent_name, lport->tag[0]); > + ds_put_format(s, " parent: %s, tag:%"PRIu64"\n", > + lport->parent_name, lport->tag[0]); > } > if (lport->n_macs) { > - printf(" macs:"); > + ds_put_cstr(s, " macs:"); > for (size_t j = 0; j < lport->n_macs; j++) { > - printf(" %s", lport->macs[j]); > + ds_put_format(s, " %s", lport->macs[j]); > } > - printf("\n"); > + ds_put_char(s, '\n'); > } > } > } > > static void > -nbctl_show(struct ovs_cmdl_context *ctx) > +nbctl_show(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_logical_switch *lswitch; > > if (ctx->argc == 2) { > - lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]); > if (lswitch) { > - print_lswitch(lswitch); > + print_lswitch(lswitch, &ctx->output); > } > } else { > - NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) { > - print_lswitch(lswitch); > + NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) { > + print_lswitch(lswitch, &ctx->output); > } > } > } > > static void > -nbctl_lswitch_add(struct ovs_cmdl_context *ctx) > +nbctl_lswitch_add(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > struct nbrec_logical_switch *lswitch; > > - lswitch = nbrec_logical_switch_insert(nb_ctx->txn); > + lswitch = nbrec_logical_switch_insert(ctx->txn); > if (ctx->argc == 2) { > nbrec_logical_switch_set_name(lswitch, ctx->argv[1]); > } > } > > static void > -nbctl_lswitch_del(struct ovs_cmdl_context *ctx) > +nbctl_lswitch_del(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_switch *lswitch; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, id); > + lswitch = lswitch_by_name_or_uuid(ctx, id); > if (!lswitch) { > return; > } > @@ -222,35 +461,33 @@ nbctl_lswitch_del(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lswitch_list(struct ovs_cmdl_context *ctx) > +nbctl_lswitch_list(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_logical_switch *lswitch; > struct smap lswitches; > > smap_init(&lswitches); > - NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) { > + NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) { > smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)", > UUID_ARGS(&lswitch->header_.uuid), lswitch->name); > } > const struct smap_node **nodes = smap_sort(&lswitches); > for (size_t i = 0; i < smap_count(&lswitches); i++) { > const struct smap_node *node = nodes[i]; > - printf("%s\n", node->value); > + ds_put_format(&ctx->output, "%s\n", node->value); > } > smap_destroy(&lswitches); > free(nodes); > } > > static void > -nbctl_lswitch_set_external_id(struct ovs_cmdl_context *ctx) > +nbctl_lswitch_set_external_id(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_switch *lswitch; > struct smap new_external_ids; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, id); > + lswitch = lswitch_by_name_or_uuid(ctx, id); > if (!lswitch) { > return; > } > @@ -267,13 +504,12 @@ nbctl_lswitch_set_external_id(struct > ovs_cmdl_context *ctx) > } > > static void > -nbctl_lswitch_get_external_id(struct ovs_cmdl_context *ctx) > +nbctl_lswitch_get_external_id(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_switch *lswitch; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, id); > + lswitch = lswitch_by_name_or_uuid(ctx, id); > if (!lswitch) { > return; > } > @@ -286,7 +522,7 @@ nbctl_lswitch_get_external_id(struct ovs_cmdl_context > *ctx) > > value = smap_get(&lswitch->external_ids, key); > if (value) { > - printf("%s\n", value); > + ds_put_format(&ctx->output, "%s\n", value); > } > } else { > struct smap_node *node; > @@ -294,13 +530,13 @@ nbctl_lswitch_get_external_id(struct > ovs_cmdl_context *ctx) > /* List all external IDs */ > > SMAP_FOR_EACH(node, &lswitch->external_ids) { > - printf("%s=%s\n", node->key, node->value); > + ds_put_format(&ctx->output, "%s=%s\n", node->key, > node->value); > } > } > } > > static const struct nbrec_logical_port * > -lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id) > +lport_by_name_or_uuid(struct ctl_context *ctx, const char *id) > { > const struct nbrec_logical_port *lport = NULL; > bool is_uuid = false; > @@ -308,11 +544,11 @@ lport_by_name_or_uuid(struct nbctl_context *nb_ctx, > const char *id) > > if (uuid_from_string(&lport_uuid, id)) { > is_uuid = true; > - lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid); > + lport = nbrec_logical_port_get_for_uuid(ctx->idl, &lport_uuid); > } > > if (!lport) { > - NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) { > + NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->idl) { > if (!strcmp(lport->name, id)) { > break; > } > @@ -328,14 +564,13 @@ lport_by_name_or_uuid(struct nbctl_context *nb_ctx, > const char *id) > } > > static void > -nbctl_lport_add(struct ovs_cmdl_context *ctx) > +nbctl_lport_add(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > struct nbrec_logical_port *lport; > const struct nbrec_logical_switch *lswitch; > int64_t tag; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lswitch) { > return; > } > @@ -355,7 +590,7 @@ nbctl_lport_add(struct ovs_cmdl_context *ctx) > } > > /* Create the logical port. */ > - lport = nbrec_logical_port_insert(nb_ctx->txn); > + lport = nbrec_logical_port_insert(ctx->txn); > nbrec_logical_port_set_name(lport, ctx->argv[2]); > if (ctx->argc == 5) { > nbrec_logical_port_set_parent_name(lport, ctx->argv[3]); > @@ -395,19 +630,18 @@ remove_lport(const struct nbrec_logical_switch > *lswitch, size_t idx) > } > > static void > -nbctl_lport_del(struct ovs_cmdl_context *ctx) > +nbctl_lport_del(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lport = lport_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lport) { > return; > } > > /* Find the switch that contains 'lport', then delete it. */ > const struct nbrec_logical_switch *lswitch; > - NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) { > + NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) { > for (size_t i = 0; i < lswitch->n_ports; i++) { > if (lswitch->ports[i] == lport) { > remove_lport(lswitch, i); > @@ -421,15 +655,14 @@ nbctl_lport_del(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_list(struct ovs_cmdl_context *ctx) > +nbctl_lport_list(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_switch *lswitch; > struct smap lports; > size_t i; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, id); > + lswitch = lswitch_by_name_or_uuid(ctx, id); > if (!lswitch) { > return; > } > @@ -443,53 +676,50 @@ nbctl_lport_list(struct ovs_cmdl_context *ctx) > const struct smap_node **nodes = smap_sort(&lports); > for (i = 0; i < smap_count(&lports); i++) { > const struct smap_node *node = nodes[i]; > - printf("%s\n", node->value); > + ds_put_format(&ctx->output, "%s\n", node->value); > } > smap_destroy(&lports); > free(nodes); > } > > static void > -nbctl_lport_get_parent(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_parent(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lport = lport_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lport) { > return; > } > > if (lport->parent_name) { > - printf("%s\n", lport->parent_name); > + ds_put_format(&ctx->output, "%s\n", lport->parent_name); > } > } > > static void > -nbctl_lport_get_tag(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_tag(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lport = lport_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lport) { > return; > } > > if (lport->n_tag > 0) { > - printf("%"PRId64"\n", lport->tag[0]); > + ds_put_format(&ctx->output, "%"PRId64"\n", lport->tag[0]); > } > } > > static void > -nbctl_lport_set_external_id(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_external_id(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > struct smap new_external_ids; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -506,13 +736,12 @@ nbctl_lport_set_external_id(struct ovs_cmdl_context > *ctx) > } > > static void > -nbctl_lport_get_external_id(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_external_id(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -525,7 +754,7 @@ nbctl_lport_get_external_id(struct ovs_cmdl_context > *ctx) > > value = smap_get(&lport->external_ids, key); > if (value) { > - printf("%s\n", value); > + ds_put_format(&ctx->output, "%s\n", value); > } > } else { > struct smap_node *node; > @@ -533,19 +762,18 @@ nbctl_lport_get_external_id(struct ovs_cmdl_context > *ctx) > /* List all external IDs */ > > SMAP_FOR_EACH(node, &lport->external_ids) { > - printf("%s=%s\n", node->key, node->value); > + ds_put_format(&ctx->output, "%s=%s\n", node->key, > node->value); > } > } > } > > static void > -nbctl_lport_set_macs(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_macs(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -555,16 +783,15 @@ nbctl_lport_set_macs(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_get_macs(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_macs(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > struct svec macs; > const char *mac; > size_t i; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -575,19 +802,18 @@ nbctl_lport_get_macs(struct ovs_cmdl_context *ctx) > } > svec_sort(&macs); > SVEC_FOR_EACH(i, mac, &macs) { > - printf("%s\n", mac); > + ds_put_format(&ctx->output, "%s\n", mac); > } > svec_destroy(&macs); > } > > static void > -nbctl_lport_set_port_security(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_port_security(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -597,16 +823,15 @@ nbctl_lport_set_port_security(struct > ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_get_port_security(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_port_security(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > struct svec addrs; > const char *addr; > size_t i; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -617,35 +842,34 @@ nbctl_lport_get_port_security(struct > ovs_cmdl_context *ctx) > } > svec_sort(&addrs); > SVEC_FOR_EACH(i, addr, &addrs) { > - printf("%s\n", addr); > + ds_put_format(&ctx->output, "%s\n", addr); > } > svec_destroy(&addrs); > } > > static void > -nbctl_lport_get_up(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_up(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > > - printf("%s\n", (lport->up && *lport->up) ? "up" : "down"); > + ds_put_format(&ctx->output, > + "%s\n", (lport->up && *lport->up) ? "up" : "down"); > } > > static void > -nbctl_lport_set_enabled(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_enabled(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const char *state = ctx->argv[2]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -662,30 +886,28 @@ nbctl_lport_set_enabled(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_get_enabled(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_enabled(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > > - printf("%s\n", > - (!lport->enabled || *lport->enabled) ? "enabled" : "disabled"); > + ds_put_format(&ctx->output, "%s\n", > + !lport->enabled || *lport->enabled ? "enabled" : > "disabled"); > } > > static void > -nbctl_lport_set_type(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_type(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const char *type = ctx->argv[2]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -694,30 +916,28 @@ nbctl_lport_set_type(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_get_type(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_type(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > > - printf("%s\n", lport->type); > + ds_put_format(&ctx->output, "%s\n", lport->type); > } > > static void > -nbctl_lport_set_options(struct ovs_cmdl_context *ctx) > +nbctl_lport_set_options(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > size_t i; > struct smap options = SMAP_INITIALIZER(&options); > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > @@ -738,20 +958,19 @@ nbctl_lport_set_options(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_lport_get_options(struct ovs_cmdl_context *ctx) > +nbctl_lport_get_options(struct ctl_context *ctx) > { > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *id = ctx->argv[1]; > const struct nbrec_logical_port *lport; > struct smap_node *node; > > - lport = lport_by_name_or_uuid(nb_ctx, id); > + lport = lport_by_name_or_uuid(ctx, id); > if (!lport) { > return; > } > > SMAP_FOR_EACH(node, &lport->options) { > - printf("%s=%s\n", node->key, node->value); > + ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value); > } > } > > @@ -793,14 +1012,13 @@ acl_cmp(const void *acl1_, const void *acl2_) > } > > static void > -nbctl_acl_list(struct ovs_cmdl_context *ctx) > +nbctl_acl_list(struct ctl_context *ctx) > { > const struct nbrec_logical_switch *lswitch; > - struct nbctl_context *nb_ctx = ctx->pvt; > const struct nbrec_acl **acls; > size_t i; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lswitch) { > return; > } > @@ -822,15 +1040,14 @@ nbctl_acl_list(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_acl_add(struct ovs_cmdl_context *ctx) > +nbctl_acl_add(struct ctl_context *ctx) > { > const struct nbrec_logical_switch *lswitch; > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *action = ctx->argv[5]; > const char *direction; > int64_t priority; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lswitch) { > return; > } > @@ -860,12 +1077,12 @@ nbctl_acl_add(struct ovs_cmdl_context *ctx) > } > > /* Create the acl. */ > - struct nbrec_acl *acl = nbrec_acl_insert(nb_ctx->txn); > + struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn); > nbrec_acl_set_priority(acl, priority); > nbrec_acl_set_direction(acl, direction); > nbrec_acl_set_match(acl, ctx->argv[4]); > nbrec_acl_set_action(acl, action); > - if (ctx->argc == 7 && ctx->argv[6][0] == 'l') { > + if (shash_find(&ctx->options, "--log") != NULL) { > nbrec_acl_set_log(acl, true); > } > > @@ -880,14 +1097,13 @@ nbctl_acl_add(struct ovs_cmdl_context *ctx) > } > > static void > -nbctl_acl_del(struct ovs_cmdl_context *ctx) > +nbctl_acl_del(struct ctl_context *ctx) > { > const struct nbrec_logical_switch *lswitch; > - struct nbctl_context *nb_ctx = ctx->pvt; > const char *direction; > int64_t priority = 0; > > - lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]); > + lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]); > if (!lswitch) { > return; > } > @@ -959,343 +1175,292 @@ nbctl_acl_del(struct ovs_cmdl_context *ctx) > } > } > > +static const struct ctl_table_class tables[] = { > + {&nbrec_table_logical_switch, > + {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL}, > + {NULL, NULL, NULL}}}, > + > + {&nbrec_table_logical_port, > + {{&nbrec_table_logical_port, &nbrec_logical_port_col_name, NULL}, > + {NULL, NULL, NULL}}}, > + > + {&nbrec_table_acl, > + {{NULL, NULL, NULL}, > + {NULL, NULL, NULL}}}, > + > + {&nbrec_table_logical_router, > + {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL}, > + {NULL, NULL, NULL}}}, > + > + {&nbrec_table_logical_router_port, > + {{&nbrec_table_logical_router_port, > &nbrec_logical_router_port_col_name, > + NULL}, > + {NULL, NULL, NULL}}}, > + > + {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} > +}; > + > static void > -parse_options(int argc, char *argv[]) > +run_prerequisites(struct ctl_command *commands, size_t n_commands, > + struct ovsdb_idl *idl) > { > - enum { > - VLOG_OPTION_ENUMS, > - }; > - static const struct option long_options[] = { > - {"db", required_argument, NULL, 'd'}, > - {"help", no_argument, NULL, 'h'}, > - {"options", no_argument, NULL, 'o'}, > - {"version", no_argument, NULL, 'V'}, > - VLOG_LONG_OPTIONS, > - STREAM_SSL_LONG_OPTIONS, > - {NULL, 0, NULL, 0}, > - }; > - char *short_options = > ovs_cmdl_long_options_to_short_options(long_options); > + struct ctl_command *c; > > - for (;;) { > - int c; > - > - c = getopt_long(argc, argv, short_options, long_options, NULL); > - if (c == -1) { > - break; > - } > + for (c = commands; c < &commands[n_commands]; c++) { > + if (c->syntax->prerequisites) { > + struct ctl_context ctx; > > - switch (c) { > - VLOG_OPTION_HANDLERS; > - STREAM_SSL_OPTION_HANDLERS; > + ds_init(&c->output); > + c->table = NULL; > > - case 'd': > - db = optarg; > - break; > + ctl_context_init(&ctx, c, idl, NULL, NULL, NULL); > + (c->syntax->prerequisites)(&ctx); > + ctl_context_done(&ctx, c); > > - case 'h': > - usage(); > - exit(EXIT_SUCCESS); > + ovs_assert(!c->output.string); > + ovs_assert(!c->table); > + } > + } > +} > > - case 'o': > - ovs_cmdl_print_options(long_options); > - exit(EXIT_SUCCESS); > +static void > +do_nbctl(const char *args, struct ctl_command *commands, size_t > n_commands, > + struct ovsdb_idl *idl) > +{ > + struct ovsdb_idl_txn *txn; > + enum ovsdb_idl_txn_status status; > + struct ovsdb_symbol_table *symtab; > + struct ctl_context ctx; > + struct ctl_command *c; > + struct shash_node *node; > + char *error = 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-nbctl: %s", args); > + > + symtab = ovsdb_symbol_table_create(); > + for (c = commands; c < &commands[n_commands]; c++) { > + ds_init(&c->output); > + c->table = NULL; > + } > + ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL); > + for (c = commands; c < &commands[n_commands]; c++) { > + ctl_context_init_command(&ctx, c); > + if (c->syntax->run) { > + (c->syntax->run)(&ctx); > + } > + ctl_context_done_command(&ctx, c); > > - case 'V': > - ovs_print_version(0, 0); > - exit(EXIT_SUCCESS); > + if (ctx.try_again) { > + ctl_context_done(&ctx, NULL); > + goto try_again; > + } > + } > + ctl_context_done(&ctx, NULL); > > - default: > - break; > + SHASH_FOR_EACH (node, &symtab->sh) { > + struct ovsdb_symbol *symbol = node->data; > + if (!symbol->created) { > + ctl_fatal("row id \"%s\" is referenced but never created > (e.g. " > + "with \"-- --id=%s create ...\")", > + node->name, node->name); > + } > + if (!symbol->strong_ref) { > + if (!symbol->weak_ref) { > + VLOG_WARN("row id \"%s\" was created but no reference to > it " > + "was inserted, so it will not actually appear > in " > + "the database", node->name); > + } else { > + VLOG_WARN("row id \"%s\" was created but only a weak " > + "reference to it was inserted, so it will not " > + "actually appear in the database", node->name); > + } > } > } > > - if (!db) { > - db = default_db(); > + status = ovsdb_idl_txn_commit_block(txn); > + if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { > + for (c = commands; c < &commands[n_commands]; c++) { > + if (c->syntax->postprocess) { > + ctl_context_init(&ctx, c, idl, txn, symtab, NULL); > + (c->syntax->postprocess)(&ctx); > + ctl_context_done(&ctx, c); > + } > + } > } > + error = xstrdup(ovsdb_idl_txn_get_error(txn)); > > - free(short_options); > -} > + switch (status) { > + case TXN_UNCOMMITTED: > + case TXN_INCOMPLETE: > + OVS_NOT_REACHED(); > > -static const struct ovs_cmdl_command all_commands[] = { > - { > - .name = "show", > - .usage = "[LSWITCH]", > - .min_args = 0, > - .max_args = 1, > - .handler = nbctl_show, > - }, > - { > - .name = "lswitch-add", > - .usage = "[LSWITCH]", > - .min_args = 0, > - .max_args = 1, > - .handler = nbctl_lswitch_add, > - }, > - { > - .name = "lswitch-del", > - .usage = "LSWITCH", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lswitch_del, > - }, > - { > - .name = "lswitch-list", > - .usage = "", > - .min_args = 0, > - .max_args = 0, > - .handler = nbctl_lswitch_list, > - }, > - { > - .name = "lswitch-set-external-id", > - .usage = "LSWITCH KEY [VALUE]", > - .min_args = 2, > - .max_args = 3, > - .handler = nbctl_lswitch_set_external_id, > - }, > - { > - .name = "lswitch-get-external-id", > - .usage = "LSWITCH [KEY]", > - .min_args = 1, > - .max_args = 2, > - .handler = nbctl_lswitch_get_external_id, > - }, > - { > - .name = "acl-add", > - .usage = "LSWITCH DIRECTION PRIORITY MATCH ACTION [log]", > - .min_args = 5, > - .max_args = 6, > - .handler = nbctl_acl_add, > - }, > - { > - .name = "acl-del", > - .usage = "LSWITCH [DIRECTION [PRIORITY MATCH]]", > - .min_args = 1, > - .max_args = 4, > - .handler = nbctl_acl_del, > - }, > - { > - .name = "acl-list", > - .usage = "LSWITCH", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_acl_list, > - }, > - { > - .name = "lport-add", > - .usage = "LSWITCH LPORT [PARENT] [TAG]", > - .min_args = 2, > - .max_args = 4, > - .handler = nbctl_lport_add, > - }, > - { > - .name = "lport-del", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_del, > - }, > - { > - .name = "lport-list", > - .usage = "LSWITCH", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_list, > - }, > - { > - .name = "lport-get-parent", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_parent, > - }, > - { > - .name = "lport-get-tag", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_tag, > - }, > - { > - .name = "lport-set-external-id", > - .usage = "LPORT KEY [VALUE]", > - .min_args = 2, > - .max_args = 3, > - .handler = nbctl_lport_set_external_id, > - }, > - { > - .name = "lport-get-external-id", > - .usage = "LPORT [KEY]", > - .min_args = 1, > - .max_args = 2, > - .handler = nbctl_lport_get_external_id, > - }, > - { > - .name = "lport-set-macs", > - .usage = "LPORT [MAC]...", > - .min_args = 1, > - /* Accept however many arguments the system will allow. */ > - .max_args = INT_MAX, > - .handler = nbctl_lport_set_macs, > - }, > - { > - .name = "lport-get-macs", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_macs, > - }, > - { > - .name = "lport-set-port-security", > - .usage = "LPORT [ADDRS]...", > - .min_args = 0, > - /* Accept however many arguments the system will allow. */ > - .max_args = INT_MAX, > - .handler = nbctl_lport_set_port_security, > - }, > - { > - .name = "lport-get-port-security", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_port_security, > - }, > - { > - .name = "lport-get-up", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_up, > - }, > - { > - .name = "lport-set-enabled", > - .usage = "LPORT STATE", > - .min_args = 2, > - .max_args = 2, > - .handler = nbctl_lport_set_enabled, > - }, > - { > - .name = "lport-get-enabled", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_enabled, > - }, > - { > - .name = "lport-set-type", > - .usage = "LPORT TYPE", > - .min_args = 2, > - .max_args = 2, > - .handler = nbctl_lport_set_type, > - }, > - { > - .name = "lport-get-type", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_type, > - }, > - { > - .name = "lport-set-options", > - .usage = "LPORT KEY=VALUE [KEY=VALUE]...", > - .min_args = 1, > - .max_args = INT_MAX, > - .handler = nbctl_lport_set_options > - }, > - { > - .name = "lport-get-options", > - .usage = "LPORT", > - .min_args = 1, > - .max_args = 1, > - .handler = nbctl_lport_get_options, > - }, > - > - { > - /* sentinel */ > - .name = NULL, > - }, > -}; > + case TXN_ABORTED: > + /* Should not happen--we never call ovsdb_idl_txn_abort(). */ > + ctl_fatal("transaction aborted"); > > -static const struct ovs_cmdl_command * > -get_all_commands(void) > -{ > - return all_commands; > -} > + case TXN_UNCHANGED: > + case TXN_SUCCESS: > + break; > > -static const char * > -default_db(void) > -{ > - static char *def; > - if (!def) { > - def = getenv("OVN_NB_DB"); > - if (!def) { > - def = xasprintf("unix:%s/db.sock", ovs_rundir()); > - } > - } > - return def; > -} > + case TXN_TRY_AGAIN: > + goto try_again; > > -int > -main(int argc, char *argv[]) > -{ > - extern struct vlog_module VLM_reconnect; > - struct ovs_cmdl_context ctx; > - struct nbctl_context nb_ctx = { .idl = NULL, }; > - enum ovsdb_idl_txn_status txn_status; > - unsigned int seqno; > - int res = 0; > - char *args; > + case TXN_ERROR: > + ctl_fatal("transaction error: %s", error); > > - fatal_ignore_sigpipe(); > - set_program_name(argv[0]); > - vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); > - vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); > - parse_options(argc, argv); > - nbrec_init(); > + case TXN_NOT_LOCKED: > + /* Should not happen--we never call ovsdb_idl_set_lock(). */ > + ctl_fatal("database not locked"); > > - args = process_escape_args(argv); > + default: > + OVS_NOT_REACHED(); > + } > + free(error); > > - nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false); > - ctx.pvt = &nb_ctx; > - ctx.argc = argc - optind; > - ctx.argv = argv + optind; > + ovsdb_symbol_table_destroy(symtab); > > - seqno = ovsdb_idl_get_seqno(nb_ctx.idl); > - for (;;) { > - ovsdb_idl_run(nb_ctx.idl); > + for (c = commands; c < &commands[n_commands]; c++) { > + struct ds *ds = &c->output; > > - if (!ovsdb_idl_is_alive(nb_ctx.idl)) { > - int retval = ovsdb_idl_get_last_error(nb_ctx.idl); > - VLOG_ERR("%s: database connection failed (%s)", > - db, ovs_retval_to_string(retval)); > - res = 1; > - break; > - } > + if (c->table) { > + table_print(c->table, &table_style); > + } else if (oneline) { > + size_t j; > > - if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) { > - nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl); > - ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args); > - ovs_cmdl_run_command(&ctx, get_all_commands()); > - txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn); > - if (txn_status == TXN_TRY_AGAIN) { > - ovsdb_idl_txn_destroy(nb_ctx.txn); > - nb_ctx.txn = NULL; > - continue; > - } else { > - break; > + ds_chomp(ds, '\n'); > + for (j = 0; j < ds->length; j++) { > + int ch = ds->string[j]; > + switch (ch) { > + case '\n': > + fputs("\\n", stdout); > + break; > + > + case '\\': > + fputs("\\\\", stdout); > + break; > + > + default: > + putchar(ch); > + } > } > + putchar('\n'); > + } else { > + fputs(ds_cstr(ds), stdout); > } > + ds_destroy(&c->output); > + table_destroy(c->table); > + free(c->table); > > - if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) { > - ovsdb_idl_wait(nb_ctx.idl); > - poll_block(); > - } > + shash_destroy_free_data(&c->options); > } > + free(commands); > + ovsdb_idl_txn_destroy(txn); > + ovsdb_idl_destroy(idl); > + > + exit(EXIT_SUCCESS); > > - if (nb_ctx.txn) { > - ovsdb_idl_txn_destroy(nb_ctx.txn); > +try_again: > + /* Our transaction needs to be rerun, or a prerequisite was not met. > Free > + * resources and return so that the caller can try again. */ > + if (txn) { > + ovsdb_idl_txn_abort(txn); > + ovsdb_idl_txn_destroy(txn); > + the_idl_txn = NULL; > } > - ovsdb_idl_destroy(nb_ctx.idl); > - free(args); > + 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); > +} > + > +/* 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 > +nbctl_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); > +} > + > +static const struct ctl_command_syntax nbctl_commands[] = { > + { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO }, > + > + /* lswitch commands. */ > + { "lswitch-add", 0, 1, "[LSWITCH]", NULL, nbctl_lswitch_add, > + NULL, "", RW }, > + { "lswitch-del", 1, 1, "LSWITCH", NULL, nbctl_lswitch_del, > + NULL, "", RW }, > + { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO }, > + { "lswitch-set-external-id", 2, 3, "LSWITCH KEY [VALUE]", NULL, > + nbctl_lswitch_set_external_id, NULL, "", RW }, > + { "lswitch-get-external-id", 1, 2, "LSWITCH [KEY]", NULL, > + nbctl_lswitch_get_external_id, NULL, "", RO }, > + > + /* acl commands. */ > + { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL, > + nbctl_acl_add, NULL, "--log", RW }, > + { "acl-del", 1, 4, "LSWITCH [DIRECTION [PRIORITY MATCH]]", NULL, > + nbctl_acl_del, NULL, "", RW }, > + { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO }, > + > + /* lport commands. */ > + { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, > nbctl_lport_add, > + NULL, "", RW }, > + { "lport-del", 1, 1, "LPORT", NULL, nbctl_lport_del, NULL, "", RO }, > + { "lport-list", 1, 1, "LSWITCH", NULL, nbctl_lport_list, NULL, "", RO > }, > + { "lport-get-parent", 1, 1, "LPORT", NULL, nbctl_lport_get_parent, > NULL, > + "", RO }, > + { "lport-get-tag", 1, 1, "LPORT", NULL, nbctl_lport_get_tag, NULL, "", > + RO }, > + { "lport-set-external-id", 2, 3, "LPORT KEY [VALUE]", NULL, > + nbctl_lport_set_external_id, NULL, "", RW }, > + { "lport-get-external-id", 1, 2, "LPORT [KEY]", NULL, > + nbctl_lport_get_external_id, NULL, "", RO }, > + { "lport-set-macs", 1, INT_MAX, "LPORT [MAC]...", NULL, > + nbctl_lport_set_macs, NULL, "", RW }, > + { "lport-get-macs", 1, 1, "LPORT", NULL, nbctl_lport_get_macs, NULL, > + "", RO }, > + { "lport-set-port-security", 0, INT_MAX, "LPORT [ADDRS]...", NULL, > + nbctl_lport_set_port_security, NULL, "", RW }, > + { "lport-get-port-security", 1, 1, "LPORT", NULL, > + nbctl_lport_get_port_security, NULL, "", RO }, > + { "lport-get-up", 1, 1, "LPORT", NULL, nbctl_lport_get_up, NULL, "", > RO }, > + { "lport-set-enabled", 2, 2, "LPORT STATE", NULL, > nbctl_lport_set_enabled, > + NULL, "", RW }, > + { "lport-get-enabled", 1, 1, "LPORT", NULL, nbctl_lport_get_enabled, > NULL, > + "", RO }, > + { "lport-set-type", 2, 2, "LPORT TYPE", NULL, nbctl_lport_set_type, > NULL, > + "", RW }, > + { "lport-get-type", 1, 1, "LPORT", NULL, nbctl_lport_get_type, NULL, > "", > + RO }, > + { "lport-set-options", 1, INT_MAX, "LPORT KEY=VALUE [KEY=VALUE]...", > NULL, > + nbctl_lport_set_options, NULL, "", RW }, > + { "lport-get-options", 1, 1, "LPORT", NULL, nbctl_lport_get_options, > NULL, > + "", RO }, > + > + {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO}, > +}; > > - exit(res); > +/* Registers nbctl and common db commands. */ > +static void > +nbctl_cmd_init(void) > +{ > + ctl_init(tables, NULL, nbctl_exit); > + ctl_register_commands(nbctl_commands); > } > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > index 200c703..d55732f 100644 > --- a/tests/ovn-nbctl.at > +++ b/tests/ovn-nbctl.at > @@ -119,8 +119,8 @@ AT_SETUP([ovn-nbctl - ACLs]) > OVN_NBCTL_TEST_START > > AT_CHECK([ovn-nbctl lswitch-add ls0]) > -AT_CHECK([ovn-nbctl acl-add ls0 from-lport 600 udp drop log]) > -AT_CHECK([ovn-nbctl acl-add ls0 to-lport 500 udp drop log]) > +AT_CHECK([ovn-nbctl --log acl-add ls0 from-lport 600 udp drop]) > +AT_CHECK([ovn-nbctl --log acl-add ls0 to-lport 500 udp drop]) > AT_CHECK([ovn-nbctl acl-add ls0 from-lport 400 tcp drop]) > AT_CHECK([ovn-nbctl acl-add ls0 to-lport 300 tcp drop]) > AT_CHECK([ovn-nbctl acl-add ls0 from-lport 200 ip drop]) > -- > 2.1.3 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > -- Alex Wang, Open vSwitch developer _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev