On 11 September 2015 at 20:29, Ben Pfaff <[email protected]> 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 <[email protected]>
>
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
> [email protected]
> http://openvswitch.org/mailman/listinfo/dev
>
--
Alex Wang,
Open vSwitch developer
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev