2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at:
6 * http://www.apache.org/licenses/LICENSE-2.0
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
22 #include "command-line.h"
23 #include "db-ctl-base.h"
25 #include "fatal-signal.h"
27 #include "ovn/lib/ovn-nb-idl.h"
28 #include "poll-loop.h"
32 #include "stream-ssl.h"
37 #include "openvswitch/vlog.h"
39 VLOG_DEFINE_THIS_MODULE(nbctl);
41 /* --db: The database server to contact. */
42 static const char *db;
44 /* --oneline: Write each command's output as a single line? */
47 /* --dry-run: Do not commit any changes. */
50 /* --timeout: Time to wait for a connection to 'db'. */
53 /* Format for table output. */
54 static struct table_style table_style = TABLE_STYLE_DEFAULT;
56 /* The IDL we're using and the current transaction, if any.
57 * This is for use by nbctl_exit() only, to allow it to clean up.
58 * Other code should use its context arguments. */
59 static struct ovsdb_idl *the_idl;
60 static struct ovsdb_idl_txn *the_idl_txn;
61 OVS_NO_RETURN static void nbctl_exit(int status);
63 static void nbctl_cmd_init(void);
64 OVS_NO_RETURN static void usage(void);
65 static void parse_options(int argc, char *argv[], struct shash *local_options);
66 static const char *nbctl_default_db(void);
67 static void run_prerequisites(struct ctl_command[], size_t n_commands,
69 static void do_nbctl(const char *args, struct ctl_command *, size_t n,
73 main(int argc, char *argv[])
75 extern struct vlog_module VLM_reconnect;
76 struct ovsdb_idl *idl;
77 struct ctl_command *commands;
78 struct shash local_options;
83 set_program_name(argv[0]);
84 fatal_ignore_sigpipe();
85 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
86 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
91 /* Log our arguments. This is often valuable for debugging systems. */
92 args = process_escape_args(argv);
93 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
94 "Called as %s", args);
96 /* Parse command line. */
97 shash_init(&local_options);
98 parse_options(argc, argv, &local_options);
99 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
106 /* Initialize IDL. */
107 idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
108 run_prerequisites(commands, n_commands, idl);
110 /* Execute the commands.
112 * 'seqno' is the database sequence number for which we last tried to
113 * execute our transaction. There's no point in trying to commit more than
114 * once for any given sequence number, because if the transaction fails
115 * it's because the database changed and we need to obtain an up-to-date
116 * view of the database before we try the transaction again. */
117 seqno = ovsdb_idl_get_seqno(idl);
120 if (!ovsdb_idl_is_alive(idl)) {
121 int retval = ovsdb_idl_get_last_error(idl);
122 ctl_fatal("%s: database connection failed (%s)",
123 db, ovs_retval_to_string(retval));
126 if (seqno != ovsdb_idl_get_seqno(idl)) {
127 seqno = ovsdb_idl_get_seqno(idl);
128 do_nbctl(args, commands, n_commands, idl);
131 if (seqno == ovsdb_idl_get_seqno(idl)) {
139 nbctl_default_db(void)
143 def = getenv("OVN_NB_DB");
145 def = xasprintf("unix:%s/db.sock", ovs_rundir());
152 parse_options(int argc, char *argv[], struct shash *local_options)
155 OPT_DB = UCHAR_MAX + 1,
165 static const struct option global_long_options[] = {
166 {"db", required_argument, NULL, OPT_DB},
167 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
168 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
169 {"oneline", no_argument, NULL, OPT_ONELINE},
170 {"timeout", required_argument, NULL, 't'},
171 {"help", no_argument, NULL, 'h'},
172 {"commands", no_argument, NULL, OPT_COMMANDS},
173 {"options", no_argument, NULL, OPT_OPTIONS},
174 {"version", no_argument, NULL, 'V'},
176 STREAM_SSL_LONG_OPTIONS,
180 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
181 char *tmp, *short_options;
183 struct option *options;
184 size_t allocated_options;
188 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
189 short_options = xasprintf("+%s", tmp);
192 /* We want to parse both global and command-specific options here, but
193 * getopt_long() isn't too convenient for the job. We copy our global
194 * options into a dynamic array, then append all of the command-specific
196 options = xmemdup(global_long_options, sizeof global_long_options);
197 allocated_options = ARRAY_SIZE(global_long_options);
198 n_options = n_global_long_options;
199 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
200 table_style.format = TF_LIST;
206 c = getopt_long(argc, argv, short_options, options, &idx);
221 vlog_set_levels(&VLM_nbctl, VLF_SYSLOG, VLL_WARN);
229 if (shash_find(local_options, options[idx].name)) {
230 ctl_fatal("'%s' option specified multiple times",
233 shash_add_nocopy(local_options,
234 xasprintf("--%s", options[idx].name),
235 optarg ? xstrdup(optarg) : NULL);
243 ctl_print_commands();
246 ctl_print_options(global_long_options);
249 ovs_print_version(0, 0);
250 printf("DB Schema %s\n", nbrec_get_db_version());
254 timeout = strtoul(optarg, NULL, 10);
256 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
261 TABLE_OPTION_HANDLERS(&table_style)
262 STREAM_SSL_OPTION_HANDLERS
273 db = nbctl_default_db();
276 for (i = n_global_long_options; options[i].name; i++) {
277 free(CONST_CAST(char *, options[i].name));
286 %s: OVN northbound DB management utility\n\
287 usage: %s [OPTIONS] COMMAND [ARG...]\n\
290 show print overview of database contents\n\
291 show LSWITCH print overview of database contents for LSWITCH\n\
293 Logical switch commands:\n\
294 lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\
295 lswitch-del LSWITCH delete LSWITCH and all its ports\n\
296 lswitch-list print the names of all logical switches\n\
297 lswitch-set-external-id LSWITCH KEY [VALUE]\n\
298 set or delete an external-id on LSWITCH\n\
299 lswitch-get-external-id LSWITCH [KEY]\n\
300 list one or all external-ids on LSWITCH\n\
303 acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
304 add an ACL to LSWITCH\n\
305 acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\
306 remove ACLs from LSWITCH\n\
307 acl-list LSWITCH print ACLs for LSWITCH\n\
309 Logical port commands:\n\
310 lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
311 lport-add LSWITCH LPORT PARENT TAG\n\
312 add logical port LPORT on LSWITCH with PARENT\n\
314 lport-del LPORT delete LPORT from its attached switch\n\
315 lport-list LSWITCH print the names of all logical ports on LSWITCH\n\
316 lport-get-parent LPORT get the parent of LPORT if set\n\
317 lport-get-tag LPORT get the LPORT's tag if set\n\
318 lport-set-external-id LPORT KEY [VALUE]\n\
319 set or delete an external-id on LPORT\n\
320 lport-get-external-id LPORT [KEY]\n\
321 list one or all external-ids on LPORT\n\
322 lport-set-macs LPORT [MAC]...\n\
323 set MAC addresses for LPORT.\n\
324 lport-get-macs LPORT get a list of MAC addresses on LPORT\n\
325 lport-set-port-security LPORT [ADDRS]...\n\
326 set port security addresses for LPORT.\n\
327 lport-get-port-security LPORT get LPORT's port security addresses\n\
328 lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
329 lport-set-enabled LPORT STATE\n\
330 set administrative state LPORT\n\
331 ('enabled' or 'disabled')\n\
332 lport-get-enabled LPORT get administrative state LPORT\n\
333 ('enabled' or 'disabled')\n\
334 lport-set-type LPORT TYPE Set the type for LPORT\n\
335 lport-get-type LPORT Get the type for LPORT\n\
336 lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
337 Set options related to the type of LPORT\n\
338 lport-get-options LPORT Get the type specific options for LPORT\n\
341 --db=DATABASE connect to DATABASE\n\
343 -t, --timeout=SECS wait at most SECS seconds\n\
344 --dry-run do not commit changes to database\n\
345 --oneline print exactly one line of output per command\n",
346 program_name, program_name, nbctl_default_db());
349 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
352 -h, --help display this help message\n\
353 -V, --version display version information\n");
357 static const struct nbrec_logical_switch *
358 lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id)
360 const struct nbrec_logical_switch *lswitch = NULL;
361 bool is_uuid = false;
362 bool duplicate = false;
363 struct uuid lswitch_uuid;
365 if (uuid_from_string(&lswitch_uuid, id)) {
367 lswitch = nbrec_logical_switch_get_for_uuid(ctx->idl,
372 const struct nbrec_logical_switch *iter;
374 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
375 if (strcmp(iter->name, id)) {
379 VLOG_WARN("There is more than one logical switch named '%s'. "
389 if (!lswitch && !duplicate) {
390 VLOG_WARN("lswitch not found for %s: '%s'",
391 is_uuid ? "UUID" : "name", id);
398 print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s)
400 ds_put_format(s, " lswitch "UUID_FMT" (%s)\n",
401 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
403 for (size_t i = 0; i < lswitch->n_ports; i++) {
404 const struct nbrec_logical_port *lport = lswitch->ports[i];
406 ds_put_format(s, " lport %s\n", lport->name);
407 if (lport->parent_name && lport->n_tag) {
408 ds_put_format(s, " parent: %s, tag:%"PRIu64"\n",
409 lport->parent_name, lport->tag[0]);
412 ds_put_cstr(s, " macs:");
413 for (size_t j = 0; j < lport->n_macs; j++) {
414 ds_put_format(s, " %s", lport->macs[j]);
416 ds_put_char(s, '\n');
422 nbctl_show(struct ctl_context *ctx)
424 const struct nbrec_logical_switch *lswitch;
426 if (ctx->argc == 2) {
427 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
429 print_lswitch(lswitch, &ctx->output);
432 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
433 print_lswitch(lswitch, &ctx->output);
439 nbctl_lswitch_add(struct ctl_context *ctx)
441 struct nbrec_logical_switch *lswitch;
443 lswitch = nbrec_logical_switch_insert(ctx->txn);
444 if (ctx->argc == 2) {
445 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
450 nbctl_lswitch_del(struct ctl_context *ctx)
452 const char *id = ctx->argv[1];
453 const struct nbrec_logical_switch *lswitch;
455 lswitch = lswitch_by_name_or_uuid(ctx, id);
460 nbrec_logical_switch_delete(lswitch);
464 nbctl_lswitch_list(struct ctl_context *ctx)
466 const struct nbrec_logical_switch *lswitch;
467 struct smap lswitches;
469 smap_init(&lswitches);
470 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
471 smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
472 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
474 const struct smap_node **nodes = smap_sort(&lswitches);
475 for (size_t i = 0; i < smap_count(&lswitches); i++) {
476 const struct smap_node *node = nodes[i];
477 ds_put_format(&ctx->output, "%s\n", node->value);
479 smap_destroy(&lswitches);
484 nbctl_lswitch_set_external_id(struct ctl_context *ctx)
486 const char *id = ctx->argv[1];
487 const struct nbrec_logical_switch *lswitch;
488 struct smap new_external_ids;
490 lswitch = lswitch_by_name_or_uuid(ctx, id);
495 smap_init(&new_external_ids);
496 smap_clone(&new_external_ids, &lswitch->external_ids);
497 if (ctx->argc == 4) {
498 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
500 smap_remove(&new_external_ids, ctx->argv[2]);
502 nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
503 smap_destroy(&new_external_ids);
507 nbctl_lswitch_get_external_id(struct ctl_context *ctx)
509 const char *id = ctx->argv[1];
510 const struct nbrec_logical_switch *lswitch;
512 lswitch = lswitch_by_name_or_uuid(ctx, id);
517 if (ctx->argc == 3) {
518 const char *key = ctx->argv[2];
521 /* List one external ID */
523 value = smap_get(&lswitch->external_ids, key);
525 ds_put_format(&ctx->output, "%s\n", value);
528 struct smap_node *node;
530 /* List all external IDs */
532 SMAP_FOR_EACH(node, &lswitch->external_ids) {
533 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
538 static const struct nbrec_logical_port *
539 lport_by_name_or_uuid(struct ctl_context *ctx, const char *id)
541 const struct nbrec_logical_port *lport = NULL;
542 bool is_uuid = false;
543 struct uuid lport_uuid;
545 if (uuid_from_string(&lport_uuid, id)) {
547 lport = nbrec_logical_port_get_for_uuid(ctx->idl, &lport_uuid);
551 NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->idl) {
552 if (!strcmp(lport->name, id)) {
559 VLOG_WARN("lport not found for %s: '%s'",
560 is_uuid ? "UUID" : "name", id);
567 nbctl_lport_add(struct ctl_context *ctx)
569 struct nbrec_logical_port *lport;
570 const struct nbrec_logical_switch *lswitch;
573 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
578 if (ctx->argc != 3 && ctx->argc != 5) {
579 /* If a parent_name is specified, a tag must be specified as well. */
580 VLOG_WARN("Invalid arguments to lport-add.");
584 if (ctx->argc == 5) {
586 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
587 VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
592 /* Create the logical port. */
593 lport = nbrec_logical_port_insert(ctx->txn);
594 nbrec_logical_port_set_name(lport, ctx->argv[2]);
595 if (ctx->argc == 5) {
596 nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
597 nbrec_logical_port_set_tag(lport, &tag, 1);
600 /* Insert the logical port into the logical switch. */
601 nbrec_logical_switch_verify_ports(lswitch);
602 struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
603 (lswitch->n_ports + 1));
604 memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
605 new_ports[lswitch->n_ports] = lport;
606 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
610 /* Removes lport 'lswitch->ports[idx]'. */
612 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
614 const struct nbrec_logical_port *lport = lswitch->ports[idx];
616 /* First remove 'lport' from the array of ports. This is what will
617 * actually cause the logical port to be deleted when the transaction is
618 * sent to the database server (due to garbage collection). */
619 struct nbrec_logical_port **new_ports
620 = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
621 new_ports[idx] = new_ports[lswitch->n_ports - 1];
622 nbrec_logical_switch_verify_ports(lswitch);
623 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
626 /* Delete 'lport' from the IDL. This won't have a real effect on the
627 * database server (the IDL will suppress it in fact) but it means that it
628 * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
629 nbrec_logical_port_delete(lport);
633 nbctl_lport_del(struct ctl_context *ctx)
635 const struct nbrec_logical_port *lport;
637 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
642 /* Find the switch that contains 'lport', then delete it. */
643 const struct nbrec_logical_switch *lswitch;
644 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
645 for (size_t i = 0; i < lswitch->n_ports; i++) {
646 if (lswitch->ports[i] == lport) {
647 remove_lport(lswitch, i);
653 VLOG_WARN("logical port %s is not part of any logical switch",
658 nbctl_lport_list(struct ctl_context *ctx)
660 const char *id = ctx->argv[1];
661 const struct nbrec_logical_switch *lswitch;
665 lswitch = lswitch_by_name_or_uuid(ctx, id);
671 for (i = 0; i < lswitch->n_ports; i++) {
672 const struct nbrec_logical_port *lport = lswitch->ports[i];
673 smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
674 UUID_ARGS(&lport->header_.uuid), lport->name);
676 const struct smap_node **nodes = smap_sort(&lports);
677 for (i = 0; i < smap_count(&lports); i++) {
678 const struct smap_node *node = nodes[i];
679 ds_put_format(&ctx->output, "%s\n", node->value);
681 smap_destroy(&lports);
686 nbctl_lport_get_parent(struct ctl_context *ctx)
688 const struct nbrec_logical_port *lport;
690 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
695 if (lport->parent_name) {
696 ds_put_format(&ctx->output, "%s\n", lport->parent_name);
701 nbctl_lport_get_tag(struct ctl_context *ctx)
703 const struct nbrec_logical_port *lport;
705 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
710 if (lport->n_tag > 0) {
711 ds_put_format(&ctx->output, "%"PRId64"\n", lport->tag[0]);
716 nbctl_lport_set_external_id(struct ctl_context *ctx)
718 const char *id = ctx->argv[1];
719 const struct nbrec_logical_port *lport;
720 struct smap new_external_ids;
722 lport = lport_by_name_or_uuid(ctx, id);
727 smap_init(&new_external_ids);
728 smap_clone(&new_external_ids, &lport->external_ids);
729 if (ctx->argc == 4) {
730 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
732 smap_remove(&new_external_ids, ctx->argv[2]);
734 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
735 smap_destroy(&new_external_ids);
739 nbctl_lport_get_external_id(struct ctl_context *ctx)
741 const char *id = ctx->argv[1];
742 const struct nbrec_logical_port *lport;
744 lport = lport_by_name_or_uuid(ctx, id);
749 if (ctx->argc == 3) {
750 const char *key = ctx->argv[2];
753 /* List one external ID */
755 value = smap_get(&lport->external_ids, key);
757 ds_put_format(&ctx->output, "%s\n", value);
760 struct smap_node *node;
762 /* List all external IDs */
764 SMAP_FOR_EACH(node, &lport->external_ids) {
765 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
771 nbctl_lport_set_macs(struct ctl_context *ctx)
773 const char *id = ctx->argv[1];
774 const struct nbrec_logical_port *lport;
776 lport = lport_by_name_or_uuid(ctx, id);
781 nbrec_logical_port_set_macs(lport,
782 (const char **) ctx->argv + 2, ctx->argc - 2);
786 nbctl_lport_get_macs(struct ctl_context *ctx)
788 const char *id = ctx->argv[1];
789 const struct nbrec_logical_port *lport;
794 lport = lport_by_name_or_uuid(ctx, id);
800 for (i = 0; i < lport->n_macs; i++) {
801 svec_add(&macs, lport->macs[i]);
804 SVEC_FOR_EACH(i, mac, &macs) {
805 ds_put_format(&ctx->output, "%s\n", mac);
811 nbctl_lport_set_port_security(struct ctl_context *ctx)
813 const char *id = ctx->argv[1];
814 const struct nbrec_logical_port *lport;
816 lport = lport_by_name_or_uuid(ctx, id);
821 nbrec_logical_port_set_port_security(lport,
822 (const char **) ctx->argv + 2, ctx->argc - 2);
826 nbctl_lport_get_port_security(struct ctl_context *ctx)
828 const char *id = ctx->argv[1];
829 const struct nbrec_logical_port *lport;
834 lport = lport_by_name_or_uuid(ctx, id);
840 for (i = 0; i < lport->n_port_security; i++) {
841 svec_add(&addrs, lport->port_security[i]);
844 SVEC_FOR_EACH(i, addr, &addrs) {
845 ds_put_format(&ctx->output, "%s\n", addr);
847 svec_destroy(&addrs);
851 nbctl_lport_get_up(struct ctl_context *ctx)
853 const char *id = ctx->argv[1];
854 const struct nbrec_logical_port *lport;
856 lport = lport_by_name_or_uuid(ctx, id);
861 ds_put_format(&ctx->output,
862 "%s\n", (lport->up && *lport->up) ? "up" : "down");
866 nbctl_lport_set_enabled(struct ctl_context *ctx)
868 const char *id = ctx->argv[1];
869 const char *state = ctx->argv[2];
870 const struct nbrec_logical_port *lport;
872 lport = lport_by_name_or_uuid(ctx, id);
877 if (!strcasecmp(state, "enabled")) {
879 nbrec_logical_port_set_enabled(lport, &enabled, 1);
880 } else if (!strcasecmp(state, "disabled")) {
881 bool enabled = false;
882 nbrec_logical_port_set_enabled(lport, &enabled, 1);
884 VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
889 nbctl_lport_get_enabled(struct ctl_context *ctx)
891 const char *id = ctx->argv[1];
892 const struct nbrec_logical_port *lport;
894 lport = lport_by_name_or_uuid(ctx, id);
899 ds_put_format(&ctx->output, "%s\n",
900 !lport->enabled || *lport->enabled ? "enabled" : "disabled");
904 nbctl_lport_set_type(struct ctl_context *ctx)
906 const char *id = ctx->argv[1];
907 const char *type = ctx->argv[2];
908 const struct nbrec_logical_port *lport;
910 lport = lport_by_name_or_uuid(ctx, id);
915 nbrec_logical_port_set_type(lport, type);
919 nbctl_lport_get_type(struct ctl_context *ctx)
921 const char *id = ctx->argv[1];
922 const struct nbrec_logical_port *lport;
924 lport = lport_by_name_or_uuid(ctx, id);
929 ds_put_format(&ctx->output, "%s\n", lport->type);
933 nbctl_lport_set_options(struct ctl_context *ctx)
935 const char *id = ctx->argv[1];
936 const struct nbrec_logical_port *lport;
938 struct smap options = SMAP_INITIALIZER(&options);
940 lport = lport_by_name_or_uuid(ctx, id);
945 for (i = 2; i < ctx->argc; i++) {
947 value = xstrdup(ctx->argv[i]);
948 key = strsep(&value, "=");
950 smap_add(&options, key, value);
955 nbrec_logical_port_set_options(lport, &options);
957 smap_destroy(&options);
961 nbctl_lport_get_options(struct ctl_context *ctx)
963 const char *id = ctx->argv[1];
964 const struct nbrec_logical_port *lport;
965 struct smap_node *node;
967 lport = lport_by_name_or_uuid(ctx, id);
972 SMAP_FOR_EACH(node, &lport->options) {
973 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
983 dir_encode(const char *dir)
985 if (!strcmp(dir, "from-lport")) {
986 return DIR_FROM_LPORT;
987 } else if (!strcmp(dir, "to-lport")) {
995 acl_cmp(const void *acl1_, const void *acl2_)
997 const struct nbrec_acl *const *acl1p = acl1_;
998 const struct nbrec_acl *const *acl2p = acl2_;
999 const struct nbrec_acl *acl1 = *acl1p;
1000 const struct nbrec_acl *acl2 = *acl2p;
1002 int dir1 = dir_encode(acl1->direction);
1003 int dir2 = dir_encode(acl2->direction);
1006 return dir1 < dir2 ? -1 : 1;
1007 } else if (acl1->priority != acl2->priority) {
1008 return acl1->priority > acl2->priority ? -1 : 1;
1010 return strcmp(acl1->match, acl2->match);
1015 nbctl_acl_list(struct ctl_context *ctx)
1017 const struct nbrec_logical_switch *lswitch;
1018 const struct nbrec_acl **acls;
1021 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
1026 acls = xmalloc(sizeof *acls * lswitch->n_acls);
1027 for (i = 0; i < lswitch->n_acls; i++) {
1028 acls[i] = lswitch->acls[i];
1031 qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
1033 for (i = 0; i < lswitch->n_acls; i++) {
1034 const struct nbrec_acl *acl = acls[i];
1035 printf("%10s %5"PRId64" (%s) %s%s\n", acl->direction, acl->priority,
1036 acl->match, acl->action, acl->log ? " log" : "");
1043 nbctl_acl_add(struct ctl_context *ctx)
1045 const struct nbrec_logical_switch *lswitch;
1046 const char *action = ctx->argv[5];
1047 const char *direction;
1050 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
1055 /* Validate direction. Only require the first letter. */
1056 if (ctx->argv[2][0] == 't') {
1057 direction = "to-lport";
1058 } else if (ctx->argv[2][0] == 'f') {
1059 direction = "from-lport";
1061 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
1065 /* Validate priority. */
1066 if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
1067 || priority > 65535) {
1068 VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
1072 /* Validate action. */
1073 if (strcmp(action, "allow") && strcmp(action, "allow-related")
1074 && strcmp(action, "drop") && strcmp(action, "reject")) {
1075 VLOG_WARN("Invalid action '%s'", action);
1079 /* Create the acl. */
1080 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1081 nbrec_acl_set_priority(acl, priority);
1082 nbrec_acl_set_direction(acl, direction);
1083 nbrec_acl_set_match(acl, ctx->argv[4]);
1084 nbrec_acl_set_action(acl, action);
1085 if (shash_find(&ctx->options, "--log") != NULL) {
1086 nbrec_acl_set_log(acl, true);
1089 /* Insert the acl into the logical switch. */
1090 nbrec_logical_switch_verify_acls(lswitch);
1091 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls *
1092 (lswitch->n_acls + 1));
1093 memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1094 new_acls[lswitch->n_acls] = acl;
1095 nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1);
1100 nbctl_acl_del(struct ctl_context *ctx)
1102 const struct nbrec_logical_switch *lswitch;
1103 const char *direction;
1104 int64_t priority = 0;
1106 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
1111 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1112 VLOG_WARN("Invalid number of arguments");
1116 if (ctx->argc == 2) {
1117 /* If direction, priority, and match are not specified, delete
1119 nbrec_logical_switch_verify_acls(lswitch);
1120 nbrec_logical_switch_set_acls(lswitch, NULL, 0);
1124 /* Validate direction. Only require first letter. */
1125 if (ctx->argv[2][0] == 't') {
1126 direction = "to-lport";
1127 } else if (ctx->argv[2][0] == 'f') {
1128 direction = "from-lport";
1130 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
1134 /* If priority and match are not specified, delete all ACLs with the
1135 * specified direction. */
1136 if (ctx->argc == 3) {
1137 struct nbrec_acl **new_acls
1138 = xmalloc(sizeof *new_acls * lswitch->n_acls);
1141 for (size_t i = 0; i < lswitch->n_acls; i++) {
1142 if (strcmp(direction, lswitch->acls[i]->direction)) {
1143 new_acls[n_acls++] = lswitch->acls[i];
1147 nbrec_logical_switch_verify_acls(lswitch);
1148 nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
1153 /* Validate priority. */
1154 if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
1155 || priority > 65535) {
1156 VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
1160 /* Remove the matching rule. */
1161 for (size_t i = 0; i < lswitch->n_acls; i++) {
1162 struct nbrec_acl *acl = lswitch->acls[i];
1164 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1165 !strcmp(direction, acl->direction)) {
1166 struct nbrec_acl **new_acls
1167 = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1168 new_acls[i] = lswitch->acls[lswitch->n_acls - 1];
1169 nbrec_logical_switch_verify_acls(lswitch);
1170 nbrec_logical_switch_set_acls(lswitch, new_acls,
1171 lswitch->n_acls - 1);
1178 static const struct ctl_table_class tables[] = {
1179 {&nbrec_table_logical_switch,
1180 {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
1181 {NULL, NULL, NULL}}},
1183 {&nbrec_table_logical_port,
1184 {{&nbrec_table_logical_port, &nbrec_logical_port_col_name, NULL},
1185 {NULL, NULL, NULL}}},
1188 {{NULL, NULL, NULL},
1189 {NULL, NULL, NULL}}},
1191 {&nbrec_table_logical_router,
1192 {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
1193 {NULL, NULL, NULL}}},
1195 {&nbrec_table_logical_router_port,
1196 {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
1198 {NULL, NULL, NULL}}},
1200 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
1204 run_prerequisites(struct ctl_command *commands, size_t n_commands,
1205 struct ovsdb_idl *idl)
1207 struct ctl_command *c;
1209 for (c = commands; c < &commands[n_commands]; c++) {
1210 if (c->syntax->prerequisites) {
1211 struct ctl_context ctx;
1213 ds_init(&c->output);
1216 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
1217 (c->syntax->prerequisites)(&ctx);
1218 ctl_context_done(&ctx, c);
1220 ovs_assert(!c->output.string);
1221 ovs_assert(!c->table);
1227 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
1228 struct ovsdb_idl *idl)
1230 struct ovsdb_idl_txn *txn;
1231 enum ovsdb_idl_txn_status status;
1232 struct ovsdb_symbol_table *symtab;
1233 struct ctl_context ctx;
1234 struct ctl_command *c;
1235 struct shash_node *node;
1238 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
1240 ovsdb_idl_txn_set_dry_run(txn);
1243 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
1245 symtab = ovsdb_symbol_table_create();
1246 for (c = commands; c < &commands[n_commands]; c++) {
1247 ds_init(&c->output);
1250 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
1251 for (c = commands; c < &commands[n_commands]; c++) {
1252 ctl_context_init_command(&ctx, c);
1253 if (c->syntax->run) {
1254 (c->syntax->run)(&ctx);
1256 ctl_context_done_command(&ctx, c);
1258 if (ctx.try_again) {
1259 ctl_context_done(&ctx, NULL);
1263 ctl_context_done(&ctx, NULL);
1265 SHASH_FOR_EACH (node, &symtab->sh) {
1266 struct ovsdb_symbol *symbol = node->data;
1267 if (!symbol->created) {
1268 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
1269 "with \"-- --id=%s create ...\")",
1270 node->name, node->name);
1272 if (!symbol->strong_ref) {
1273 if (!symbol->weak_ref) {
1274 VLOG_WARN("row id \"%s\" was created but no reference to it "
1275 "was inserted, so it will not actually appear in "
1276 "the database", node->name);
1278 VLOG_WARN("row id \"%s\" was created but only a weak "
1279 "reference to it was inserted, so it will not "
1280 "actually appear in the database", node->name);
1285 status = ovsdb_idl_txn_commit_block(txn);
1286 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
1287 for (c = commands; c < &commands[n_commands]; c++) {
1288 if (c->syntax->postprocess) {
1289 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
1290 (c->syntax->postprocess)(&ctx);
1291 ctl_context_done(&ctx, c);
1295 error = xstrdup(ovsdb_idl_txn_get_error(txn));
1298 case TXN_UNCOMMITTED:
1299 case TXN_INCOMPLETE:
1303 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1304 ctl_fatal("transaction aborted");
1314 ctl_fatal("transaction error: %s", error);
1316 case TXN_NOT_LOCKED:
1317 /* Should not happen--we never call ovsdb_idl_set_lock(). */
1318 ctl_fatal("database not locked");
1325 ovsdb_symbol_table_destroy(symtab);
1327 for (c = commands; c < &commands[n_commands]; c++) {
1328 struct ds *ds = &c->output;
1331 table_print(c->table, &table_style);
1332 } else if (oneline) {
1336 for (j = 0; j < ds->length; j++) {
1337 int ch = ds->string[j];
1340 fputs("\\n", stdout);
1344 fputs("\\\\", stdout);
1353 fputs(ds_cstr(ds), stdout);
1355 ds_destroy(&c->output);
1356 table_destroy(c->table);
1359 shash_destroy_free_data(&c->options);
1362 ovsdb_idl_txn_destroy(txn);
1363 ovsdb_idl_destroy(idl);
1368 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
1369 * resources and return so that the caller can try again. */
1371 ovsdb_idl_txn_abort(txn);
1372 ovsdb_idl_txn_destroy(txn);
1375 ovsdb_symbol_table_destroy(symtab);
1376 for (c = commands; c < &commands[n_commands]; c++) {
1377 ds_destroy(&c->output);
1378 table_destroy(c->table);
1384 /* Frees the current transaction and the underlying IDL and then calls
1387 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1388 * for a clean memory leak report from valgrind in the normal case. That makes
1389 * it easier to notice real memory leaks. */
1391 nbctl_exit(int status)
1394 ovsdb_idl_txn_abort(the_idl_txn);
1395 ovsdb_idl_txn_destroy(the_idl_txn);
1397 ovsdb_idl_destroy(the_idl);
1401 static const struct ctl_command_syntax nbctl_commands[] = {
1402 { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO },
1404 /* lswitch commands. */
1405 { "lswitch-add", 0, 1, "[LSWITCH]", NULL, nbctl_lswitch_add,
1407 { "lswitch-del", 1, 1, "LSWITCH", NULL, nbctl_lswitch_del,
1409 { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO },
1410 { "lswitch-set-external-id", 2, 3, "LSWITCH KEY [VALUE]", NULL,
1411 nbctl_lswitch_set_external_id, NULL, "", RW },
1412 { "lswitch-get-external-id", 1, 2, "LSWITCH [KEY]", NULL,
1413 nbctl_lswitch_get_external_id, NULL, "", RO },
1416 { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
1417 nbctl_acl_add, NULL, "--log", RW },
1418 { "acl-del", 1, 4, "LSWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
1419 nbctl_acl_del, NULL, "", RW },
1420 { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO },
1422 /* lport commands. */
1423 { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, nbctl_lport_add,
1425 { "lport-del", 1, 1, "LPORT", NULL, nbctl_lport_del, NULL, "", RO },
1426 { "lport-list", 1, 1, "LSWITCH", NULL, nbctl_lport_list, NULL, "", RO },
1427 { "lport-get-parent", 1, 1, "LPORT", NULL, nbctl_lport_get_parent, NULL,
1429 { "lport-get-tag", 1, 1, "LPORT", NULL, nbctl_lport_get_tag, NULL, "",
1431 { "lport-set-external-id", 2, 3, "LPORT KEY [VALUE]", NULL,
1432 nbctl_lport_set_external_id, NULL, "", RW },
1433 { "lport-get-external-id", 1, 2, "LPORT [KEY]", NULL,
1434 nbctl_lport_get_external_id, NULL, "", RO },
1435 { "lport-set-macs", 1, INT_MAX, "LPORT [MAC]...", NULL,
1436 nbctl_lport_set_macs, NULL, "", RW },
1437 { "lport-get-macs", 1, 1, "LPORT", NULL, nbctl_lport_get_macs, NULL,
1439 { "lport-set-port-security", 0, INT_MAX, "LPORT [ADDRS]...", NULL,
1440 nbctl_lport_set_port_security, NULL, "", RW },
1441 { "lport-get-port-security", 1, 1, "LPORT", NULL,
1442 nbctl_lport_get_port_security, NULL, "", RO },
1443 { "lport-get-up", 1, 1, "LPORT", NULL, nbctl_lport_get_up, NULL, "", RO },
1444 { "lport-set-enabled", 2, 2, "LPORT STATE", NULL, nbctl_lport_set_enabled,
1446 { "lport-get-enabled", 1, 1, "LPORT", NULL, nbctl_lport_get_enabled, NULL,
1448 { "lport-set-type", 2, 2, "LPORT TYPE", NULL, nbctl_lport_set_type, NULL,
1450 { "lport-get-type", 1, 1, "LPORT", NULL, nbctl_lport_get_type, NULL, "",
1452 { "lport-set-options", 1, INT_MAX, "LPORT KEY=VALUE [KEY=VALUE]...", NULL,
1453 nbctl_lport_set_options, NULL, "", RW },
1454 { "lport-get-options", 1, 1, "LPORT", NULL, nbctl_lport_get_options, NULL,
1457 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
1460 /* Registers nbctl and common db commands. */
1462 nbctl_cmd_init(void)
1464 ctl_init(tables, NULL, nbctl_exit);
1465 ctl_register_commands(nbctl_commands);