#include <config.h>
#include <getopt.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "command-line.h"
#include "dirs.h"
#include "fatal-signal.h"
-#include "ovn/ovn-nb-idl.h"
+#include "ovn/lib/ovn-nb-idl.h"
#include "poll-loop.h"
+#include "process.h"
#include "stream.h"
#include "stream-ssl.h"
#include "util.h"
%s: OVN northbound DB management utility\n\
usage: %s [OPTIONS] COMMAND [ARG...]\n\
\n\
-Logical Switch Commands:\n\
- lswitch-add [name] Create a logical switch\n\
- lswitch-del <lswitch> Delete a logical switch\n\
- lswitch-list List configured logical switches\n\
- lswitch-set-external-id <lswitch> <key> [value]\n\
- Set or delete an external:id on a logical switch\n\
- lswitch-get-external-id <lswitch> [key]\n\
- List one or all external:ids set on a switch\n\
+General commands:\n\
+ show print overview of database contents\n\
+ show LSWITCH print overview of database contents for LSWITCH\n\
\n\
-Logical Port Commands:\n\
- lport-add <name> <lswitch> Create a logical port on a logical switch\n\
- lport-del <lport> Delete a logical port (by name or UUID)\n\
- lport-list <lswitch> List ports on a logical switch\n\
- lport-set-external-id <lport> <key> [value]\n\
- Set or delete an external:id on a logical port\n\
- lport-get-external-id <lport> [key]\n\
- List one or all external:ids set on a port\n\
- lport-set-macs <lport> [MAC] [MAC] [...]\n\
- Set MAC addresses for the logical port. Specify\n\
- more than one using additional arguments.\n\
- lport-get-macs <lport> Get a list of MAC addresses on the port.\n\
+Logical switch commands:\n\
+ lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\
+ lswitch-del LSWITCH delete LSWITCH and all its ports\n\
+ lswitch-list print the names of all logical switches\n\
+ lswitch-set-external-id LSWITCH KEY [VALUE]\n\
+ set or delete an external-id on LSWITCH\n\
+ lswitch-get-external-id LSWITCH [KEY]\n\
+ list one or all external-ids on LSWITCH\n\
+\n\
+Logical port commands:\n\
+ lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
+ lport-add LSWITCH LPORT PARENT TAG\n\
+ add logical port LPORT on LSWITCH with PARENT\n\
+ on TAG\n\
+ lport-del LPORT delete LPORT from its attached switch\n\
+ lport-list LSWITCH print the names of all logical ports on LSWITCH\n\
+ lport-get-parent LPORT get the parent of LPORT if set\n\
+ lport-get-tag LPORT get the LPORT's tag if set\n\
+ lport-set-external-id LPORT KEY [VALUE]\n\
+ set or delete an external-id on LPORT\n\
+ lport-get-external-id LPORT [KEY]\n\
+ list one or all external-ids on LPORT\n\
+ lport-set-macs LPORT [MAC]...\n\
+ set MAC addresses for LPORT.\n\
+ lport-get-macs LPORT get a list of MAC addresses on LPORT\n\
+ lport-set-port-security LPORT [ADDRS]...\n\
+ set port security addresses for LPORT.\n\
+ lport-get-port-security LPORT get LPORT's port security addresses\n\
+ lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
+ lport-set-enabled LPORT STATE\n\
+ set administrative state LPORT\n\
+ ('enabled' or 'disabled')\n\
+ lport-get-enabled LPORT get administrative state LPORT\n\
+ ('enabled' or 'disabled')\n\
+ lport-set-type LPORT TYPE Set the type for LPORT\n\
+ lport-get-type LPORT Get the type for LPORT\n\
+ lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
+ Set options related to the type of LPORT\n\
+ lport-get-options LPORT Get the type specific options for LPORT\n\
\n\
Options:\n\
--db=DATABASE connect to DATABASE\n\
return lswitch;
}
+static void
+print_lswitch(const struct nbrec_logical_switch *lswitch)
+{
+ printf(" 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);
+ if (lport->parent_name && lport->n_tag) {
+ printf(" parent: %s, tag:%"PRIu64"\n",
+ lport->parent_name, lport->tag[0]);
+ }
+ if (lport->n_macs) {
+ printf(" macs:");
+ for (size_t j = 0; j < lport->n_macs; j++) {
+ printf(" %s", lport->macs[j]);
+ }
+ printf("\n");
+ }
+ }
+}
+
+static void
+do_show(struct ovs_cmdl_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]);
+ if (lswitch) {
+ print_lswitch(lswitch);
+ }
+ } else {
+ NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
+ print_lswitch(lswitch);
+ }
+ }
+}
+
static void
do_lswitch_add(struct ovs_cmdl_context *ctx)
{
/* List one external ID */
value = smap_get(&lswitch->external_ids, key);
- if (value && *value) {
+ if (value) {
printf("%s\n", value);
- } else {
- printf("external-id '%s' is not set.\n", key);
}
} else {
struct smap_node *node;
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[2]);
+ lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
if (!lswitch) {
return;
}
+ if (ctx->argc != 3 && ctx->argc != 5) {
+ /* If a parent_name is specified, a tag must be specified as well. */
+ VLOG_WARN("Invalid arguments to lport-add.");
+ return;
+ }
+
+ if (ctx->argc == 5) {
+ /* Validate tag. */
+ if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
+ VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
+ return;
+ }
+ }
+
+ /* Create the logical port. */
lport = nbrec_logical_port_insert(nb_ctx->txn);
- nbrec_logical_port_set_name(lport, ctx->argv[1]);
- nbrec_logical_port_set_lswitch(lport, lswitch);
+ nbrec_logical_port_set_name(lport, ctx->argv[2]);
+ if (ctx->argc == 5) {
+ nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
+ nbrec_logical_port_set_tag(lport, &tag, 1);
+ }
+
+ /* Insert the logical port into the logical switch. */
+ nbrec_logical_switch_verify_ports(lswitch);
+ struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
+ (lswitch->n_ports + 1));
+ memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
+ new_ports[lswitch->n_ports] = lport;
+ nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
+ free(new_ports);
+}
+
+/* Removes lport 'lswitch->ports[idx]'. */
+static void
+remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
+{
+ const struct nbrec_logical_port *lport = lswitch->ports[idx];
+
+ /* First remove 'lport' from the array of ports. This is what will
+ * actually cause the logical port to be deleted when the transaction is
+ * sent to the database server (due to garbage collection). */
+ struct nbrec_logical_port **new_ports
+ = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
+ new_ports[idx] = new_ports[lswitch->n_ports - 1];
+ nbrec_logical_switch_verify_ports(lswitch);
+ nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
+ free(new_ports);
+
+ /* Delete 'lport' from the IDL. This won't have a real effect on the
+ * database server (the IDL will suppress it in fact) but it means that it
+ * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
+ nbrec_logical_port_delete(lport);
}
static void
return;
}
- nbrec_logical_port_delete(lport);
+ /* Find the switch that contains 'lport', then delete it. */
+ const struct nbrec_logical_switch *lswitch;
+ NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) {
+ for (size_t i = 0; i < lswitch->n_ports; i++) {
+ if (lswitch->ports[i] == lport) {
+ remove_lport(lswitch, i);
+ return;
+ }
+ }
+ }
+
+ VLOG_WARN("logical port %s is not part of any logical switch",
+ ctx->argv[1]);
}
-static bool
-is_lswitch(const struct nbrec_logical_switch *lswitch,
- struct uuid *lswitch_uuid, const char *name)
+static void
+do_lport_list(struct ovs_cmdl_context *ctx)
{
- if (lswitch_uuid) {
- return uuid_equals(lswitch_uuid, &lswitch->header_.uuid);
- } else {
- return !strcmp(lswitch->name, name);
+ 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);
+ if (!lswitch) {
+ return;
+ }
+
+ for (size_t i = 0; i < lswitch->n_ports; i++) {
+ const struct nbrec_logical_port *lport = lswitch->ports[i];
+ printf(UUID_FMT " (%s)\n",
+ UUID_ARGS(&lport->header_.uuid), lport->name);
}
}
+static void
+do_lport_get_parent(struct ovs_cmdl_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]);
+ if (!lport) {
+ return;
+ }
+
+ if (lport->parent_name) {
+ printf("%s\n", lport->parent_name);
+ }
+}
static void
-do_lport_list(struct ovs_cmdl_context *ctx)
+do_lport_get_tag(struct ovs_cmdl_context *ctx)
{
struct nbctl_context *nb_ctx = ctx->pvt;
- const char *id = ctx->argv[1];
const struct nbrec_logical_port *lport;
- bool is_uuid = false;
- struct uuid lswitch_uuid;
- if (uuid_from_string(&lswitch_uuid, id)) {
- is_uuid = true;
+ lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
+ if (!lport) {
+ return;
}
- NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
- bool match;
- if (is_uuid) {
- match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL);
- } else {
- match = is_lswitch(lport->lswitch, NULL, id);
- }
- if (!match) {
- continue;
- }
- printf(UUID_FMT " (%s)\n",
- UUID_ARGS(&lport->header_.uuid), lport->name);
+ if (lport->n_tag > 0) {
+ printf("%"PRId64"\n", lport->tag[0]);
}
}
/* List one external ID */
value = smap_get(&lport->external_ids, key);
- if (value && *value) {
+ if (value) {
printf("%s\n", value);
- } else {
- printf("external-id '%s' is not set.\n", key);
}
} else {
struct smap_node *node;
printf("%s\n", lport->macs[i]);
}
}
+
+static void
+do_lport_set_port_security(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ nbrec_logical_port_set_port_security(lport,
+ (const char **) ctx->argv + 2, ctx->argc - 2);
+}
+
+static void
+do_lport_get_port_security(struct ovs_cmdl_context *ctx)
+{
+ struct nbctl_context *nb_ctx = ctx->pvt;
+ const char *id = ctx->argv[1];
+ const struct nbrec_logical_port *lport;
+ size_t i;
+
+ lport = lport_by_name_or_uuid(nb_ctx, id);
+ if (!lport) {
+ return;
+ }
+
+ for (i = 0; i < lport->n_port_security; i++) {
+ printf("%s\n", lport->port_security[i]);
+ }
+}
+
+static void
+do_lport_get_up(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
+}
+
+static void
+do_lport_set_enabled(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ if (!strcasecmp(state, "enabled")) {
+ bool enabled = true;
+ nbrec_logical_port_set_enabled(lport, &enabled, 1);
+ } else if (!strcasecmp(state, "disabled")) {
+ bool enabled = false;
+ nbrec_logical_port_set_enabled(lport, &enabled, 1);
+ } else {
+ VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
+ }
+}
+
+static void
+do_lport_get_enabled(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ printf("%s\n",
+ (!lport->enabled || *lport->enabled) ? "enabled" : "disabled");
+}
+
+static void
+do_lport_set_type(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ nbrec_logical_port_set_type(lport, type);
+}
+
+static void
+do_lport_get_type(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ printf("%s\n", lport->type);
+}
+
+static void
+do_lport_set_options(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ for (i = 2; i < ctx->argc; i++) {
+ char *key, *value;
+ value = xstrdup(ctx->argv[i]);
+ key = strsep(&value, "=");
+ if (value) {
+ smap_add(&options, key, value);
+ }
+ free(key);
+ }
+
+ nbrec_logical_port_set_options(lport, &options);
+
+ smap_destroy(&options);
+}
+
+static void
+do_lport_get_options(struct ovs_cmdl_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);
+ if (!lport) {
+ return;
+ }
+
+ SMAP_FOR_EACH(node, &lport->options) {
+ printf("%s=%s\n", node->key, node->value);
+ }
+}
\f
static void
parse_options(int argc, char *argv[])
}
static const struct ovs_cmdl_command all_commands[] = {
+ {
+ .name = "show",
+ .usage = "[LSWITCH]",
+ .min_args = 0,
+ .max_args = 1,
+ .handler = do_show,
+ },
{
.name = "lswitch-add",
- .usage = "[lswitch]",
+ .usage = "[LSWITCH]",
.min_args = 0,
.max_args = 1,
.handler = do_lswitch_add,
},
{
.name = "lswitch-del",
- .usage = "<lswitch>",
+ .usage = "LSWITCH",
.min_args = 1,
.max_args = 1,
.handler = do_lswitch_del,
},
{
.name = "lswitch-set-external-id",
- .usage = "<lswitch> <key> [value]",
+ .usage = "LSWITCH KEY [VALUE]",
.min_args = 2,
.max_args = 3,
.handler = do_lswitch_set_external_id,
},
{
.name = "lswitch-get-external-id",
- .usage = "<lswitch> [key]",
+ .usage = "LSWITCH [KEY]",
.min_args = 1,
.max_args = 2,
.handler = do_lswitch_get_external_id,
},
{
.name = "lport-add",
- .usage = "<name> <lswitch>",
+ .usage = "LSWITCH LPORT [PARENT] [TAG]",
.min_args = 2,
- .max_args = 2,
+ .max_args = 4,
.handler = do_lport_add,
},
{
.name = "lport-del",
- .usage = "<lport>",
+ .usage = "LPORT",
.min_args = 1,
.max_args = 1,
.handler = do_lport_del,
},
{
.name = "lport-list",
- .usage = "<lswitch>",
+ .usage = "LSWITCH",
.min_args = 1,
.max_args = 1,
.handler = do_lport_list,
},
+ {
+ .name = "lport-get-parent",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_parent,
+ },
+ {
+ .name = "lport-get-tag",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_tag,
+ },
{
.name = "lport-set-external-id",
- .usage = "<lport> <key> [value]",
+ .usage = "LPORT KEY [VALUE]",
.min_args = 2,
.max_args = 3,
.handler = do_lport_set_external_id,
},
{
.name = "lport-get-external-id",
- .usage = "<lport> [key]",
+ .usage = "LPORT [KEY]",
.min_args = 1,
.max_args = 2,
.handler = do_lport_get_external_id,
},
{
.name = "lport-set-macs",
- .usage = "<lport> [MAC] [MAC] [...]",
+ .usage = "LPORT [MAC]...",
.min_args = 1,
/* Accept however many arguments the system will allow. */
.max_args = INT_MAX,
},
{
.name = "lport-get-macs",
- .usage = "<lport>",
+ .usage = "LPORT",
.min_args = 1,
.max_args = 1,
.handler = do_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 = do_lport_set_port_security,
+ },
+ {
+ .name = "lport-get-port-security",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_port_security,
+ },
+ {
+ .name = "lport-get-up",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_up,
+ },
+ {
+ .name = "lport-set-enabled",
+ .usage = "LPORT STATE",
+ .min_args = 2,
+ .max_args = 2,
+ .handler = do_lport_set_enabled,
+ },
+ {
+ .name = "lport-get-enabled",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_enabled,
+ },
+ {
+ .name = "lport-set-type",
+ .usage = "LPORT TYPE",
+ .min_args = 2,
+ .max_args = 2,
+ .handler = do_lport_set_type,
+ },
+ {
+ .name = "lport-get-type",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_type,
+ },
+ {
+ .name = "lport-set-options",
+ .usage = "LPORT KEY=VALUE [KEY=VALUE]...",
+ .min_args = 1,
+ .max_args = INT_MAX,
+ .handler = do_lport_set_options
+ },
+ {
+ .name = "lport-get-options",
+ .usage = "LPORT",
+ .min_args = 1,
+ .max_args = 1,
+ .handler = do_lport_get_options,
+ },
{
/* sentinel */
{
static char *def;
if (!def) {
- def = xasprintf("unix:%s/db.sock", ovs_rundir());
+ def = getenv("OVN_NB_DB");
+ if (!def) {
+ def = xasprintf("unix:%s/db.sock", ovs_rundir());
+ }
}
return def;
}
enum ovsdb_idl_txn_status txn_status;
unsigned int seqno;
int res = 0;
+ char *args;
fatal_ignore_sigpipe();
set_program_name(argv[0]);
parse_options(argc, argv);
nbrec_init();
+ args = process_escape_args(argv);
+
nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
ctx.pvt = &nb_ctx;
ctx.argc = argc - optind;
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);
}
ovsdb_idl_destroy(nb_ctx.idl);
+ free(args);
exit(res);
}