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"
29 #include "poll-loop.h"
33 #include "stream-ssl.h"
38 #include "openvswitch/vlog.h"
40 VLOG_DEFINE_THIS_MODULE(nbctl);
42 /* --db: The database server to contact. */
43 static const char *db;
45 /* --oneline: Write each command's output as a single line? */
48 /* --dry-run: Do not commit any changes. */
51 /* --timeout: Time to wait for a connection to 'db'. */
54 /* Format for table output. */
55 static struct table_style table_style = TABLE_STYLE_DEFAULT;
57 /* The IDL we're using and the current transaction, if any.
58 * This is for use by nbctl_exit() only, to allow it to clean up.
59 * Other code should use its context arguments. */
60 static struct ovsdb_idl *the_idl;
61 static struct ovsdb_idl_txn *the_idl_txn;
62 OVS_NO_RETURN static void nbctl_exit(int status);
64 static void nbctl_cmd_init(void);
65 OVS_NO_RETURN static void usage(void);
66 static void parse_options(int argc, char *argv[], struct shash *local_options);
67 static const char *nbctl_default_db(void);
68 static void run_prerequisites(struct ctl_command[], size_t n_commands,
70 static bool do_nbctl(const char *args, struct ctl_command *, size_t n,
74 main(int argc, char *argv[])
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_from_string_assert("reconnect: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 if (do_nbctl(args, commands, n_commands, idl)) {
134 if (seqno == ovsdb_idl_get_seqno(idl)) {
142 nbctl_default_db(void)
146 def = getenv("OVN_NB_DB");
148 def = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
155 parse_options(int argc, char *argv[], struct shash *local_options)
158 OPT_DB = UCHAR_MAX + 1,
168 static const struct option global_long_options[] = {
169 {"db", required_argument, NULL, OPT_DB},
170 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
171 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
172 {"oneline", no_argument, NULL, OPT_ONELINE},
173 {"timeout", required_argument, NULL, 't'},
174 {"help", no_argument, NULL, 'h'},
175 {"commands", no_argument, NULL, OPT_COMMANDS},
176 {"options", no_argument, NULL, OPT_OPTIONS},
177 {"version", no_argument, NULL, 'V'},
179 STREAM_SSL_LONG_OPTIONS,
183 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
184 char *tmp, *short_options;
186 struct option *options;
187 size_t allocated_options;
191 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
192 short_options = xasprintf("+%s", tmp);
195 /* We want to parse both global and command-specific options here, but
196 * getopt_long() isn't too convenient for the job. We copy our global
197 * options into a dynamic array, then append all of the command-specific
199 options = xmemdup(global_long_options, sizeof global_long_options);
200 allocated_options = ARRAY_SIZE(global_long_options);
201 n_options = n_global_long_options;
202 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
203 table_style.format = TF_LIST;
209 c = getopt_long(argc, argv, short_options, options, &idx);
224 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
232 if (shash_find(local_options, options[idx].name)) {
233 ctl_fatal("'%s' option specified multiple times",
236 shash_add_nocopy(local_options,
237 xasprintf("--%s", options[idx].name),
238 optarg ? xstrdup(optarg) : NULL);
246 ctl_print_commands();
249 ctl_print_options(global_long_options);
252 ovs_print_version(0, 0);
253 printf("DB Schema %s\n", nbrec_get_db_version());
257 timeout = strtoul(optarg, NULL, 10);
259 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
264 TABLE_OPTION_HANDLERS(&table_style)
265 STREAM_SSL_OPTION_HANDLERS
277 db = nbctl_default_db();
280 for (i = n_global_long_options; options[i].name; i++) {
281 free(CONST_CAST(char *, options[i].name));
290 %s: OVN northbound DB management utility\n\
291 usage: %s [OPTIONS] COMMAND [ARG...]\n\
294 show print overview of database contents\n\
295 show LSWITCH print overview of database contents for LSWITCH\n\
296 show ROUTER print overview of database contents for ROUTER\n\
298 Logical switch commands:\n\
299 lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\
300 lswitch-del LSWITCH delete LSWITCH and all its ports\n\
301 lswitch-list print the names of all logical switches\n\
304 acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
305 add an ACL to LSWITCH\n\
306 acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\
307 remove ACLs from LSWITCH\n\
308 acl-list LSWITCH print ACLs for LSWITCH\n\
310 Logical router port commands:\n\
311 lrport-add ROUTER LRPORT add logical router port LRPORT to ROUTER\n\
312 lrport-del LRPORT delete LRPORT from its attached router\n\
313 lrport-list ROUTER print the names of all logical ports on ROUTER\n\
314 lrport-set-mac-address LRPORT [ADDRESS]\n\
315 set MAC address for LRPORT.\n\
316 lrport-get-mac-address LRPORT get MAC addresses on LRPORT\n\
317 lrport-set-enabled LRPORT STATE\n\
318 set administrative state LRPORT\n\
319 ('enabled' or 'disabled')\n\
320 lrport-get-enabled LRPORT get administrative state LRPORT\n\
321 ('enabled' or 'disabled')\n\
323 Logical port commands:\n\
324 lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
325 lport-add LSWITCH LPORT PARENT TAG\n\
326 add logical port LPORT on LSWITCH with PARENT\n\
328 lport-del LPORT delete LPORT from its attached switch\n\
329 lport-list LSWITCH print the names of all logical ports on LSWITCH\n\
330 lport-get-parent LPORT get the parent of LPORT if set\n\
331 lport-get-tag LPORT get the LPORT's tag if set\n\
332 lport-set-addresses LPORT [ADDRESS]...\n\
333 set MAC or MAC+IP addresses for LPORT.\n\
334 lport-get-addresses LPORT get a list of MAC addresses on LPORT\n\
335 lport-set-port-security LPORT [ADDRS]...\n\
336 set port security addresses for LPORT.\n\
337 lport-get-port-security LPORT get LPORT's port security addresses\n\
338 lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
339 lport-set-enabled LPORT STATE\n\
340 set administrative state LPORT\n\
341 ('enabled' or 'disabled')\n\
342 lport-get-enabled LPORT get administrative state LPORT\n\
343 ('enabled' or 'disabled')\n\
344 lport-set-type LPORT TYPE Set the type for LPORT\n\
345 lport-get-type LPORT Get the type for LPORT\n\
346 lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
347 Set options related to the type of LPORT\n\
348 lport-get-options LPORT Get the type specific options for LPORT\n\
350 Logical router commands:\n\
351 lr-add [ROUTER] create a logical router named ROUTER\n\
352 lr-del ROUTER delete ROUTER and all its ports\n\
353 lr-list print the names of all logical routers\n\
358 --db=DATABASE connect to DATABASE\n\
360 -t, --timeout=SECS wait at most SECS seconds\n\
361 --dry-run do not commit changes to database\n\
362 --oneline print exactly one line of output per command\n",
363 program_name, program_name, ctl_get_db_cmd_usage(), nbctl_default_db());
366 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
369 -h, --help display this help message\n\
370 -V, --version display version information\n");
375 /* Find a logical router given its id. */
376 static const struct nbrec_logical_router *
377 lr_by_name_or_uuid(struct ctl_context *ctx, const char *id,
380 const struct nbrec_logical_router *lr = NULL;
381 bool is_uuid = false;
384 if (uuid_from_string(&lr_uuid, id)) {
386 lr = nbrec_logical_router_get_for_uuid(ctx->idl, &lr_uuid);
390 const struct nbrec_logical_router *iter;
392 NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
393 if (strcmp(iter->name, id)) {
397 ctl_fatal("Multiple logical routers named '%s'. "
404 if (!lr && must_exist) {
405 ctl_fatal("%s: router %s not found", id, is_uuid ? "UUID" : "name");
411 static const struct nbrec_logical_switch *
412 lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id,
415 const struct nbrec_logical_switch *lswitch = NULL;
417 struct uuid lswitch_uuid;
418 bool is_uuid = uuid_from_string(&lswitch_uuid, id);
420 lswitch = nbrec_logical_switch_get_for_uuid(ctx->idl, &lswitch_uuid);
424 const struct nbrec_logical_switch *iter;
426 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
427 if (strcmp(iter->name, id)) {
431 ctl_fatal("Multiple logical switches named '%s'. "
438 if (!lswitch && must_exist) {
439 ctl_fatal("%s: lswitch %s not found", id, is_uuid ? "UUID" : "name");
445 /* Given pointer to logical router, this routine prints the router
448 print_lr(const struct nbrec_logical_router *lr, struct ds *s)
450 ds_put_format(s, " router "UUID_FMT" (%s)\n",
451 UUID_ARGS(&lr->header_.uuid), lr->name);
453 for (size_t i = 0; i < lr->n_ports; i++) {
454 const struct nbrec_logical_router_port *lrport = lr->ports[i];
455 ds_put_format(s, " lrport %s\n", lrport->name);
457 ds_put_cstr(s, " mac: ");
458 ds_put_format(s, "\"%s\"", lrport->mac);
460 ds_put_format(s, "\n");
465 print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s)
467 ds_put_format(s, " lswitch "UUID_FMT" (%s)\n",
468 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
470 for (size_t i = 0; i < lswitch->n_ports; i++) {
471 const struct nbrec_logical_port *lport = lswitch->ports[i];
473 ds_put_format(s, " lport %s\n", lport->name);
474 if (lport->parent_name) {
475 ds_put_format(s, " parent: %s\n", lport->parent_name);
478 ds_put_format(s, " tag: %"PRIu64"\n", lport->tag[0]);
480 if (lport->n_addresses) {
481 ds_put_cstr(s, " addresses: [");
482 for (size_t j = 0; j < lport->n_addresses; j++) {
483 ds_put_format(s, "%s\"%s\"",
485 lport->addresses[j]);
487 ds_put_cstr(s, "]\n");
493 nbctl_show(struct ctl_context *ctx)
495 const struct nbrec_logical_switch *lswitch;
497 if (ctx->argc == 2) {
498 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], false);
500 print_lswitch(lswitch, &ctx->output);
503 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
504 print_lswitch(lswitch, &ctx->output);
507 const struct nbrec_logical_router *lr;
509 if (ctx->argc == 2) {
510 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
512 print_lr(lr, &ctx->output);
515 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
516 print_lr(lr, &ctx->output);
522 nbctl_lswitch_add(struct ctl_context *ctx)
524 const char *lswitch_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
526 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
527 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
528 if (may_exist && add_duplicate) {
529 ctl_fatal("--may-exist and --add-duplicate may not be used together");
533 if (!add_duplicate) {
534 const struct nbrec_logical_switch *lswitch;
535 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
536 if (!strcmp(lswitch->name, lswitch_name)) {
540 ctl_fatal("%s: an lswitch with this name already exists",
545 } else if (may_exist) {
546 ctl_fatal("--may-exist requires specifying a name");
547 } else if (add_duplicate) {
548 ctl_fatal("--add-duplicate requires specifying a name");
551 struct nbrec_logical_switch *lswitch;
552 lswitch = nbrec_logical_switch_insert(ctx->txn);
554 nbrec_logical_switch_set_name(lswitch, lswitch_name);
559 nbctl_lswitch_del(struct ctl_context *ctx)
561 bool must_exist = !shash_find(&ctx->options, "--if-exists");
562 const char *id = ctx->argv[1];
563 const struct nbrec_logical_switch *lswitch;
565 lswitch = lswitch_by_name_or_uuid(ctx, id, must_exist);
570 nbrec_logical_switch_delete(lswitch);
574 nbctl_lswitch_list(struct ctl_context *ctx)
576 const struct nbrec_logical_switch *lswitch;
577 struct smap lswitches;
579 smap_init(&lswitches);
580 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
581 smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
582 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
584 const struct smap_node **nodes = smap_sort(&lswitches);
585 for (size_t i = 0; i < smap_count(&lswitches); i++) {
586 const struct smap_node *node = nodes[i];
587 ds_put_format(&ctx->output, "%s\n", node->value);
589 smap_destroy(&lswitches);
593 /* Find the lrport given its id. */
594 static const struct nbrec_logical_router_port *
595 lrport_by_name_or_uuid(struct ctl_context *ctx, const char *id,
598 const struct nbrec_logical_router_port *lrport = NULL;
599 bool is_uuid = false;
600 struct uuid lrport_uuid;
602 if (uuid_from_string(&lrport_uuid, id)) {
604 lrport = nbrec_logical_router_port_get_for_uuid(ctx->idl,
609 NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrport, ctx->idl) {
610 if (!strcmp(lrport->name, id)) {
616 if (!lrport && must_exist) {
617 ctl_fatal("%s: lrport with this %s not found",
618 id, is_uuid ? "name" : "UUID");
624 static const struct nbrec_logical_port *
625 lport_by_name_or_uuid(struct ctl_context *ctx, const char *id,
628 const struct nbrec_logical_port *lport = NULL;
630 struct uuid lport_uuid;
631 bool is_uuid = uuid_from_string(&lport_uuid, id);
633 lport = nbrec_logical_port_get_for_uuid(ctx->idl, &lport_uuid);
637 NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->idl) {
638 if (!strcmp(lport->name, id)) {
644 if (!lport && must_exist) {
645 ctl_fatal("%s: lport %s not found", id, is_uuid ? "UUID" : "name");
651 /* Returns the lswitch that contains 'lport'. */
652 static const struct nbrec_logical_switch *
653 lport_to_lswitch(const struct ovsdb_idl *idl,
654 const struct nbrec_logical_port *lport)
656 const struct nbrec_logical_switch *lswitch;
657 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, idl) {
658 for (size_t i = 0; i < lswitch->n_ports; i++) {
659 if (lswitch->ports[i] == lport) {
665 /* Can't happen because of the database schema */
666 ctl_fatal("logical port %s is not part of any logical switch",
670 /* Returns the logical router that contains 'lport'. */
671 static const struct nbrec_logical_router *
672 lrport_to_lr(const struct ovsdb_idl *idl,
673 const struct nbrec_logical_router_port *lrport)
675 const struct nbrec_logical_router *lr;
676 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, idl) {
677 for (size_t i = 0; i < lr->n_ports; i++) {
678 if (lr->ports[i] == lrport) {
684 /* Can't happen because of the database schema */
685 ctl_fatal("logical port %s is not part of any logical router",
690 lswitch_get_name(const struct nbrec_logical_switch *lswitch,
691 char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
693 if (lswitch->name[0]) {
694 return lswitch->name;
696 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lswitch->header_.uuid));
701 lr_get_name(const struct nbrec_logical_router *lr,
702 char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
707 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lr->header_.uuid));
712 nbctl_lport_add(struct ctl_context *ctx)
714 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
716 const struct nbrec_logical_switch *lswitch;
717 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
719 const char *parent_name;
721 if (ctx->argc == 3) {
724 } else if (ctx->argc == 5) {
726 parent_name = ctx->argv[3];
727 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag)
728 || tag < 0 || tag > 4095) {
729 ctl_fatal("%s: invalid tag", ctx->argv[4]);
732 ctl_fatal("lport-add with parent must also specify a tag");
735 const char *lport_name = ctx->argv[2];
736 const struct nbrec_logical_port *lport;
737 lport = lport_by_name_or_uuid(ctx, lport_name, false);
740 ctl_fatal("%s: an lport with this name already exists",
744 const struct nbrec_logical_switch *lsw;
745 lsw = lport_to_lswitch(ctx->idl, lport);
746 if (lsw != lswitch) {
747 char uuid_s[UUID_LEN + 1];
748 ctl_fatal("%s: lport already exists but in lswitch %s", lport_name,
749 lswitch_get_name(lsw, uuid_s, sizeof uuid_s));
753 if (!lport->parent_name) {
754 ctl_fatal("%s: lport already exists but has no parent",
756 } else if (strcmp(parent_name, lport->parent_name)) {
757 ctl_fatal("%s: lport already exists with different parent %s",
758 lport_name, lport->parent_name);
762 ctl_fatal("%s: lport already exists but has no tag",
764 } else if (lport->tag[0] != tag) {
765 ctl_fatal("%s: lport already exists with different "
766 "tag %"PRId64, lport_name, lport->tag[0]);
769 if (lport->parent_name) {
770 ctl_fatal("%s: lport already exists but has parent %s",
771 lport_name, lport->parent_name);
778 /* Create the logical port. */
779 lport = nbrec_logical_port_insert(ctx->txn);
780 nbrec_logical_port_set_name(lport, lport_name);
782 nbrec_logical_port_set_parent_name(lport, parent_name);
783 nbrec_logical_port_set_tag(lport, &tag, 1);
786 /* Insert the logical port into the logical switch. */
787 nbrec_logical_switch_verify_ports(lswitch);
788 struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
789 (lswitch->n_ports + 1));
790 memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
791 new_ports[lswitch->n_ports] = CONST_CAST(struct nbrec_logical_port *,
793 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
797 /* Removes lrport 'lr->ports[idx]' from logical router. */
799 remove_lrport(const struct nbrec_logical_router *lr, size_t idx)
801 const struct nbrec_logical_router_port *lrport = lr->ports[idx];
803 /* First remove 'lrport' from the array of ports. This is what will
804 * actually cause the logical port to be deleted when the transaction is
805 * sent to the database server (due to garbage collection). */
806 struct nbrec_logical_router_port **new_ports
807 = xmemdup(lr->ports, sizeof *new_ports * lr->n_ports);
808 new_ports[idx] = new_ports[lr->n_ports - 1];
809 nbrec_logical_router_verify_ports(lr);
810 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports - 1);
813 /* Delete 'lrport' from the IDL. */
814 nbrec_logical_router_port_delete(lrport);
817 /* Removes lport 'lswitch->ports[idx]'. */
819 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
821 const struct nbrec_logical_port *lport = lswitch->ports[idx];
823 /* First remove 'lport' from the array of ports. This is what will
824 * actually cause the logical port to be deleted when the transaction is
825 * sent to the database server (due to garbage collection). */
826 struct nbrec_logical_port **new_ports
827 = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
828 new_ports[idx] = new_ports[lswitch->n_ports - 1];
829 nbrec_logical_switch_verify_ports(lswitch);
830 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
833 /* Delete 'lport' from the IDL. This won't have a real effect on the
834 * database server (the IDL will suppress it in fact) but it means that it
835 * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
836 nbrec_logical_port_delete(lport);
840 nbctl_lport_del(struct ctl_context *ctx)
842 bool must_exist = !shash_find(&ctx->options, "--if-exists");
843 const struct nbrec_logical_port *lport;
845 lport = lport_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
850 /* Find the switch that contains 'lport', then delete it. */
851 const struct nbrec_logical_switch *lswitch;
852 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
853 for (size_t i = 0; i < lswitch->n_ports; i++) {
854 if (lswitch->ports[i] == lport) {
855 remove_lport(lswitch, i);
861 /* Can't happen because of the database schema. */
862 ctl_fatal("logical port %s is not part of any logical switch",
867 nbctl_lport_list(struct ctl_context *ctx)
869 const char *id = ctx->argv[1];
870 const struct nbrec_logical_switch *lswitch;
874 lswitch = lswitch_by_name_or_uuid(ctx, id, true);
877 for (i = 0; i < lswitch->n_ports; i++) {
878 const struct nbrec_logical_port *lport = lswitch->ports[i];
879 smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
880 UUID_ARGS(&lport->header_.uuid), lport->name);
882 const struct smap_node **nodes = smap_sort(&lports);
883 for (i = 0; i < smap_count(&lports); i++) {
884 const struct smap_node *node = nodes[i];
885 ds_put_format(&ctx->output, "%s\n", node->value);
887 smap_destroy(&lports);
892 nbctl_lport_get_parent(struct ctl_context *ctx)
894 const struct nbrec_logical_port *lport;
896 lport = lport_by_name_or_uuid(ctx, ctx->argv[1], true);
897 if (lport->parent_name) {
898 ds_put_format(&ctx->output, "%s\n", lport->parent_name);
903 nbctl_lport_get_tag(struct ctl_context *ctx)
905 const struct nbrec_logical_port *lport;
907 lport = lport_by_name_or_uuid(ctx, ctx->argv[1], true);
908 if (lport->n_tag > 0) {
909 ds_put_format(&ctx->output, "%"PRId64"\n", lport->tag[0]);
913 /* Set the MAC address of lrport. */
915 nbctl_lrport_set_mac(struct ctl_context *ctx)
918 const char *id = ctx->argv[1];
919 const struct nbrec_logical_router_port *lrport;
921 lrport = lrport_by_name_or_uuid(ctx, id, true);
923 const char *mac = ctx->argc > 2 ? ctx->argv[2] : "";
924 if (mac[0] && !ovs_scan(ctx->argv[2], ETH_ADDR_SCAN_FMT,
925 ETH_ADDR_SCAN_ARGS(ea))) {
926 ctl_fatal("%s: invalid MAC address format", mac);
930 nbrec_logical_router_port_set_mac(lrport, mac);
934 nbctl_lport_set_addresses(struct ctl_context *ctx)
936 const char *id = ctx->argv[1];
937 const struct nbrec_logical_port *lport;
939 lport = lport_by_name_or_uuid(ctx, id, true);
942 for (i = 2; i < ctx->argc; i++) {
945 if (strcmp(ctx->argv[i], "unknown")
946 && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
947 ETH_ADDR_SCAN_ARGS(ea))) {
948 ctl_fatal("%s: Invalid address format. See ovn-nb(5). "
949 "Hint: An Ethernet address must be "
950 "listed before an IP address, together as a single "
951 "argument.", ctx->argv[i]);
955 nbrec_logical_port_set_addresses(lport,
956 (const char **) ctx->argv + 2, ctx->argc - 2);
959 /* Following function prints the mac address of the lrport. */
961 nbctl_lrport_get_mac(struct ctl_context *ctx)
963 const char *id = ctx->argv[1];
964 const struct nbrec_logical_router_port *lrport;
966 lrport = lrport_by_name_or_uuid(ctx, id, true);
970 ds_put_format(&ctx->output, "%s\n", lrport->mac);
974 nbctl_lport_get_addresses(struct ctl_context *ctx)
976 const char *id = ctx->argv[1];
977 const struct nbrec_logical_port *lport;
978 struct svec addresses;
982 lport = lport_by_name_or_uuid(ctx, id, true);
984 svec_init(&addresses);
985 for (i = 0; i < lport->n_addresses; i++) {
986 svec_add(&addresses, lport->addresses[i]);
988 svec_sort(&addresses);
989 SVEC_FOR_EACH(i, mac, &addresses) {
990 ds_put_format(&ctx->output, "%s\n", mac);
992 svec_destroy(&addresses);
996 nbctl_lport_set_port_security(struct ctl_context *ctx)
998 const char *id = ctx->argv[1];
999 const struct nbrec_logical_port *lport;
1001 lport = lport_by_name_or_uuid(ctx, id, true);
1002 nbrec_logical_port_set_port_security(lport,
1003 (const char **) ctx->argv + 2, ctx->argc - 2);
1007 nbctl_lport_get_port_security(struct ctl_context *ctx)
1009 const char *id = ctx->argv[1];
1010 const struct nbrec_logical_port *lport;
1015 lport = lport_by_name_or_uuid(ctx, id, true);
1017 for (i = 0; i < lport->n_port_security; i++) {
1018 svec_add(&addrs, lport->port_security[i]);
1021 SVEC_FOR_EACH(i, addr, &addrs) {
1022 ds_put_format(&ctx->output, "%s\n", addr);
1024 svec_destroy(&addrs);
1028 nbctl_lport_get_up(struct ctl_context *ctx)
1030 const char *id = ctx->argv[1];
1031 const struct nbrec_logical_port *lport;
1033 lport = lport_by_name_or_uuid(ctx, id, true);
1034 ds_put_format(&ctx->output,
1035 "%s\n", (lport->up && *lport->up) ? "up" : "down");
1039 parse_enabled(const char *state)
1041 if (!strcasecmp(state, "enabled")) {
1043 } else if (!strcasecmp(state, "disabled")) {
1046 ctl_fatal("%s: state must be \"enabled\" or \"disabled\"", state);
1050 /* Set the lrport admin-enabled state. */
1052 nbctl_lrport_set_enabled(struct ctl_context *ctx)
1054 const char *id = ctx->argv[1];
1055 const char *state = ctx->argv[2];
1056 const struct nbrec_logical_router_port *lrport;
1058 lrport = lrport_by_name_or_uuid(ctx, id, true);
1063 bool enabled = parse_enabled(state);
1064 nbrec_logical_router_port_set_enabled(lrport, &enabled, 1);
1068 nbctl_lport_set_enabled(struct ctl_context *ctx)
1070 const char *id = ctx->argv[1];
1071 const char *state = ctx->argv[2];
1072 const struct nbrec_logical_port *lport;
1074 lport = lport_by_name_or_uuid(ctx, id, true);
1075 bool enabled = parse_enabled(state);
1076 nbrec_logical_port_set_enabled(lport, &enabled, 1);
1079 /* Print admin-enabled state for lrport. */
1081 nbctl_lrport_get_enabled(struct ctl_context *ctx)
1083 const char *id = ctx->argv[1];
1084 const struct nbrec_logical_router_port *lrport;
1086 lrport = lrport_by_name_or_uuid(ctx, id, true);
1091 ds_put_format(&ctx->output, "%s\n",
1093 *lrport->enabled ? "enabled" : "disabled");
1097 nbctl_lport_get_enabled(struct ctl_context *ctx)
1099 const char *id = ctx->argv[1];
1100 const struct nbrec_logical_port *lport;
1102 lport = lport_by_name_or_uuid(ctx, id, true);
1103 ds_put_format(&ctx->output, "%s\n",
1104 !lport->enabled || *lport->enabled ? "enabled" : "disabled");
1108 nbctl_lport_set_type(struct ctl_context *ctx)
1110 const char *id = ctx->argv[1];
1111 const char *type = ctx->argv[2];
1112 const struct nbrec_logical_port *lport;
1114 lport = lport_by_name_or_uuid(ctx, id, true);
1115 nbrec_logical_port_set_type(lport, type);
1119 nbctl_lport_get_type(struct ctl_context *ctx)
1121 const char *id = ctx->argv[1];
1122 const struct nbrec_logical_port *lport;
1124 lport = lport_by_name_or_uuid(ctx, id, true);
1125 ds_put_format(&ctx->output, "%s\n", lport->type);
1129 nbctl_lport_set_options(struct ctl_context *ctx)
1131 const char *id = ctx->argv[1];
1132 const struct nbrec_logical_port *lport;
1134 struct smap options = SMAP_INITIALIZER(&options);
1136 lport = lport_by_name_or_uuid(ctx, id, true);
1137 for (i = 2; i < ctx->argc; i++) {
1139 value = xstrdup(ctx->argv[i]);
1140 key = strsep(&value, "=");
1142 smap_add(&options, key, value);
1147 nbrec_logical_port_set_options(lport, &options);
1149 smap_destroy(&options);
1153 nbctl_lport_get_options(struct ctl_context *ctx)
1155 const char *id = ctx->argv[1];
1156 const struct nbrec_logical_port *lport;
1157 struct smap_node *node;
1159 lport = lport_by_name_or_uuid(ctx, id, true);
1160 SMAP_FOR_EACH(node, &lport->options) {
1161 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1171 dir_encode(const char *dir)
1173 if (!strcmp(dir, "from-lport")) {
1174 return DIR_FROM_LPORT;
1175 } else if (!strcmp(dir, "to-lport")) {
1176 return DIR_TO_LPORT;
1183 acl_cmp(const void *acl1_, const void *acl2_)
1185 const struct nbrec_acl *const *acl1p = acl1_;
1186 const struct nbrec_acl *const *acl2p = acl2_;
1187 const struct nbrec_acl *acl1 = *acl1p;
1188 const struct nbrec_acl *acl2 = *acl2p;
1190 int dir1 = dir_encode(acl1->direction);
1191 int dir2 = dir_encode(acl2->direction);
1194 return dir1 < dir2 ? -1 : 1;
1195 } else if (acl1->priority != acl2->priority) {
1196 return acl1->priority > acl2->priority ? -1 : 1;
1198 return strcmp(acl1->match, acl2->match);
1203 nbctl_acl_list(struct ctl_context *ctx)
1205 const struct nbrec_logical_switch *lswitch;
1206 const struct nbrec_acl **acls;
1209 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
1211 acls = xmalloc(sizeof *acls * lswitch->n_acls);
1212 for (i = 0; i < lswitch->n_acls; i++) {
1213 acls[i] = lswitch->acls[i];
1216 qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
1218 for (i = 0; i < lswitch->n_acls; i++) {
1219 const struct nbrec_acl *acl = acls[i];
1220 ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s%s\n",
1221 acl->direction, acl->priority,
1222 acl->match, acl->action, acl->log ? " log" : "");
1229 parse_direction(const char *arg)
1231 /* Validate direction. Only require the first letter. */
1232 if (arg[0] == 't') {
1234 } else if (arg[0] == 'f') {
1235 return "from-lport";
1237 ctl_fatal("%s: direction must be \"to-lport\" or \"from-lport\"", arg);
1242 parse_priority(const char *arg)
1244 /* Validate priority. */
1246 if (!ovs_scan(arg, "%"SCNd64, &priority)
1247 || priority < 0 || priority > 32767) {
1248 ctl_fatal("%s: priority must in range 0...32767", arg);
1254 nbctl_acl_add(struct ctl_context *ctx)
1256 const struct nbrec_logical_switch *lswitch;
1257 const char *action = ctx->argv[5];
1259 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
1261 const char *direction = parse_direction(ctx->argv[2]);
1262 int64_t priority = parse_priority(ctx->argv[3]);
1264 /* Validate action. */
1265 if (strcmp(action, "allow") && strcmp(action, "allow-related")
1266 && strcmp(action, "drop") && strcmp(action, "reject")) {
1267 ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
1268 "\"drop\", and \"reject\"", action);
1272 /* Create the acl. */
1273 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1274 nbrec_acl_set_priority(acl, priority);
1275 nbrec_acl_set_direction(acl, direction);
1276 nbrec_acl_set_match(acl, ctx->argv[4]);
1277 nbrec_acl_set_action(acl, action);
1278 if (shash_find(&ctx->options, "--log") != NULL) {
1279 nbrec_acl_set_log(acl, true);
1282 /* Insert the acl into the logical switch. */
1283 nbrec_logical_switch_verify_acls(lswitch);
1284 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls *
1285 (lswitch->n_acls + 1));
1286 memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1287 new_acls[lswitch->n_acls] = acl;
1288 nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1);
1293 nbctl_acl_del(struct ctl_context *ctx)
1295 const struct nbrec_logical_switch *lswitch;
1296 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1], true);
1298 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1299 ctl_fatal("cannot specify priority without match");
1302 if (ctx->argc == 2) {
1303 /* If direction, priority, and match are not specified, delete
1305 nbrec_logical_switch_verify_acls(lswitch);
1306 nbrec_logical_switch_set_acls(lswitch, NULL, 0);
1310 const char *direction = parse_direction(ctx->argv[2]);
1312 /* If priority and match are not specified, delete all ACLs with the
1313 * specified direction. */
1314 if (ctx->argc == 3) {
1315 struct nbrec_acl **new_acls
1316 = xmalloc(sizeof *new_acls * lswitch->n_acls);
1319 for (size_t i = 0; i < lswitch->n_acls; i++) {
1320 if (strcmp(direction, lswitch->acls[i]->direction)) {
1321 new_acls[n_acls++] = lswitch->acls[i];
1325 nbrec_logical_switch_verify_acls(lswitch);
1326 nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
1331 int64_t priority = parse_priority(ctx->argv[3]);
1333 /* Remove the matching rule. */
1334 for (size_t i = 0; i < lswitch->n_acls; i++) {
1335 struct nbrec_acl *acl = lswitch->acls[i];
1337 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1338 !strcmp(direction, acl->direction)) {
1339 struct nbrec_acl **new_acls
1340 = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1341 new_acls[i] = lswitch->acls[lswitch->n_acls - 1];
1342 nbrec_logical_switch_verify_acls(lswitch);
1343 nbrec_logical_switch_set_acls(lswitch, new_acls,
1344 lswitch->n_acls - 1);
1352 nbctl_lr_add(struct ctl_context *ctx)
1354 const char *lr_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
1356 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1357 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1358 if (may_exist && add_duplicate) {
1359 ctl_fatal("--may-exist and --add-duplicate may not be used together");
1363 if (!add_duplicate) {
1364 const struct nbrec_logical_router *lr;
1365 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1366 if (!strcmp(lr->name, lr_name)) {
1370 ctl_fatal("%s: a router with this name already exists",
1375 } else if (may_exist) {
1376 ctl_fatal("--may-exist requires specifying a name");
1377 } else if (add_duplicate) {
1378 ctl_fatal("--add-duplicate requires specifying a name");
1381 struct nbrec_logical_router *lr;
1382 lr = nbrec_logical_router_insert(ctx->txn);
1384 nbrec_logical_router_set_name(lr, lr_name);
1389 nbctl_lr_del(struct ctl_context *ctx)
1391 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1392 const char *id = ctx->argv[1];
1393 const struct nbrec_logical_router *lr;
1395 lr = lr_by_name_or_uuid(ctx, id, must_exist);
1400 nbrec_logical_router_delete(lr);
1404 nbctl_lr_list(struct ctl_context *ctx)
1406 const struct nbrec_logical_router *lr;
1410 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
1411 smap_add_format(&lrs, lr->name, UUID_FMT " (%s)",
1412 UUID_ARGS(&lr->header_.uuid), lr->name);
1414 const struct smap_node **nodes = smap_sort(&lrs);
1415 for (size_t i = 0; i < smap_count(&lrs); i++) {
1416 const struct smap_node *node = nodes[i];
1417 ds_put_format(&ctx->output, "%s\n", node->value);
1423 static const struct ctl_table_class tables[] = {
1424 {&nbrec_table_logical_switch,
1425 {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
1426 {NULL, NULL, NULL}}},
1428 {&nbrec_table_logical_port,
1429 {{&nbrec_table_logical_port, &nbrec_logical_port_col_name, NULL},
1430 {NULL, NULL, NULL}}},
1433 {{NULL, NULL, NULL},
1434 {NULL, NULL, NULL}}},
1436 {&nbrec_table_logical_router,
1437 {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
1438 {NULL, NULL, NULL}}},
1440 {&nbrec_table_logical_router_port,
1441 {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
1443 {NULL, NULL, NULL}}},
1445 {&nbrec_table_logical_router_static_route,
1446 {{&nbrec_table_logical_router_static_route, NULL,
1448 {NULL, NULL, NULL}}},
1450 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
1454 run_prerequisites(struct ctl_command *commands, size_t n_commands,
1455 struct ovsdb_idl *idl)
1457 struct ctl_command *c;
1459 for (c = commands; c < &commands[n_commands]; c++) {
1460 if (c->syntax->prerequisites) {
1461 struct ctl_context ctx;
1463 ds_init(&c->output);
1466 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
1467 (c->syntax->prerequisites)(&ctx);
1468 ctl_context_done(&ctx, c);
1470 ovs_assert(!c->output.string);
1471 ovs_assert(!c->table);
1477 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
1478 struct ovsdb_idl *idl)
1480 struct ovsdb_idl_txn *txn;
1481 enum ovsdb_idl_txn_status status;
1482 struct ovsdb_symbol_table *symtab;
1483 struct ctl_context ctx;
1484 struct ctl_command *c;
1485 struct shash_node *node;
1488 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
1490 ovsdb_idl_txn_set_dry_run(txn);
1493 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
1495 symtab = ovsdb_symbol_table_create();
1496 for (c = commands; c < &commands[n_commands]; c++) {
1497 ds_init(&c->output);
1500 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
1501 for (c = commands; c < &commands[n_commands]; c++) {
1502 ctl_context_init_command(&ctx, c);
1503 if (c->syntax->run) {
1504 (c->syntax->run)(&ctx);
1506 ctl_context_done_command(&ctx, c);
1508 if (ctx.try_again) {
1509 ctl_context_done(&ctx, NULL);
1513 ctl_context_done(&ctx, NULL);
1515 SHASH_FOR_EACH (node, &symtab->sh) {
1516 struct ovsdb_symbol *symbol = node->data;
1517 if (!symbol->created) {
1518 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
1519 "with \"-- --id=%s create ...\")",
1520 node->name, node->name);
1522 if (!symbol->strong_ref) {
1523 if (!symbol->weak_ref) {
1524 VLOG_WARN("row id \"%s\" was created but no reference to it "
1525 "was inserted, so it will not actually appear in "
1526 "the database", node->name);
1528 VLOG_WARN("row id \"%s\" was created but only a weak "
1529 "reference to it was inserted, so it will not "
1530 "actually appear in the database", node->name);
1535 status = ovsdb_idl_txn_commit_block(txn);
1536 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
1537 for (c = commands; c < &commands[n_commands]; c++) {
1538 if (c->syntax->postprocess) {
1539 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
1540 (c->syntax->postprocess)(&ctx);
1541 ctl_context_done(&ctx, c);
1545 error = xstrdup(ovsdb_idl_txn_get_error(txn));
1548 case TXN_UNCOMMITTED:
1549 case TXN_INCOMPLETE:
1553 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1554 ctl_fatal("transaction aborted");
1564 ctl_fatal("transaction error: %s", error);
1566 case TXN_NOT_LOCKED:
1567 /* Should not happen--we never call ovsdb_idl_set_lock(). */
1568 ctl_fatal("database not locked");
1575 ovsdb_symbol_table_destroy(symtab);
1577 for (c = commands; c < &commands[n_commands]; c++) {
1578 struct ds *ds = &c->output;
1581 table_print(c->table, &table_style);
1582 } else if (oneline) {
1586 for (j = 0; j < ds->length; j++) {
1587 int ch = ds->string[j];
1590 fputs("\\n", stdout);
1594 fputs("\\\\", stdout);
1603 fputs(ds_cstr(ds), stdout);
1605 ds_destroy(&c->output);
1606 table_destroy(c->table);
1609 shash_destroy_free_data(&c->options);
1612 ovsdb_idl_txn_destroy(txn);
1613 ovsdb_idl_destroy(idl);
1618 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
1619 * resources and return so that the caller can try again. */
1621 ovsdb_idl_txn_abort(txn);
1622 ovsdb_idl_txn_destroy(txn);
1625 ovsdb_symbol_table_destroy(symtab);
1626 for (c = commands; c < &commands[n_commands]; c++) {
1627 ds_destroy(&c->output);
1628 table_destroy(c->table);
1635 /* Frees the current transaction and the underlying IDL and then calls
1638 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1639 * for a clean memory leak report from valgrind in the normal case. That makes
1640 * it easier to notice real memory leaks. */
1642 nbctl_exit(int status)
1645 ovsdb_idl_txn_abort(the_idl_txn);
1646 ovsdb_idl_txn_destroy(the_idl_txn);
1648 ovsdb_idl_destroy(the_idl);
1652 /* Print a list of lrports. */
1654 nbctl_lrport_list(struct ctl_context *ctx)
1656 const char *id = ctx->argv[1];
1657 const struct nbrec_logical_router *lr;
1661 lr = lr_by_name_or_uuid(ctx, id, true);
1664 for (i = 0; i < lr->n_ports; i++) {
1665 const struct nbrec_logical_router_port *lport = lr->ports[i];
1666 smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
1667 UUID_ARGS(&lport->header_.uuid), lport->name);
1669 const struct smap_node **nodes = smap_sort(&lports);
1670 for (i = 0; i < smap_count(&lports); i++) {
1671 const struct smap_node *node = nodes[i];
1672 ds_put_format(&ctx->output, "%s\n", node->value);
1674 smap_destroy(&lports);
1678 /* Add an lrport to the logical router. */
1680 nbctl_lrport_add(struct ctl_context *ctx)
1682 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1684 const struct nbrec_logical_router *lr;
1685 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1687 const char *lrport_name = ctx->argv[2];
1688 const struct nbrec_logical_router_port *lrport;
1690 lrport = lrport_by_name_or_uuid(ctx, lrport_name, false);
1693 ctl_fatal("%s: an lrport with this name already exists",
1697 const struct nbrec_logical_router *bound_lr;
1698 bound_lr = lrport_to_lr(ctx->idl, lrport);
1699 if (bound_lr != lr) {
1700 char uuid_s[UUID_LEN + 1];
1701 ctl_fatal("%s: lrport already exists but in router %s",
1703 lr_get_name(bound_lr, uuid_s, sizeof uuid_s));
1709 /* Create the logical router port. */
1710 lrport = nbrec_logical_router_port_insert(ctx->txn);
1711 nbrec_logical_router_port_set_name(lrport, ctx->argv[2]);
1713 /* Insert the logical port into the logical router. */
1714 nbrec_logical_router_verify_ports(lr);
1715 struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
1717 memcpy(new_ports, lr->ports, sizeof *new_ports * lr->n_ports);
1718 new_ports[lr->n_ports] = CONST_CAST(
1719 struct nbrec_logical_router_port *, lrport);
1720 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports + 1);
1724 /* Deletes an lrport from a logical router. */
1726 nbctl_lrport_del(struct ctl_context *ctx)
1728 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1729 const struct nbrec_logical_router_port *lrport;
1731 lrport = lrport_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
1736 /* Find the router that contains 'lrport', then delete it. */
1737 const struct nbrec_logical_router *lr;
1738 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1739 for (size_t i = 0; i < lr->n_ports; i++) {
1740 if (lr->ports[i] == lrport) {
1741 remove_lrport(lr, i);
1747 ctl_fatal("logical router port %s is not part of any logical router",
1751 static const struct ctl_command_syntax nbctl_commands[] = {
1752 { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO },
1754 /* lswitch commands. */
1755 { "lswitch-add", 0, 1, "[LSWITCH]", NULL, nbctl_lswitch_add,
1756 NULL, "--may-exist,--add-duplicate", RW },
1757 { "lswitch-del", 1, 1, "LSWITCH", NULL, nbctl_lswitch_del,
1758 NULL, "--if-exists", RW },
1759 { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO },
1762 { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
1763 nbctl_acl_add, NULL, "--log", RW },
1764 { "acl-del", 1, 4, "LSWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
1765 nbctl_acl_del, NULL, "", RW },
1766 { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO },
1768 /* lrport commands. */
1769 { "lrport-add", 2, 2, "ROUTER LRPORT", NULL, nbctl_lrport_add,
1770 NULL, "--may-exist", RW },
1771 { "lrport-del", 1, 1, "LRPORT", NULL, nbctl_lrport_del, NULL, "", RO },
1772 { "lrport-list", 1, 1, "ROUTER", NULL, nbctl_lrport_list, NULL, "", RO },
1773 { "lrport-set-mac-address", 1, 2, "LRPORT [ADDRESS]", NULL,
1774 nbctl_lrport_set_mac, NULL, "", RW },
1775 { "lrport-get-mac-address", 1, 1, "LRPORT", NULL,
1776 nbctl_lrport_get_mac, NULL,
1778 { "lrport-set-enabled", 2, 2, "LRPORT STATE", NULL,
1779 nbctl_lrport_set_enabled, NULL, "", RW },
1780 { "lrport-get-enabled", 1, 1, "LRPORT", NULL,
1781 nbctl_lrport_get_enabled, NULL, "", RO },
1783 /* lport commands. */
1784 { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, nbctl_lport_add,
1785 NULL, "--may-exist", RW },
1786 { "lport-del", 1, 1, "LPORT", NULL, nbctl_lport_del, NULL, "--if-exists",
1788 { "lport-list", 1, 1, "LSWITCH", NULL, nbctl_lport_list, NULL, "", RO },
1789 { "lport-get-parent", 1, 1, "LPORT", NULL, nbctl_lport_get_parent, NULL,
1791 { "lport-get-tag", 1, 1, "LPORT", NULL, nbctl_lport_get_tag, NULL, "",
1793 { "lport-set-addresses", 1, INT_MAX, "LPORT [ADDRESS]...", NULL,
1794 nbctl_lport_set_addresses, NULL, "", RW },
1795 { "lport-get-addresses", 1, 1, "LPORT", NULL,
1796 nbctl_lport_get_addresses, NULL,
1798 { "lport-set-port-security", 0, INT_MAX, "LPORT [ADDRS]...", NULL,
1799 nbctl_lport_set_port_security, NULL, "", RW },
1800 { "lport-get-port-security", 1, 1, "LPORT", NULL,
1801 nbctl_lport_get_port_security, NULL, "", RO },
1802 { "lport-get-up", 1, 1, "LPORT", NULL, nbctl_lport_get_up, NULL, "", RO },
1803 { "lport-set-enabled", 2, 2, "LPORT STATE", NULL, nbctl_lport_set_enabled,
1805 { "lport-get-enabled", 1, 1, "LPORT", NULL, nbctl_lport_get_enabled, NULL,
1807 { "lport-set-type", 2, 2, "LPORT TYPE", NULL, nbctl_lport_set_type, NULL,
1809 { "lport-get-type", 1, 1, "LPORT", NULL, nbctl_lport_get_type, NULL, "",
1811 { "lport-set-options", 1, INT_MAX, "LPORT KEY=VALUE [KEY=VALUE]...", NULL,
1812 nbctl_lport_set_options, NULL, "", RW },
1813 { "lport-get-options", 1, 1, "LPORT", NULL, nbctl_lport_get_options, NULL,
1816 /* logical router commands. */
1817 { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL,
1818 "--may-exist,--add-duplicate", RW },
1819 { "lr-del", 1, 1, "ROUTER", NULL, nbctl_lr_del, NULL, "--if-exists", RW },
1820 { "lr-list", 0, 0, "", NULL, nbctl_lr_list, NULL, "", RO },
1822 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
1825 /* Registers nbctl and common db commands. */
1827 nbctl_cmd_init(void)
1829 ctl_init(tables, NULL, nbctl_exit);
1830 ctl_register_commands(nbctl_commands);