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"
26 #include "openvswitch/json.h"
27 #include "ovn/lib/ovn-nb-idl.h"
29 #include "poll-loop.h"
34 #include "stream-ssl.h"
39 #include "openvswitch/vlog.h"
41 VLOG_DEFINE_THIS_MODULE(nbctl);
43 /* --db: The database server to contact. */
44 static const char *db;
46 /* --oneline: Write each command's output as a single line? */
49 /* --dry-run: Do not commit any changes. */
52 /* --wait=TYPE: Wait for configuration change to take effect? */
53 enum nbctl_wait_type {
54 NBCTL_WAIT_NONE, /* Do not wait. */
55 NBCTL_WAIT_SB, /* Wait for southbound database updates. */
56 NBCTL_WAIT_HV /* Wait for hypervisors to catch up. */
58 static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE;
60 /* --timeout: Time to wait for a connection to 'db'. */
63 /* Format for table output. */
64 static struct table_style table_style = TABLE_STYLE_DEFAULT;
66 /* The IDL we're using and the current transaction, if any.
67 * This is for use by nbctl_exit() only, to allow it to clean up.
68 * Other code should use its context arguments. */
69 static struct ovsdb_idl *the_idl;
70 static struct ovsdb_idl_txn *the_idl_txn;
71 OVS_NO_RETURN static void nbctl_exit(int status);
73 static void nbctl_cmd_init(void);
74 OVS_NO_RETURN static void usage(void);
75 static void parse_options(int argc, char *argv[], struct shash *local_options);
76 static const char *nbctl_default_db(void);
77 static void run_prerequisites(struct ctl_command[], size_t n_commands,
79 static bool do_nbctl(const char *args, struct ctl_command *, size_t n,
81 static const struct nbrec_dhcp_options *dhcp_options_get(
82 struct ctl_context *ctx, const char *id, bool must_exist);
85 main(int argc, char *argv[])
87 struct ovsdb_idl *idl;
88 struct ctl_command *commands;
89 struct shash local_options;
94 set_program_name(argv[0]);
95 fatal_ignore_sigpipe();
96 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
97 vlog_set_levels_from_string_assert("reconnect:warn");
102 /* Log our arguments. This is often valuable for debugging systems. */
103 args = process_escape_args(argv);
104 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
105 "Called as %s", args);
107 /* Parse command line. */
108 shash_init(&local_options);
109 parse_options(argc, argv, &local_options);
110 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
117 /* Initialize IDL. */
118 idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
119 run_prerequisites(commands, n_commands, idl);
121 /* Execute the commands.
123 * 'seqno' is the database sequence number for which we last tried to
124 * execute our transaction. There's no point in trying to commit more than
125 * once for any given sequence number, because if the transaction fails
126 * it's because the database changed and we need to obtain an up-to-date
127 * view of the database before we try the transaction again. */
128 seqno = ovsdb_idl_get_seqno(idl);
131 if (!ovsdb_idl_is_alive(idl)) {
132 int retval = ovsdb_idl_get_last_error(idl);
133 ctl_fatal("%s: database connection failed (%s)",
134 db, ovs_retval_to_string(retval));
137 if (seqno != ovsdb_idl_get_seqno(idl)) {
138 seqno = ovsdb_idl_get_seqno(idl);
139 if (do_nbctl(args, commands, n_commands, idl)) {
145 if (seqno == ovsdb_idl_get_seqno(idl)) {
153 nbctl_default_db(void)
157 def = getenv("OVN_NB_DB");
159 def = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
166 parse_options(int argc, char *argv[], struct shash *local_options)
169 OPT_DB = UCHAR_MAX + 1,
181 static const struct option global_long_options[] = {
182 {"db", required_argument, NULL, OPT_DB},
183 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
184 {"no-wait", no_argument, NULL, OPT_NO_WAIT},
185 {"wait", required_argument, NULL, OPT_WAIT},
186 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
187 {"oneline", no_argument, NULL, OPT_ONELINE},
188 {"timeout", required_argument, NULL, 't'},
189 {"help", no_argument, NULL, 'h'},
190 {"commands", no_argument, NULL, OPT_COMMANDS},
191 {"options", no_argument, NULL, OPT_OPTIONS},
192 {"version", no_argument, NULL, 'V'},
194 STREAM_SSL_LONG_OPTIONS,
198 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
199 char *tmp, *short_options;
201 struct option *options;
202 size_t allocated_options;
206 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
207 short_options = xasprintf("+%s", tmp);
210 /* We want to parse both global and command-specific options here, but
211 * getopt_long() isn't too convenient for the job. We copy our global
212 * options into a dynamic array, then append all of the command-specific
214 options = xmemdup(global_long_options, sizeof global_long_options);
215 allocated_options = ARRAY_SIZE(global_long_options);
216 n_options = n_global_long_options;
217 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
218 table_style.format = TF_LIST;
224 c = getopt_long(argc, argv, short_options, options, &idx);
239 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
243 wait_type = NBCTL_WAIT_NONE;
247 if (!strcmp(optarg, "none")) {
248 wait_type = NBCTL_WAIT_NONE;
249 } else if (!strcmp(optarg, "sb")) {
250 wait_type = NBCTL_WAIT_SB;
251 } else if (!strcmp(optarg, "hv")) {
252 wait_type = NBCTL_WAIT_HV;
254 ctl_fatal("argument to --wait must be "
255 "\"none\", \"sb\", or \"hv\"");
264 if (shash_find(local_options, options[idx].name)) {
265 ctl_fatal("'%s' option specified multiple times",
268 shash_add_nocopy(local_options,
269 xasprintf("--%s", options[idx].name),
270 nullable_xstrdup(optarg));
278 ctl_print_commands();
281 ctl_print_options(global_long_options);
284 ovs_print_version(0, 0);
285 printf("DB Schema %s\n", nbrec_get_db_version());
289 timeout = strtoul(optarg, NULL, 10);
291 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
296 TABLE_OPTION_HANDLERS(&table_style)
297 STREAM_SSL_OPTION_HANDLERS
309 db = nbctl_default_db();
312 for (i = n_global_long_options; options[i].name; i++) {
313 free(CONST_CAST(char *, options[i].name));
322 %s: OVN northbound DB management utility\n\
323 usage: %s [OPTIONS] COMMAND [ARG...]\n\
326 init initialize the database\n\
327 show print overview of database contents\n\
328 show SWITCH print overview of database contents for SWITCH\n\
329 show ROUTER print overview of database contents for ROUTER\n\
331 Logical switch commands:\n\
332 ls-add [SWITCH] create a logical switch named SWITCH\n\
333 ls-del SWITCH delete SWITCH and all its ports\n\
334 ls-list print the names of all logical switches\n\
337 acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
338 add an ACL to SWITCH\n\
339 acl-del SWITCH [DIRECTION [PRIORITY MATCH]]\n\
340 remove ACLs from SWITCH\n\
341 acl-list SWITCH print ACLs for SWITCH\n\
343 Logical switch port commands:\n\
344 lsp-add SWITCH PORT add logical port PORT on SWITCH\n\
345 lsp-add SWITCH PORT PARENT TAG\n\
346 add logical port PORT on SWITCH with PARENT\n\
348 lsp-del PORT delete PORT from its attached switch\n\
349 lsp-list SWITCH print the names of all logical ports on SWITCH\n\
350 lsp-get-parent PORT get the parent of PORT if set\n\
351 lsp-get-tag PORT get the PORT's tag if set\n\
352 lsp-set-addresses PORT [ADDRESS]...\n\
353 set MAC or MAC+IP addresses for PORT.\n\
354 lsp-get-addresses PORT get a list of MAC addresses on PORT\n\
355 lsp-set-port-security PORT [ADDRS]...\n\
356 set port security addresses for PORT.\n\
357 lsp-get-port-security PORT get PORT's port security addresses\n\
358 lsp-get-up PORT get state of PORT ('up' or 'down')\n\
359 lsp-set-enabled PORT STATE\n\
360 set administrative state PORT\n\
361 ('enabled' or 'disabled')\n\
362 lsp-get-enabled PORT get administrative state PORT\n\
363 ('enabled' or 'disabled')\n\
364 lsp-set-type PORT TYPE set the type for PORT\n\
365 lsp-get-type PORT get the type for PORT\n\
366 lsp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\
367 set options related to the type of PORT\n\
368 lsp-get-options PORT get the type specific options for PORT\n\
369 lsp-set-dhcpv4-options PORT [DHCP_OPTIONS_UUID]\n\
370 set dhcpv4 options for PORT\n\
371 lsp-get-dhcpv4-options PORT get the dhcpv4 options for PORT\n\
373 Logical router commands:\n\
374 lr-add [ROUTER] create a logical router named ROUTER\n\
375 lr-del ROUTER delete ROUTER and all its ports\n\
376 lr-list print the names of all logical routers\n\
378 Logical router port commands:\n\
379 lrp-add ROUTER PORT MAC NETWORK... [peer=PEER]\n\
380 add logical port PORT on ROUTER\n\
381 lrp-del PORT delete PORT from its attached router\n\
382 lrp-list ROUTER print the names of all ports on ROUTER\n\
383 lrp-set-enabled PORT STATE\n\
384 set administrative state PORT\n\
385 ('enabled' or 'disabled')\n\
386 lrp-get-enabled PORT get administrative state PORT\n\
387 ('enabled' or 'disabled')\n\
390 lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
391 add a route to ROUTER\n\
392 lr-route-del ROUTER [PREFIX]\n\
393 remove routes from ROUTER\n\
394 lr-route-list ROUTER print routes for ROUTER\n\
397 DHCP Options commands:\n\
398 dhcp-options-create CIDR [EXTERNAL_IDS]\n\
399 create a DHCP options row with CIDR\n\
400 dhcp-options-del DHCP_OPTIONS_UUID\n\
401 delete DHCP_OPTIONS_UUID\n\
402 dhcp-options-list \n\
403 lists the DHCP_Options rows\n\
404 dhcp-options-set-options DHCP_OPTIONS_UUID KEY=VALUE [KEY=VALUE]...\n\
405 set DHCP options to the DHCP_OPTIONS_UUID\n\
406 dhcp-options-get-options DHCO_OPTIONS_UUID \n\
407 displays the DHCP options of th DHCP_OPTIONS_UUID\n\
412 --db=DATABASE connect to DATABASE\n\
414 --no-wait, --wait=none do not wait for OVN reconfiguration (default)\n\
415 --wait=sb wait for southbound database update\n\
416 --wait=hv wait for all chassis to catch up\n\
417 -t, --timeout=SECS wait at most SECS seconds\n\
418 --dry-run do not commit changes to database\n\
419 --oneline print exactly one line of output per command\n",
420 program_name, program_name, ctl_get_db_cmd_usage(), nbctl_default_db());
423 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
426 -h, --help display this help message\n\
427 -V, --version display version information\n");
432 /* Find a logical router given its id. */
433 static const struct nbrec_logical_router *
434 lr_by_name_or_uuid(struct ctl_context *ctx, const char *id,
437 const struct nbrec_logical_router *lr = NULL;
438 bool is_uuid = false;
441 if (uuid_from_string(&lr_uuid, id)) {
443 lr = nbrec_logical_router_get_for_uuid(ctx->idl, &lr_uuid);
447 const struct nbrec_logical_router *iter;
449 NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
450 if (strcmp(iter->name, id)) {
454 ctl_fatal("Multiple logical routers named '%s'. "
461 if (!lr && must_exist) {
462 ctl_fatal("%s: router %s not found", id, is_uuid ? "UUID" : "name");
468 static const struct nbrec_logical_switch *
469 ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
471 const struct nbrec_logical_switch *ls = NULL;
474 bool is_uuid = uuid_from_string(&ls_uuid, id);
476 ls = nbrec_logical_switch_get_for_uuid(ctx->idl, &ls_uuid);
480 const struct nbrec_logical_switch *iter;
482 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
483 if (strcmp(iter->name, id)) {
487 ctl_fatal("Multiple logical switches named '%s'. "
494 if (!ls && must_exist) {
495 ctl_fatal("%s: switch %s not found", id, is_uuid ? "UUID" : "name");
501 /* Given pointer to logical router, this routine prints the router
504 print_lr(const struct nbrec_logical_router *lr, struct ds *s)
506 ds_put_format(s, " router "UUID_FMT" (%s)\n",
507 UUID_ARGS(&lr->header_.uuid), lr->name);
509 for (size_t i = 0; i < lr->n_ports; i++) {
510 const struct nbrec_logical_router_port *lrp = lr->ports[i];
511 ds_put_format(s, " port %s\n", lrp->name);
513 ds_put_cstr(s, " mac: ");
514 ds_put_format(s, "\"%s\"\n", lrp->mac);
516 if (lrp->n_networks) {
517 ds_put_cstr(s, " networks: [");
518 for (size_t j = 0; j < lrp->n_networks; j++) {
519 ds_put_format(s, "%s\"%s\"",
523 ds_put_cstr(s, "]\n");
529 print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
531 ds_put_format(s, " switch "UUID_FMT" (%s)\n",
532 UUID_ARGS(&ls->header_.uuid), ls->name);
534 for (size_t i = 0; i < ls->n_ports; i++) {
535 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
537 ds_put_format(s, " port %s\n", lsp->name);
538 if (lsp->parent_name) {
539 ds_put_format(s, " parent: %s\n", lsp->parent_name);
542 ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
544 if (lsp->n_addresses) {
545 ds_put_cstr(s, " addresses: [");
546 for (size_t j = 0; j < lsp->n_addresses; j++) {
547 ds_put_format(s, "%s\"%s\"",
551 ds_put_cstr(s, "]\n");
557 nbctl_init(struct ctl_context *ctx OVS_UNUSED)
562 nbctl_show(struct ctl_context *ctx)
564 const struct nbrec_logical_switch *ls;
566 if (ctx->argc == 2) {
567 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
569 print_ls(ls, &ctx->output);
572 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
573 print_ls(ls, &ctx->output);
576 const struct nbrec_logical_router *lr;
578 if (ctx->argc == 2) {
579 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
581 print_lr(lr, &ctx->output);
584 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
585 print_lr(lr, &ctx->output);
591 nbctl_ls_add(struct ctl_context *ctx)
593 const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
595 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
596 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
597 if (may_exist && add_duplicate) {
598 ctl_fatal("--may-exist and --add-duplicate may not be used together");
602 if (!add_duplicate) {
603 const struct nbrec_logical_switch *ls;
604 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
605 if (!strcmp(ls->name, ls_name)) {
609 ctl_fatal("%s: a switch with this name already exists",
614 } else if (may_exist) {
615 ctl_fatal("--may-exist requires specifying a name");
616 } else if (add_duplicate) {
617 ctl_fatal("--add-duplicate requires specifying a name");
620 struct nbrec_logical_switch *ls;
621 ls = nbrec_logical_switch_insert(ctx->txn);
623 nbrec_logical_switch_set_name(ls, ls_name);
628 nbctl_ls_del(struct ctl_context *ctx)
630 bool must_exist = !shash_find(&ctx->options, "--if-exists");
631 const char *id = ctx->argv[1];
632 const struct nbrec_logical_switch *ls;
634 ls = ls_by_name_or_uuid(ctx, id, must_exist);
639 nbrec_logical_switch_delete(ls);
643 nbctl_ls_list(struct ctl_context *ctx)
645 const struct nbrec_logical_switch *ls;
646 struct smap lswitches;
648 smap_init(&lswitches);
649 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
650 smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
651 UUID_ARGS(&ls->header_.uuid), ls->name);
653 const struct smap_node **nodes = smap_sort(&lswitches);
654 for (size_t i = 0; i < smap_count(&lswitches); i++) {
655 const struct smap_node *node = nodes[i];
656 ds_put_format(&ctx->output, "%s\n", node->value);
658 smap_destroy(&lswitches);
662 static const struct nbrec_logical_switch_port *
663 lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
666 const struct nbrec_logical_switch_port *lsp = NULL;
668 struct uuid lsp_uuid;
669 bool is_uuid = uuid_from_string(&lsp_uuid, id);
671 lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
675 NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
676 if (!strcmp(lsp->name, id)) {
682 if (!lsp && must_exist) {
683 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
689 /* Returns the logical switch that contains 'lsp'. */
690 static const struct nbrec_logical_switch *
691 lsp_to_ls(const struct ovsdb_idl *idl,
692 const struct nbrec_logical_switch_port *lsp)
694 const struct nbrec_logical_switch *ls;
695 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, idl) {
696 for (size_t i = 0; i < ls->n_ports; i++) {
697 if (ls->ports[i] == lsp) {
703 /* Can't happen because of the database schema */
704 ctl_fatal("logical port %s is not part of any logical switch",
709 ls_get_name(const struct nbrec_logical_switch *ls,
710 char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
715 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&ls->header_.uuid));
720 nbctl_lsp_add(struct ctl_context *ctx)
722 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
724 const struct nbrec_logical_switch *ls;
725 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
727 const char *parent_name;
729 if (ctx->argc == 3) {
732 } else if (ctx->argc == 5) {
734 parent_name = ctx->argv[3];
735 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag)
736 || tag < 0 || tag > 4095) {
737 ctl_fatal("%s: invalid tag", ctx->argv[4]);
740 ctl_fatal("lsp-add with parent must also specify a tag");
743 const char *lsp_name = ctx->argv[2];
744 const struct nbrec_logical_switch_port *lsp;
745 lsp = lsp_by_name_or_uuid(ctx, lsp_name, false);
748 ctl_fatal("%s: a port with this name already exists",
752 const struct nbrec_logical_switch *lsw;
753 lsw = lsp_to_ls(ctx->idl, lsp);
755 char uuid_s[UUID_LEN + 1];
756 ctl_fatal("%s: port already exists but in switch %s", lsp_name,
757 ls_get_name(lsw, uuid_s, sizeof uuid_s));
761 if (!lsp->parent_name) {
762 ctl_fatal("%s: port already exists but has no parent",
764 } else if (strcmp(parent_name, lsp->parent_name)) {
765 ctl_fatal("%s: port already exists with different parent %s",
766 lsp_name, lsp->parent_name);
770 ctl_fatal("%s: port already exists but has no tag",
772 } else if (lsp->tag[0] != tag) {
773 ctl_fatal("%s: port already exists with different "
774 "tag %"PRId64, lsp_name, lsp->tag[0]);
777 if (lsp->parent_name) {
778 ctl_fatal("%s: port already exists but has parent %s",
779 lsp_name, lsp->parent_name);
786 /* Create the logical port. */
787 lsp = nbrec_logical_switch_port_insert(ctx->txn);
788 nbrec_logical_switch_port_set_name(lsp, lsp_name);
790 nbrec_logical_switch_port_set_parent_name(lsp, parent_name);
791 nbrec_logical_switch_port_set_tag(lsp, &tag, 1);
794 /* Insert the logical port into the logical switch. */
795 nbrec_logical_switch_verify_ports(ls);
796 struct nbrec_logical_switch_port **new_ports = xmalloc(sizeof *new_ports *
798 memcpy(new_ports, ls->ports, sizeof *new_ports * ls->n_ports);
799 new_ports[ls->n_ports] = CONST_CAST(struct nbrec_logical_switch_port *,
801 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports + 1);
805 /* Removes logical switch port 'ls->ports[idx]'. */
807 remove_lsp(const struct nbrec_logical_switch *ls, size_t idx)
809 const struct nbrec_logical_switch_port *lsp = ls->ports[idx];
811 /* First remove 'lsp' from the array of ports. This is what will
812 * actually cause the logical port to be deleted when the transaction is
813 * sent to the database server (due to garbage collection). */
814 struct nbrec_logical_switch_port **new_ports
815 = xmemdup(ls->ports, sizeof *new_ports * ls->n_ports);
816 new_ports[idx] = new_ports[ls->n_ports - 1];
817 nbrec_logical_switch_verify_ports(ls);
818 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports - 1);
821 /* Delete 'lsp' from the IDL. This won't have a real effect on the
822 * database server (the IDL will suppress it in fact) but it means that it
823 * won't show up when we iterate with NBREC_LOGICAL_SWITCH_PORT_FOR_EACH
825 nbrec_logical_switch_port_delete(lsp);
829 nbctl_lsp_del(struct ctl_context *ctx)
831 bool must_exist = !shash_find(&ctx->options, "--if-exists");
832 const struct nbrec_logical_switch_port *lsp;
834 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
839 /* Find the switch that contains 'lsp', then delete it. */
840 const struct nbrec_logical_switch *ls;
841 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
842 for (size_t i = 0; i < ls->n_ports; i++) {
843 if (ls->ports[i] == lsp) {
850 /* Can't happen because of the database schema. */
851 ctl_fatal("logical port %s is not part of any logical switch",
856 nbctl_lsp_list(struct ctl_context *ctx)
858 const char *id = ctx->argv[1];
859 const struct nbrec_logical_switch *ls;
863 ls = ls_by_name_or_uuid(ctx, id, true);
866 for (i = 0; i < ls->n_ports; i++) {
867 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
868 smap_add_format(&lsps, lsp->name, UUID_FMT " (%s)",
869 UUID_ARGS(&lsp->header_.uuid), lsp->name);
871 const struct smap_node **nodes = smap_sort(&lsps);
872 for (i = 0; i < smap_count(&lsps); i++) {
873 const struct smap_node *node = nodes[i];
874 ds_put_format(&ctx->output, "%s\n", node->value);
881 nbctl_lsp_get_parent(struct ctl_context *ctx)
883 const struct nbrec_logical_switch_port *lsp;
885 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
886 if (lsp->parent_name) {
887 ds_put_format(&ctx->output, "%s\n", lsp->parent_name);
892 nbctl_lsp_get_tag(struct ctl_context *ctx)
894 const struct nbrec_logical_switch_port *lsp;
896 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
897 if (lsp->n_tag > 0) {
898 ds_put_format(&ctx->output, "%"PRId64"\n", lsp->tag[0]);
903 nbctl_lsp_set_addresses(struct ctl_context *ctx)
905 const char *id = ctx->argv[1];
906 const struct nbrec_logical_switch_port *lsp;
908 lsp = lsp_by_name_or_uuid(ctx, id, true);
911 for (i = 2; i < ctx->argc; i++) {
914 if (strcmp(ctx->argv[i], "unknown")
915 && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
916 ETH_ADDR_SCAN_ARGS(ea))) {
917 ctl_fatal("%s: Invalid address format. See ovn-nb(5). "
918 "Hint: An Ethernet address must be "
919 "listed before an IP address, together as a single "
920 "argument.", ctx->argv[i]);
924 nbrec_logical_switch_port_set_addresses(lsp,
925 (const char **) ctx->argv + 2, ctx->argc - 2);
929 nbctl_lsp_get_addresses(struct ctl_context *ctx)
931 const char *id = ctx->argv[1];
932 const struct nbrec_logical_switch_port *lsp;
933 struct svec addresses;
937 lsp = lsp_by_name_or_uuid(ctx, id, true);
939 svec_init(&addresses);
940 for (i = 0; i < lsp->n_addresses; i++) {
941 svec_add(&addresses, lsp->addresses[i]);
943 svec_sort(&addresses);
944 SVEC_FOR_EACH(i, mac, &addresses) {
945 ds_put_format(&ctx->output, "%s\n", mac);
947 svec_destroy(&addresses);
951 nbctl_lsp_set_port_security(struct ctl_context *ctx)
953 const char *id = ctx->argv[1];
954 const struct nbrec_logical_switch_port *lsp;
956 lsp = lsp_by_name_or_uuid(ctx, id, true);
957 nbrec_logical_switch_port_set_port_security(lsp,
958 (const char **) ctx->argv + 2, ctx->argc - 2);
962 nbctl_lsp_get_port_security(struct ctl_context *ctx)
964 const char *id = ctx->argv[1];
965 const struct nbrec_logical_switch_port *lsp;
970 lsp = lsp_by_name_or_uuid(ctx, id, true);
972 for (i = 0; i < lsp->n_port_security; i++) {
973 svec_add(&addrs, lsp->port_security[i]);
976 SVEC_FOR_EACH(i, addr, &addrs) {
977 ds_put_format(&ctx->output, "%s\n", addr);
979 svec_destroy(&addrs);
983 nbctl_lsp_get_up(struct ctl_context *ctx)
985 const char *id = ctx->argv[1];
986 const struct nbrec_logical_switch_port *lsp;
988 lsp = lsp_by_name_or_uuid(ctx, id, true);
989 ds_put_format(&ctx->output,
990 "%s\n", (lsp->up && *lsp->up) ? "up" : "down");
994 parse_enabled(const char *state)
996 if (!strcasecmp(state, "enabled")) {
998 } else if (!strcasecmp(state, "disabled")) {
1001 ctl_fatal("%s: state must be \"enabled\" or \"disabled\"", state);
1006 nbctl_lsp_set_enabled(struct ctl_context *ctx)
1008 const char *id = ctx->argv[1];
1009 const char *state = ctx->argv[2];
1010 const struct nbrec_logical_switch_port *lsp;
1012 lsp = lsp_by_name_or_uuid(ctx, id, true);
1013 bool enabled = parse_enabled(state);
1014 nbrec_logical_switch_port_set_enabled(lsp, &enabled, 1);
1018 nbctl_lsp_get_enabled(struct ctl_context *ctx)
1020 const char *id = ctx->argv[1];
1021 const struct nbrec_logical_switch_port *lsp;
1023 lsp = lsp_by_name_or_uuid(ctx, id, true);
1024 ds_put_format(&ctx->output, "%s\n",
1025 !lsp->enabled || *lsp->enabled ? "enabled" : "disabled");
1029 nbctl_lsp_set_type(struct ctl_context *ctx)
1031 const char *id = ctx->argv[1];
1032 const char *type = ctx->argv[2];
1033 const struct nbrec_logical_switch_port *lsp;
1035 lsp = lsp_by_name_or_uuid(ctx, id, true);
1036 nbrec_logical_switch_port_set_type(lsp, type);
1040 nbctl_lsp_get_type(struct ctl_context *ctx)
1042 const char *id = ctx->argv[1];
1043 const struct nbrec_logical_switch_port *lsp;
1045 lsp = lsp_by_name_or_uuid(ctx, id, true);
1046 ds_put_format(&ctx->output, "%s\n", lsp->type);
1050 nbctl_lsp_set_options(struct ctl_context *ctx)
1052 const char *id = ctx->argv[1];
1053 const struct nbrec_logical_switch_port *lsp;
1055 struct smap options = SMAP_INITIALIZER(&options);
1057 lsp = lsp_by_name_or_uuid(ctx, id, true);
1058 for (i = 2; i < ctx->argc; i++) {
1060 value = xstrdup(ctx->argv[i]);
1061 key = strsep(&value, "=");
1063 smap_add(&options, key, value);
1068 nbrec_logical_switch_port_set_options(lsp, &options);
1070 smap_destroy(&options);
1074 nbctl_lsp_get_options(struct ctl_context *ctx)
1076 const char *id = ctx->argv[1];
1077 const struct nbrec_logical_switch_port *lsp;
1078 struct smap_node *node;
1080 lsp = lsp_by_name_or_uuid(ctx, id, true);
1081 SMAP_FOR_EACH(node, &lsp->options) {
1082 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1087 nbctl_lsp_set_dhcpv4_options(struct ctl_context *ctx)
1089 const char *id = ctx->argv[1];
1090 const struct nbrec_logical_switch_port *lsp;
1092 lsp = lsp_by_name_or_uuid(ctx, id, true);
1093 const struct nbrec_dhcp_options *dhcp_opt = NULL;
1094 if (ctx->argc == 3 ) {
1095 dhcp_opt = dhcp_options_get(ctx, ctx->argv[2], true);
1101 char *error = ip_parse_cidr(dhcp_opt->cidr, &ip, &plen);
1104 ctl_fatal("DHCP options cidr '%s' is not IPv4", dhcp_opt->cidr);
1108 nbrec_logical_switch_port_set_dhcpv4_options(lsp, dhcp_opt);
1112 nbctl_lsp_get_dhcpv4_options(struct ctl_context *ctx)
1114 const char *id = ctx->argv[1];
1115 const struct nbrec_logical_switch_port *lsp;
1117 lsp = lsp_by_name_or_uuid(ctx, id, true);
1118 if (lsp->dhcpv4_options) {
1119 ds_put_format(&ctx->output, UUID_FMT " (%s)\n",
1120 UUID_ARGS(&lsp->dhcpv4_options->header_.uuid),
1121 lsp->dhcpv4_options->cidr);
1131 dir_encode(const char *dir)
1133 if (!strcmp(dir, "from-lport")) {
1134 return DIR_FROM_LPORT;
1135 } else if (!strcmp(dir, "to-lport")) {
1136 return DIR_TO_LPORT;
1143 acl_cmp(const void *acl1_, const void *acl2_)
1145 const struct nbrec_acl *const *acl1p = acl1_;
1146 const struct nbrec_acl *const *acl2p = acl2_;
1147 const struct nbrec_acl *acl1 = *acl1p;
1148 const struct nbrec_acl *acl2 = *acl2p;
1150 int dir1 = dir_encode(acl1->direction);
1151 int dir2 = dir_encode(acl2->direction);
1154 return dir1 < dir2 ? -1 : 1;
1155 } else if (acl1->priority != acl2->priority) {
1156 return acl1->priority > acl2->priority ? -1 : 1;
1158 return strcmp(acl1->match, acl2->match);
1163 nbctl_acl_list(struct ctl_context *ctx)
1165 const struct nbrec_logical_switch *ls;
1166 const struct nbrec_acl **acls;
1169 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1171 acls = xmalloc(sizeof *acls * ls->n_acls);
1172 for (i = 0; i < ls->n_acls; i++) {
1173 acls[i] = ls->acls[i];
1176 qsort(acls, ls->n_acls, sizeof *acls, acl_cmp);
1178 for (i = 0; i < ls->n_acls; i++) {
1179 const struct nbrec_acl *acl = acls[i];
1180 ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s%s\n",
1181 acl->direction, acl->priority,
1182 acl->match, acl->action, acl->log ? " log" : "");
1189 parse_direction(const char *arg)
1191 /* Validate direction. Only require the first letter. */
1192 if (arg[0] == 't') {
1194 } else if (arg[0] == 'f') {
1195 return "from-lport";
1197 ctl_fatal("%s: direction must be \"to-lport\" or \"from-lport\"", arg);
1202 parse_priority(const char *arg)
1204 /* Validate priority. */
1206 if (!ovs_scan(arg, "%"SCNd64, &priority)
1207 || priority < 0 || priority > 32767) {
1208 ctl_fatal("%s: priority must in range 0...32767", arg);
1214 nbctl_acl_add(struct ctl_context *ctx)
1216 const struct nbrec_logical_switch *ls;
1217 const char *action = ctx->argv[5];
1219 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1221 const char *direction = parse_direction(ctx->argv[2]);
1222 int64_t priority = parse_priority(ctx->argv[3]);
1224 /* Validate action. */
1225 if (strcmp(action, "allow") && strcmp(action, "allow-related")
1226 && strcmp(action, "drop") && strcmp(action, "reject")) {
1227 ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
1228 "\"drop\", and \"reject\"", action);
1232 /* Create the acl. */
1233 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1234 nbrec_acl_set_priority(acl, priority);
1235 nbrec_acl_set_direction(acl, direction);
1236 nbrec_acl_set_match(acl, ctx->argv[4]);
1237 nbrec_acl_set_action(acl, action);
1238 if (shash_find(&ctx->options, "--log") != NULL) {
1239 nbrec_acl_set_log(acl, true);
1242 /* Insert the acl into the logical switch. */
1243 nbrec_logical_switch_verify_acls(ls);
1244 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * (ls->n_acls + 1));
1245 memcpy(new_acls, ls->acls, sizeof *new_acls * ls->n_acls);
1246 new_acls[ls->n_acls] = acl;
1247 nbrec_logical_switch_set_acls(ls, new_acls, ls->n_acls + 1);
1252 nbctl_acl_del(struct ctl_context *ctx)
1254 const struct nbrec_logical_switch *ls;
1255 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1257 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1258 ctl_fatal("cannot specify priority without match");
1261 if (ctx->argc == 2) {
1262 /* If direction, priority, and match are not specified, delete
1264 nbrec_logical_switch_verify_acls(ls);
1265 nbrec_logical_switch_set_acls(ls, NULL, 0);
1269 const char *direction = parse_direction(ctx->argv[2]);
1271 /* If priority and match are not specified, delete all ACLs with the
1272 * specified direction. */
1273 if (ctx->argc == 3) {
1274 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * ls->n_acls);
1277 for (size_t i = 0; i < ls->n_acls; i++) {
1278 if (strcmp(direction, ls->acls[i]->direction)) {
1279 new_acls[n_acls++] = ls->acls[i];
1283 nbrec_logical_switch_verify_acls(ls);
1284 nbrec_logical_switch_set_acls(ls, new_acls, n_acls);
1289 int64_t priority = parse_priority(ctx->argv[3]);
1291 /* Remove the matching rule. */
1292 for (size_t i = 0; i < ls->n_acls; i++) {
1293 struct nbrec_acl *acl = ls->acls[i];
1295 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1296 !strcmp(direction, acl->direction)) {
1297 struct nbrec_acl **new_acls
1298 = xmemdup(ls->acls, sizeof *new_acls * ls->n_acls);
1299 new_acls[i] = ls->acls[ls->n_acls - 1];
1300 nbrec_logical_switch_verify_acls(ls);
1301 nbrec_logical_switch_set_acls(ls, new_acls,
1310 nbctl_lr_add(struct ctl_context *ctx)
1312 const char *lr_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
1314 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1315 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1316 if (may_exist && add_duplicate) {
1317 ctl_fatal("--may-exist and --add-duplicate may not be used together");
1321 if (!add_duplicate) {
1322 const struct nbrec_logical_router *lr;
1323 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1324 if (!strcmp(lr->name, lr_name)) {
1328 ctl_fatal("%s: a router with this name already exists",
1333 } else if (may_exist) {
1334 ctl_fatal("--may-exist requires specifying a name");
1335 } else if (add_duplicate) {
1336 ctl_fatal("--add-duplicate requires specifying a name");
1339 struct nbrec_logical_router *lr;
1340 lr = nbrec_logical_router_insert(ctx->txn);
1342 nbrec_logical_router_set_name(lr, lr_name);
1347 nbctl_lr_del(struct ctl_context *ctx)
1349 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1350 const char *id = ctx->argv[1];
1351 const struct nbrec_logical_router *lr;
1353 lr = lr_by_name_or_uuid(ctx, id, must_exist);
1358 nbrec_logical_router_delete(lr);
1362 nbctl_lr_list(struct ctl_context *ctx)
1364 const struct nbrec_logical_router *lr;
1368 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
1369 smap_add_format(&lrs, lr->name, UUID_FMT " (%s)",
1370 UUID_ARGS(&lr->header_.uuid), lr->name);
1372 const struct smap_node **nodes = smap_sort(&lrs);
1373 for (size_t i = 0; i < smap_count(&lrs); i++) {
1374 const struct smap_node *node = nodes[i];
1375 ds_put_format(&ctx->output, "%s\n", node->value);
1381 static const struct nbrec_dhcp_options *
1382 dhcp_options_get(struct ctl_context *ctx, const char *id, bool must_exist)
1384 struct uuid dhcp_opts_uuid;
1385 const struct nbrec_dhcp_options *dhcp_opts = NULL;
1386 if (uuid_from_string(&dhcp_opts_uuid, id)) {
1387 dhcp_opts = nbrec_dhcp_options_get_for_uuid(ctx->idl, &dhcp_opts_uuid);
1390 if (!dhcp_opts && must_exist) {
1391 ctl_fatal("%s: dhcp options UUID not found", id);
1397 nbctl_dhcp_options_create(struct ctl_context *ctx)
1399 /* Validate the cidr */
1402 char *error = ip_parse_cidr(ctx->argv[1], &ip, &plen);
1404 /* check if its IPv6 cidr */
1406 struct in6_addr ipv6;
1407 error = ipv6_parse_cidr(ctx->argv[1], &ipv6, &plen);
1410 ctl_fatal("Invalid cidr format '%s'", ctx->argv[1]);
1415 struct nbrec_dhcp_options *dhcp_opts = nbrec_dhcp_options_insert(ctx->txn);
1416 nbrec_dhcp_options_set_cidr(dhcp_opts, ctx->argv[1]);
1418 struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
1419 for (size_t i = 2; i < ctx->argc; i++) {
1421 value = xstrdup(ctx->argv[i]);
1422 key = strsep(&value, "=");
1424 smap_add(&ext_ids, key, value);
1429 nbrec_dhcp_options_set_external_ids(dhcp_opts, &ext_ids);
1430 smap_destroy(&ext_ids);
1434 nbctl_dhcp_options_set_options(struct ctl_context *ctx)
1436 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1437 ctx, ctx->argv[1], true);
1439 struct smap dhcp_options = SMAP_INITIALIZER(&dhcp_options);
1440 for (size_t i = 2; i < ctx->argc; i++) {
1442 value = xstrdup(ctx->argv[i]);
1443 key = strsep(&value, "=");
1445 smap_add(&dhcp_options, key, value);
1450 nbrec_dhcp_options_set_options(dhcp_opts, &dhcp_options);
1451 smap_destroy(&dhcp_options);
1455 nbctl_dhcp_options_get_options(struct ctl_context *ctx)
1457 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1458 ctx, ctx->argv[1], true);
1460 struct smap_node *node;
1461 SMAP_FOR_EACH(node, &dhcp_opts->options) {
1462 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1467 nbctl_dhcp_options_del(struct ctl_context *ctx)
1469 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1470 const char *id = ctx->argv[1];
1471 const struct nbrec_dhcp_options *dhcp_opts;
1473 dhcp_opts = dhcp_options_get(ctx, id, must_exist);
1478 nbrec_dhcp_options_delete(dhcp_opts);
1482 nbctl_dhcp_options_list(struct ctl_context *ctx)
1484 const struct nbrec_dhcp_options *dhcp_opts;
1485 struct smap dhcp_options;
1487 smap_init(&dhcp_options);
1488 NBREC_DHCP_OPTIONS_FOR_EACH(dhcp_opts, ctx->idl) {
1489 smap_add_format(&dhcp_options, dhcp_opts->cidr, UUID_FMT,
1490 UUID_ARGS(&dhcp_opts->header_.uuid));
1492 const struct smap_node **nodes = smap_sort(&dhcp_options);
1493 for (size_t i = 0; i < smap_count(&dhcp_options); i++) {
1494 const struct smap_node *node = nodes[i];
1495 ds_put_format(&ctx->output, "%s\n", node->value);
1497 smap_destroy(&dhcp_options);
1501 /* The caller must free the returned string. */
1503 normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
1505 ovs_be32 network = ipv4 & be32_prefix_mask(plen);
1507 return xasprintf(IP_FMT, IP_ARGS(network));
1509 return xasprintf(IP_FMT"/%d", IP_ARGS(network), plen);
1513 /* The caller must free the returned string. */
1515 normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
1517 char network_s[INET6_ADDRSTRLEN];
1519 struct in6_addr mask = ipv6_create_mask(plen);
1520 struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
1522 inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
1524 return xasprintf("%s", network_s);
1526 return xasprintf("%s/%d", network_s, plen);
1530 /* The caller must free the returned string. */
1532 normalize_prefix_str(const char *orig_prefix)
1538 error = ip_parse_cidr(orig_prefix, &ipv4, &plen);
1540 return normalize_ipv4_prefix(ipv4, plen);
1542 struct in6_addr ipv6;
1545 error = ipv6_parse_cidr(orig_prefix, &ipv6, &plen);
1550 return normalize_ipv6_prefix(ipv6, plen);
1555 nbctl_lr_route_add(struct ctl_context *ctx)
1557 const struct nbrec_logical_router *lr;
1558 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1559 char *prefix, *next_hop;
1561 prefix = normalize_prefix_str(ctx->argv[2]);
1563 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1566 next_hop = normalize_prefix_str(ctx->argv[3]);
1568 ctl_fatal("bad next hop argument: %s", ctx->argv[3]);
1571 if (strchr(prefix, '.')) {
1573 if (!ip_parse(ctx->argv[3], &hop_ipv4)) {
1574 ctl_fatal("bad IPv4 nexthop argument: %s", ctx->argv[3]);
1577 struct in6_addr hop_ipv6;
1578 if (!ipv6_parse(ctx->argv[3], &hop_ipv6)) {
1579 ctl_fatal("bad IPv6 nexthop argument: %s", ctx->argv[3]);
1583 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1584 for (int i = 0; i < lr->n_static_routes; i++) {
1585 const struct nbrec_logical_router_static_route *route
1586 = lr->static_routes[i];
1589 rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1591 /* Ignore existing prefix we couldn't parse. */
1595 if (strcmp(rt_prefix, prefix)) {
1601 ctl_fatal("duplicate prefix: %s", prefix);
1604 /* Update the next hop for an existing route. */
1605 nbrec_logical_router_verify_static_routes(lr);
1606 nbrec_logical_router_static_route_verify_ip_prefix(route);
1607 nbrec_logical_router_static_route_verify_nexthop(route);
1608 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1609 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1610 if (ctx->argc == 5) {
1611 nbrec_logical_router_static_route_set_output_port(route,
1620 struct nbrec_logical_router_static_route *route;
1621 route = nbrec_logical_router_static_route_insert(ctx->txn);
1622 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1623 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1624 if (ctx->argc == 5) {
1625 nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]);
1628 nbrec_logical_router_verify_static_routes(lr);
1629 struct nbrec_logical_router_static_route **new_routes
1630 = xmalloc(sizeof *new_routes * (lr->n_static_routes + 1));
1631 memcpy(new_routes, lr->static_routes,
1632 sizeof *new_routes * lr->n_static_routes);
1633 new_routes[lr->n_static_routes] = route;
1634 nbrec_logical_router_set_static_routes(lr, new_routes,
1635 lr->n_static_routes + 1);
1642 nbctl_lr_route_del(struct ctl_context *ctx)
1644 const struct nbrec_logical_router *lr;
1645 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1647 if (ctx->argc == 2) {
1648 /* If a prefix is not specified, delete all routes. */
1649 nbrec_logical_router_set_static_routes(lr, NULL, 0);
1653 char *prefix = normalize_prefix_str(ctx->argv[2]);
1655 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1658 for (int i = 0; i < lr->n_static_routes; i++) {
1659 char *rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1661 /* Ignore existing prefix we couldn't parse. */
1665 if (!strcmp(prefix, rt_prefix)) {
1666 struct nbrec_logical_router_static_route **new_routes
1667 = xmemdup(lr->static_routes,
1668 sizeof *new_routes * lr->n_static_routes);
1670 new_routes[i] = lr->static_routes[lr->n_static_routes - 1];
1671 nbrec_logical_router_verify_static_routes(lr);
1672 nbrec_logical_router_set_static_routes(lr, new_routes,
1673 lr->n_static_routes - 1);
1682 if (!shash_find(&ctx->options, "--if-exists")) {
1683 ctl_fatal("no matching prefix: %s", prefix);
1688 static const struct nbrec_logical_router_port *
1689 lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
1691 const struct nbrec_logical_router_port *lrp = NULL;
1693 struct uuid lrp_uuid;
1694 bool is_uuid = uuid_from_string(&lrp_uuid, id);
1696 lrp = nbrec_logical_router_port_get_for_uuid(ctx->idl, &lrp_uuid);
1700 NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrp, ctx->idl) {
1701 if (!strcmp(lrp->name, id)) {
1707 if (!lrp && must_exist) {
1708 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
1714 /* Returns the logical router that contains 'lrp'. */
1715 static const struct nbrec_logical_router *
1716 lrp_to_lr(const struct ovsdb_idl *idl,
1717 const struct nbrec_logical_router_port *lrp)
1719 const struct nbrec_logical_router *lr;
1720 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, idl) {
1721 for (size_t i = 0; i < lr->n_ports; i++) {
1722 if (lr->ports[i] == lrp) {
1728 /* Can't happen because of the database schema */
1729 ctl_fatal("port %s is not part of any logical router",
1734 lr_get_name(const struct nbrec_logical_router *lr, char uuid_s[UUID_LEN + 1],
1740 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lr->header_.uuid));
1745 nbctl_lrp_add(struct ctl_context *ctx)
1747 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1749 const struct nbrec_logical_router *lr;
1750 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1752 const char *lrp_name = ctx->argv[2];
1753 const char *mac = ctx->argv[3];
1754 const char **networks = (const char **) &ctx->argv[4];
1756 int n_networks = ctx->argc - 4;
1757 for (int i = 4; i < ctx->argc; i++) {
1758 if (strchr(ctx->argv[i], '=')) {
1765 ctl_fatal("%s: router port requires specifying a network", lrp_name);
1768 char **settings = (char **) &ctx->argv[n_networks + 4];
1769 int n_settings = ctx->argc - 4 - n_networks;
1771 const struct nbrec_logical_router_port *lrp;
1772 lrp = lrp_by_name_or_uuid(ctx, lrp_name, false);
1775 ctl_fatal("%s: a port with this name already exists",
1779 const struct nbrec_logical_router *bound_lr;
1780 bound_lr = lrp_to_lr(ctx->idl, lrp);
1781 if (bound_lr != lr) {
1782 char uuid_s[UUID_LEN + 1];
1783 ctl_fatal("%s: port already exists but in router %s", lrp_name,
1784 lr_get_name(bound_lr, uuid_s, sizeof uuid_s));
1787 if (strcmp(mac, lrp->mac)) {
1788 ctl_fatal("%s: port already exists with mac %s", lrp_name,
1792 struct sset new_networks = SSET_INITIALIZER(&new_networks);
1793 for (int i = 0; i < n_networks; i++) {
1794 sset_add(&new_networks, networks[i]);
1797 struct sset orig_networks = SSET_INITIALIZER(&orig_networks);
1798 sset_add_array(&orig_networks, lrp->networks, lrp->n_networks);
1800 if (!sset_equals(&orig_networks, &new_networks)) {
1801 ctl_fatal("%s: port already exists with different network",
1805 sset_destroy(&orig_networks);
1806 sset_destroy(&new_networks);
1808 /* Special-case sanity-check of peer ports. */
1809 const char *peer = NULL;
1810 for (int i = 0; i < n_settings; i++) {
1811 if (!strncmp(settings[i], "peer=", 5)) {
1812 peer = settings[i] + 5;
1817 if ((!peer != !lrp->peer) ||
1818 (lrp->peer && strcmp(peer, lrp->peer))) {
1819 ctl_fatal("%s: port already exists with mismatching peer",
1827 if (!ovs_scan(mac, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
1828 ctl_fatal("%s: invalid mac address %s", lrp_name, mac);
1831 for (int i = 0; i < n_networks; i++) {
1834 char *error = ip_parse_cidr(networks[i], &ipv4, &plen);
1837 struct in6_addr ipv6;
1838 error = ipv6_parse_cidr(networks[i], &ipv6, &plen);
1841 ctl_fatal("%s: invalid network address: %s", lrp_name,
1847 /* Create the logical port. */
1848 lrp = nbrec_logical_router_port_insert(ctx->txn);
1849 nbrec_logical_router_port_set_name(lrp, lrp_name);
1850 nbrec_logical_router_port_set_mac(lrp, mac);
1851 nbrec_logical_router_port_set_networks(lrp, networks, n_networks);
1853 for (int i = 0; i < n_settings; i++) {
1854 ctl_set_column("Logical_Router_Port", &lrp->header_, settings[i],
1858 /* Insert the logical port into the logical router. */
1859 nbrec_logical_router_verify_ports(lr);
1860 struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
1862 memcpy(new_ports, lr->ports, sizeof *new_ports * lr->n_ports);
1863 new_ports[lr->n_ports] = CONST_CAST(struct nbrec_logical_router_port *,
1865 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports + 1);
1869 /* Removes logical router port 'lr->ports[idx]'. */
1871 remove_lrp(const struct nbrec_logical_router *lr, size_t idx)
1873 const struct nbrec_logical_router_port *lrp = lr->ports[idx];
1875 /* First remove 'lrp' from the array of ports. This is what will
1876 * actually cause the logical port to be deleted when the transaction is
1877 * sent to the database server (due to garbage collection). */
1878 struct nbrec_logical_router_port **new_ports
1879 = xmemdup(lr->ports, sizeof *new_ports * lr->n_ports);
1880 new_ports[idx] = new_ports[lr->n_ports - 1];
1881 nbrec_logical_router_verify_ports(lr);
1882 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports - 1);
1885 /* Delete 'lrp' from the IDL. This won't have a real effect on
1886 * the database server (the IDL will suppress it in fact) but it
1887 * means that it won't show up when we iterate with
1888 * NBREC_LOGICAL_ROUTER_PORT_FOR_EACH later. */
1889 nbrec_logical_router_port_delete(lrp);
1893 nbctl_lrp_del(struct ctl_context *ctx)
1895 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1896 const struct nbrec_logical_router_port *lrp;
1898 lrp = lrp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
1903 /* Find the router that contains 'lrp', then delete it. */
1904 const struct nbrec_logical_router *lr;
1905 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1906 for (size_t i = 0; i < lr->n_ports; i++) {
1907 if (lr->ports[i] == lrp) {
1914 /* Can't happen because of the database schema. */
1915 ctl_fatal("logical port %s is not part of any logical router",
1919 /* Print a list of logical router ports. */
1921 nbctl_lrp_list(struct ctl_context *ctx)
1923 const char *id = ctx->argv[1];
1924 const struct nbrec_logical_router *lr;
1928 lr = lr_by_name_or_uuid(ctx, id, true);
1931 for (i = 0; i < lr->n_ports; i++) {
1932 const struct nbrec_logical_router_port *lrp = lr->ports[i];
1933 smap_add_format(&lrps, lrp->name, UUID_FMT " (%s)",
1934 UUID_ARGS(&lrp->header_.uuid), lrp->name);
1936 const struct smap_node **nodes = smap_sort(&lrps);
1937 for (i = 0; i < smap_count(&lrps); i++) {
1938 const struct smap_node *node = nodes[i];
1939 ds_put_format(&ctx->output, "%s\n", node->value);
1941 smap_destroy(&lrps);
1945 /* Set the logical router port admin-enabled state. */
1947 nbctl_lrp_set_enabled(struct ctl_context *ctx)
1949 const char *id = ctx->argv[1];
1950 const char *state = ctx->argv[2];
1951 const struct nbrec_logical_router_port *lrp;
1953 lrp = lrp_by_name_or_uuid(ctx, id, true);
1958 bool enabled = parse_enabled(state);
1959 nbrec_logical_router_port_set_enabled(lrp, &enabled, 1);
1962 /* Print admin-enabled state for logical router port. */
1964 nbctl_lrp_get_enabled(struct ctl_context *ctx)
1966 const char *id = ctx->argv[1];
1967 const struct nbrec_logical_router_port *lrp;
1969 lrp = lrp_by_name_or_uuid(ctx, id, true);
1974 ds_put_format(&ctx->output, "%s\n",
1976 *lrp->enabled ? "enabled" : "disabled");
1982 const struct nbrec_logical_router_static_route *route;
1986 ipv4_route_cmp(const void *route1_, const void *route2_)
1988 const struct ipv4_route *route1p = route1_;
1989 const struct ipv4_route *route2p = route2_;
1991 if (route1p->plen != route2p->plen) {
1992 return route1p->plen > route2p->plen ? -1 : 1;
1993 } else if (route1p->addr != route2p->addr) {
1994 return ntohl(route1p->addr) < ntohl(route2p->addr) ? -1 : 1;
2002 struct in6_addr addr;
2003 const struct nbrec_logical_router_static_route *route;
2007 ipv6_route_cmp(const void *route1_, const void *route2_)
2009 const struct ipv6_route *route1p = route1_;
2010 const struct ipv6_route *route2p = route2_;
2012 if (route1p->plen != route2p->plen) {
2013 return route1p->plen > route2p->plen ? -1 : 1;
2015 return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr));
2019 print_route(const struct nbrec_logical_router_static_route *route, struct ds *s)
2022 char *prefix = normalize_prefix_str(route->ip_prefix);
2023 char *next_hop = normalize_prefix_str(route->nexthop);
2024 ds_put_format(s, "%25s %25s", prefix, next_hop);
2028 if (route->output_port) {
2029 ds_put_format(s, " %s", route->output_port);
2031 ds_put_char(s, '\n');
2035 nbctl_lr_route_list(struct ctl_context *ctx)
2037 const struct nbrec_logical_router *lr;
2038 struct ipv4_route *ipv4_routes;
2039 struct ipv6_route *ipv6_routes;
2040 size_t n_ipv4_routes = 0;
2041 size_t n_ipv6_routes = 0;
2043 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2045 ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
2046 ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
2048 for (int i = 0; i < lr->n_static_routes; i++) {
2049 const struct nbrec_logical_router_static_route *route
2050 = lr->static_routes[i];
2055 error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen);
2057 ipv4_routes[n_ipv4_routes].plen = plen;
2058 ipv4_routes[n_ipv4_routes].addr = ipv4;
2059 ipv4_routes[n_ipv4_routes].route = route;
2064 struct in6_addr ipv6;
2065 error = ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen);
2067 ipv6_routes[n_ipv6_routes].plen = plen;
2068 ipv6_routes[n_ipv6_routes].addr = ipv6;
2069 ipv6_routes[n_ipv6_routes].route = route;
2072 /* Invalid prefix. */
2073 VLOG_WARN("router "UUID_FMT" (%s) has invalid prefix: %s",
2074 UUID_ARGS(&lr->header_.uuid), lr->name,
2082 qsort(ipv4_routes, n_ipv4_routes, sizeof *ipv4_routes, ipv4_route_cmp);
2083 qsort(ipv6_routes, n_ipv6_routes, sizeof *ipv6_routes, ipv6_route_cmp);
2085 if (n_ipv4_routes) {
2086 ds_put_cstr(&ctx->output, "IPv4 Routes\n");
2088 for (int i = 0; i < n_ipv4_routes; i++) {
2089 print_route(ipv4_routes[i].route, &ctx->output);
2092 if (n_ipv6_routes) {
2093 ds_put_format(&ctx->output, "%sIPv6 Routes\n",
2094 n_ipv4_routes ? "\n" : "");
2096 for (int i = 0; i < n_ipv6_routes; i++) {
2097 print_route(ipv6_routes[i].route, &ctx->output);
2104 static const struct ctl_table_class tables[] = {
2105 {&nbrec_table_nb_global,
2106 {{&nbrec_table_nb_global, NULL, NULL},
2107 {NULL, NULL, NULL}}},
2109 {&nbrec_table_logical_switch,
2110 {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
2111 {NULL, NULL, NULL}}},
2113 {&nbrec_table_logical_switch_port,
2114 {{&nbrec_table_logical_switch_port, &nbrec_logical_switch_port_col_name,
2116 {NULL, NULL, NULL}}},
2119 {{NULL, NULL, NULL},
2120 {NULL, NULL, NULL}}},
2122 {&nbrec_table_load_balancer,
2123 {{NULL, NULL, NULL},
2124 {NULL, NULL, NULL}}},
2126 {&nbrec_table_logical_router,
2127 {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
2128 {NULL, NULL, NULL}}},
2130 {&nbrec_table_logical_router_port,
2131 {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
2133 {NULL, NULL, NULL}}},
2135 {&nbrec_table_logical_router_static_route,
2136 {{&nbrec_table_logical_router_static_route, NULL,
2138 {NULL, NULL, NULL}}},
2141 {{&nbrec_table_nat, NULL,
2143 {NULL, NULL, NULL}}},
2145 {&nbrec_table_address_set,
2146 {{&nbrec_table_address_set, &nbrec_address_set_col_name, NULL},
2147 {NULL, NULL, NULL}}},
2149 {&nbrec_table_dhcp_options,
2150 {{&nbrec_table_dhcp_options, NULL,
2152 {NULL, NULL, NULL}}},
2154 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
2158 run_prerequisites(struct ctl_command *commands, size_t n_commands,
2159 struct ovsdb_idl *idl)
2161 ovsdb_idl_add_table(idl, &nbrec_table_nb_global);
2162 if (wait_type == NBCTL_WAIT_SB) {
2163 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg);
2164 } else if (wait_type == NBCTL_WAIT_HV) {
2165 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg);
2168 for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) {
2169 if (c->syntax->prerequisites) {
2170 struct ctl_context ctx;
2172 ds_init(&c->output);
2175 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
2176 (c->syntax->prerequisites)(&ctx);
2177 ctl_context_done(&ctx, c);
2179 ovs_assert(!c->output.string);
2180 ovs_assert(!c->table);
2186 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
2187 struct ovsdb_idl *idl)
2189 struct ovsdb_idl_txn *txn;
2190 enum ovsdb_idl_txn_status status;
2191 struct ovsdb_symbol_table *symtab;
2192 struct ctl_context ctx;
2193 struct ctl_command *c;
2194 struct shash_node *node;
2195 int64_t next_cfg = 0;
2198 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
2200 ovsdb_idl_txn_set_dry_run(txn);
2203 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
2205 const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl);
2207 /* XXX add verification that table is empty */
2208 nb = nbrec_nb_global_insert(txn);
2211 if (wait_type != NBCTL_WAIT_NONE) {
2212 ovsdb_idl_txn_increment(txn, &nb->header_,
2213 &nbrec_nb_global_col_nb_cfg);
2216 symtab = ovsdb_symbol_table_create();
2217 for (c = commands; c < &commands[n_commands]; c++) {
2218 ds_init(&c->output);
2221 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
2222 for (c = commands; c < &commands[n_commands]; c++) {
2223 ctl_context_init_command(&ctx, c);
2224 if (c->syntax->run) {
2225 (c->syntax->run)(&ctx);
2227 ctl_context_done_command(&ctx, c);
2229 if (ctx.try_again) {
2230 ctl_context_done(&ctx, NULL);
2234 ctl_context_done(&ctx, NULL);
2236 SHASH_FOR_EACH (node, &symtab->sh) {
2237 struct ovsdb_symbol *symbol = node->data;
2238 if (!symbol->created) {
2239 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
2240 "with \"-- --id=%s create ...\")",
2241 node->name, node->name);
2243 if (!symbol->strong_ref) {
2244 if (!symbol->weak_ref) {
2245 VLOG_WARN("row id \"%s\" was created but no reference to it "
2246 "was inserted, so it will not actually appear in "
2247 "the database", node->name);
2249 VLOG_WARN("row id \"%s\" was created but only a weak "
2250 "reference to it was inserted, so it will not "
2251 "actually appear in the database", node->name);
2256 status = ovsdb_idl_txn_commit_block(txn);
2257 if (wait_type != NBCTL_WAIT_NONE && status == TXN_SUCCESS) {
2258 next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
2260 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
2261 for (c = commands; c < &commands[n_commands]; c++) {
2262 if (c->syntax->postprocess) {
2263 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
2264 (c->syntax->postprocess)(&ctx);
2265 ctl_context_done(&ctx, c);
2269 error = xstrdup(ovsdb_idl_txn_get_error(txn));
2272 case TXN_UNCOMMITTED:
2273 case TXN_INCOMPLETE:
2277 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
2278 ctl_fatal("transaction aborted");
2288 ctl_fatal("transaction error: %s", error);
2290 case TXN_NOT_LOCKED:
2291 /* Should not happen--we never call ovsdb_idl_set_lock(). */
2292 ctl_fatal("database not locked");
2299 ovsdb_symbol_table_destroy(symtab);
2301 for (c = commands; c < &commands[n_commands]; c++) {
2302 struct ds *ds = &c->output;
2305 table_print(c->table, &table_style);
2306 } else if (oneline) {
2310 for (j = 0; j < ds->length; j++) {
2311 int ch = ds->string[j];
2314 fputs("\\n", stdout);
2318 fputs("\\\\", stdout);
2327 fputs(ds_cstr(ds), stdout);
2329 ds_destroy(&c->output);
2330 table_destroy(c->table);
2333 shash_destroy_free_data(&c->options);
2337 if (wait_type != NBCTL_WAIT_NONE && status != TXN_UNCHANGED) {
2338 ovsdb_idl_enable_reconnect(idl);
2341 NBREC_NB_GLOBAL_FOR_EACH (nb, idl) {
2342 int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB
2345 if (cur_cfg >= next_cfg) {
2349 ovsdb_idl_wait(idl);
2355 ovsdb_idl_txn_destroy(txn);
2356 ovsdb_idl_destroy(idl);
2361 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
2362 * resources and return so that the caller can try again. */
2364 ovsdb_idl_txn_abort(txn);
2365 ovsdb_idl_txn_destroy(txn);
2368 ovsdb_symbol_table_destroy(symtab);
2369 for (c = commands; c < &commands[n_commands]; c++) {
2370 ds_destroy(&c->output);
2371 table_destroy(c->table);
2378 /* Frees the current transaction and the underlying IDL and then calls
2381 * Freeing the transaction and the IDL is not strictly necessary, but it makes
2382 * for a clean memory leak report from valgrind in the normal case. That makes
2383 * it easier to notice real memory leaks. */
2385 nbctl_exit(int status)
2388 ovsdb_idl_txn_abort(the_idl_txn);
2389 ovsdb_idl_txn_destroy(the_idl_txn);
2391 ovsdb_idl_destroy(the_idl);
2395 static const struct ctl_command_syntax nbctl_commands[] = {
2396 { "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW },
2397 { "show", 0, 1, "[SWITCH]", NULL, nbctl_show, NULL, "", RO },
2399 /* logical switch commands. */
2400 { "ls-add", 0, 1, "[SWITCH]", NULL, nbctl_ls_add, NULL,
2401 "--may-exist,--add-duplicate", RW },
2402 { "ls-del", 1, 1, "SWITCH", NULL, nbctl_ls_del, NULL, "--if-exists", RW },
2403 { "ls-list", 0, 0, "", NULL, nbctl_ls_list, NULL, "", RO },
2406 { "acl-add", 5, 5, "SWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
2407 nbctl_acl_add, NULL, "--log", RW },
2408 { "acl-del", 1, 4, "SWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
2409 nbctl_acl_del, NULL, "", RW },
2410 { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_list, NULL, "", RO },
2412 /* logical switch port commands. */
2413 { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add,
2414 NULL, "--may-exist", RW },
2415 { "lsp-del", 1, 1, "PORT", NULL, nbctl_lsp_del, NULL, "--if-exists", RW },
2416 { "lsp-list", 1, 1, "SWITCH", NULL, nbctl_lsp_list, NULL, "", RO },
2417 { "lsp-get-parent", 1, 1, "PORT", NULL, nbctl_lsp_get_parent, NULL,
2419 { "lsp-get-tag", 1, 1, "PORT", NULL, nbctl_lsp_get_tag, NULL, "", RO },
2420 { "lsp-set-addresses", 1, INT_MAX, "PORT [ADDRESS]...", NULL,
2421 nbctl_lsp_set_addresses, NULL, "", RW },
2422 { "lsp-get-addresses", 1, 1, "PORT", NULL, nbctl_lsp_get_addresses, NULL,
2424 { "lsp-set-port-security", 0, INT_MAX, "PORT [ADDRS]...", NULL,
2425 nbctl_lsp_set_port_security, NULL, "", RW },
2426 { "lsp-get-port-security", 1, 1, "PORT", NULL,
2427 nbctl_lsp_get_port_security, NULL, "", RO },
2428 { "lsp-get-up", 1, 1, "PORT", NULL, nbctl_lsp_get_up, NULL, "", RO },
2429 { "lsp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lsp_set_enabled,
2431 { "lsp-get-enabled", 1, 1, "PORT", NULL, nbctl_lsp_get_enabled, NULL,
2433 { "lsp-set-type", 2, 2, "PORT TYPE", NULL, nbctl_lsp_set_type, NULL,
2435 { "lsp-get-type", 1, 1, "PORT", NULL, nbctl_lsp_get_type, NULL, "", RO },
2436 { "lsp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...", NULL,
2437 nbctl_lsp_set_options, NULL, "", RW },
2438 { "lsp-get-options", 1, 1, "PORT", NULL, nbctl_lsp_get_options, NULL,
2440 { "lsp-set-dhcpv4-options", 1, 2, "PORT [DHCP_OPT_UUID]", NULL,
2441 nbctl_lsp_set_dhcpv4_options, NULL, "", RW },
2442 { "lsp-get-dhcpv4-options", 1, 1, "PORT", NULL,
2443 nbctl_lsp_get_dhcpv4_options, NULL, "", RO },
2445 /* logical router commands. */
2446 { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL,
2447 "--may-exist,--add-duplicate", RW },
2448 { "lr-del", 1, 1, "ROUTER", NULL, nbctl_lr_del, NULL, "--if-exists", RW },
2449 { "lr-list", 0, 0, "", NULL, nbctl_lr_list, NULL, "", RO },
2451 /* logical router port commands. */
2452 { "lrp-add", 4, INT_MAX,
2453 "ROUTER PORT MAC NETWORK... [COLUMN[:KEY]=VALUE]...",
2454 NULL, nbctl_lrp_add, NULL, "--may-exist", RW },
2455 { "lrp-del", 1, 1, "PORT", NULL, nbctl_lrp_del, NULL, "--if-exists", RW },
2456 { "lrp-list", 1, 1, "ROUTER", NULL, nbctl_lrp_list, NULL, "", RO },
2457 { "lrp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lrp_set_enabled,
2459 { "lrp-get-enabled", 1, 1, "PORT", NULL, nbctl_lrp_get_enabled,
2462 /* logical router route commands. */
2463 { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL,
2464 nbctl_lr_route_add, NULL, "--may-exist", RW },
2465 { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del,
2466 NULL, "--if-exists", RW },
2467 { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL,
2470 /* DHCP_Options commands */
2471 {"dhcp-options-create", 1, INT_MAX, "CIDR [EXTERNAL:IDS]", NULL,
2472 nbctl_dhcp_options_create, NULL, "", RW },
2473 {"dhcp-options-del", 1, 1, "DHCP_OPT_UUID", NULL,
2474 nbctl_dhcp_options_del, NULL, "", RW},
2475 {"dhcp-options-list", 0, 0, "", NULL, nbctl_dhcp_options_list, NULL, "", RO},
2476 {"dhcp-options-set-options", 1, INT_MAX, "DHCP_OPT_UUID KEY=VALUE [KEY=VALUE]...",
2477 NULL, nbctl_dhcp_options_set_options, NULL, "", RW },
2478 {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL,
2479 nbctl_dhcp_options_get_options, NULL, "", RO },
2481 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
2484 /* Registers nbctl and common db commands. */
2486 nbctl_cmd_init(void)
2488 ctl_init(tables, NULL, nbctl_exit);
2489 ctl_register_commands(nbctl_commands);