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 void do_nbctl(const char *args, struct ctl_command *, size_t n,
74 main(int argc, char *argv[])
76 extern struct vlog_module VLM_reconnect;
77 struct ovsdb_idl *idl;
78 struct ctl_command *commands;
79 struct shash local_options;
84 set_program_name(argv[0]);
85 fatal_ignore_sigpipe();
86 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
87 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
92 /* Log our arguments. This is often valuable for debugging systems. */
93 args = process_escape_args(argv);
94 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
95 "Called as %s", args);
97 /* Parse command line. */
98 shash_init(&local_options);
99 parse_options(argc, argv, &local_options);
100 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
107 /* Initialize IDL. */
108 idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
109 run_prerequisites(commands, n_commands, idl);
111 /* Execute the commands.
113 * 'seqno' is the database sequence number for which we last tried to
114 * execute our transaction. There's no point in trying to commit more than
115 * once for any given sequence number, because if the transaction fails
116 * it's because the database changed and we need to obtain an up-to-date
117 * view of the database before we try the transaction again. */
118 seqno = ovsdb_idl_get_seqno(idl);
121 if (!ovsdb_idl_is_alive(idl)) {
122 int retval = ovsdb_idl_get_last_error(idl);
123 ctl_fatal("%s: database connection failed (%s)",
124 db, ovs_retval_to_string(retval));
127 if (seqno != ovsdb_idl_get_seqno(idl)) {
128 seqno = ovsdb_idl_get_seqno(idl);
129 do_nbctl(args, commands, n_commands, idl);
132 if (seqno == ovsdb_idl_get_seqno(idl)) {
140 nbctl_default_db(void)
144 def = getenv("OVN_NB_DB");
146 def = ctl_default_db();
153 parse_options(int argc, char *argv[], struct shash *local_options)
156 OPT_DB = UCHAR_MAX + 1,
166 static const struct option global_long_options[] = {
167 {"db", required_argument, NULL, OPT_DB},
168 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
169 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
170 {"oneline", no_argument, NULL, OPT_ONELINE},
171 {"timeout", required_argument, NULL, 't'},
172 {"help", no_argument, NULL, 'h'},
173 {"commands", no_argument, NULL, OPT_COMMANDS},
174 {"options", no_argument, NULL, OPT_OPTIONS},
175 {"version", no_argument, NULL, 'V'},
177 STREAM_SSL_LONG_OPTIONS,
181 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
182 char *tmp, *short_options;
184 struct option *options;
185 size_t allocated_options;
189 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
190 short_options = xasprintf("+%s", tmp);
193 /* We want to parse both global and command-specific options here, but
194 * getopt_long() isn't too convenient for the job. We copy our global
195 * options into a dynamic array, then append all of the command-specific
197 options = xmemdup(global_long_options, sizeof global_long_options);
198 allocated_options = ARRAY_SIZE(global_long_options);
199 n_options = n_global_long_options;
200 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
201 table_style.format = TF_LIST;
207 c = getopt_long(argc, argv, short_options, options, &idx);
222 vlog_set_levels(&VLM_nbctl, VLF_SYSLOG, VLL_WARN);
230 if (shash_find(local_options, options[idx].name)) {
231 ctl_fatal("'%s' option specified multiple times",
234 shash_add_nocopy(local_options,
235 xasprintf("--%s", options[idx].name),
236 optarg ? xstrdup(optarg) : NULL);
244 ctl_print_commands();
247 ctl_print_options(global_long_options);
250 ovs_print_version(0, 0);
251 printf("DB Schema %s\n", nbrec_get_db_version());
255 timeout = strtoul(optarg, NULL, 10);
257 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
262 TABLE_OPTION_HANDLERS(&table_style)
263 STREAM_SSL_OPTION_HANDLERS
275 db = nbctl_default_db();
278 for (i = n_global_long_options; options[i].name; i++) {
279 free(CONST_CAST(char *, options[i].name));
288 %s: OVN northbound DB management utility\n\
289 usage: %s [OPTIONS] COMMAND [ARG...]\n\
292 show print overview of database contents\n\
293 show LSWITCH print overview of database contents for LSWITCH\n\
295 Logical switch commands:\n\
296 lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\
297 lswitch-del LSWITCH delete LSWITCH and all its ports\n\
298 lswitch-list print the names of all logical switches\n\
301 acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
302 add an ACL to LSWITCH\n\
303 acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\
304 remove ACLs from LSWITCH\n\
305 acl-list LSWITCH print ACLs for LSWITCH\n\
307 Logical port commands:\n\
308 lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
309 lport-add LSWITCH LPORT PARENT TAG\n\
310 add logical port LPORT on LSWITCH with PARENT\n\
312 lport-del LPORT delete LPORT from its attached switch\n\
313 lport-list LSWITCH print the names of all logical ports on LSWITCH\n\
314 lport-get-parent LPORT get the parent of LPORT if set\n\
315 lport-get-tag LPORT get the LPORT's tag if set\n\
316 lport-set-addresses LPORT [ADDRESS]...\n\
317 set MAC or MAC+IP addresses for LPORT.\n\
318 lport-get-addresses LPORT get a list of MAC addresses on LPORT\n\
319 lport-set-port-security LPORT [ADDRS]...\n\
320 set port security addresses for LPORT.\n\
321 lport-get-port-security LPORT get LPORT's port security addresses\n\
322 lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
323 lport-set-enabled LPORT STATE\n\
324 set administrative state LPORT\n\
325 ('enabled' or 'disabled')\n\
326 lport-get-enabled LPORT get administrative state LPORT\n\
327 ('enabled' or 'disabled')\n\
328 lport-set-type LPORT TYPE Set the type for LPORT\n\
329 lport-get-type LPORT Get the type for LPORT\n\
330 lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
331 Set options related to the type of LPORT\n\
332 lport-get-options LPORT Get the type specific options for LPORT\n\
337 --db=DATABASE connect to DATABASE\n\
339 -t, --timeout=SECS wait at most SECS seconds\n\
340 --dry-run do not commit changes to database\n\
341 --oneline print exactly one line of output per command\n",
342 program_name, program_name, ctl_get_db_cmd_usage(), nbctl_default_db());
345 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
348 -h, --help display this help message\n\
349 -V, --version display version information\n");
353 static const struct nbrec_logical_switch *
354 lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id)
356 const struct nbrec_logical_switch *lswitch = NULL;
357 bool is_uuid = false;
358 bool duplicate = false;
359 struct uuid lswitch_uuid;
361 if (uuid_from_string(&lswitch_uuid, id)) {
363 lswitch = nbrec_logical_switch_get_for_uuid(ctx->idl,
368 const struct nbrec_logical_switch *iter;
370 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
371 if (strcmp(iter->name, id)) {
375 VLOG_WARN("There is more than one logical switch named '%s'. "
385 if (!lswitch && !duplicate) {
386 VLOG_WARN("lswitch not found for %s: '%s'",
387 is_uuid ? "UUID" : "name", id);
394 print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s)
396 ds_put_format(s, " lswitch "UUID_FMT" (%s)\n",
397 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
399 for (size_t i = 0; i < lswitch->n_ports; i++) {
400 const struct nbrec_logical_port *lport = lswitch->ports[i];
402 ds_put_format(s, " lport %s\n", lport->name);
403 if (lport->parent_name) {
404 ds_put_format(s, " parent: %s\n", lport->parent_name);
407 ds_put_format(s, " tag: %"PRIu64"\n", lport->tag[0]);
409 if (lport->n_addresses) {
410 ds_put_cstr(s, " addresses:");
411 for (size_t j = 0; j < lport->n_addresses; j++) {
412 ds_put_format(s, " %s", lport->addresses[j]);
414 ds_put_char(s, '\n');
420 nbctl_show(struct ctl_context *ctx)
422 const struct nbrec_logical_switch *lswitch;
424 if (ctx->argc == 2) {
425 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
427 print_lswitch(lswitch, &ctx->output);
430 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
431 print_lswitch(lswitch, &ctx->output);
437 nbctl_lswitch_add(struct ctl_context *ctx)
439 struct nbrec_logical_switch *lswitch;
441 lswitch = nbrec_logical_switch_insert(ctx->txn);
442 if (ctx->argc == 2) {
443 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
448 nbctl_lswitch_del(struct ctl_context *ctx)
450 const char *id = ctx->argv[1];
451 const struct nbrec_logical_switch *lswitch;
453 lswitch = lswitch_by_name_or_uuid(ctx, id);
458 nbrec_logical_switch_delete(lswitch);
462 nbctl_lswitch_list(struct ctl_context *ctx)
464 const struct nbrec_logical_switch *lswitch;
465 struct smap lswitches;
467 smap_init(&lswitches);
468 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
469 smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
470 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
472 const struct smap_node **nodes = smap_sort(&lswitches);
473 for (size_t i = 0; i < smap_count(&lswitches); i++) {
474 const struct smap_node *node = nodes[i];
475 ds_put_format(&ctx->output, "%s\n", node->value);
477 smap_destroy(&lswitches);
481 static const struct nbrec_logical_port *
482 lport_by_name_or_uuid(struct ctl_context *ctx, const char *id)
484 const struct nbrec_logical_port *lport = NULL;
485 bool is_uuid = false;
486 struct uuid lport_uuid;
488 if (uuid_from_string(&lport_uuid, id)) {
490 lport = nbrec_logical_port_get_for_uuid(ctx->idl, &lport_uuid);
494 NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->idl) {
495 if (!strcmp(lport->name, id)) {
502 VLOG_WARN("lport not found for %s: '%s'",
503 is_uuid ? "UUID" : "name", id);
510 nbctl_lport_add(struct ctl_context *ctx)
512 struct nbrec_logical_port *lport;
513 const struct nbrec_logical_switch *lswitch;
516 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
521 if (ctx->argc != 3 && ctx->argc != 5) {
522 /* If a parent_name is specified, a tag must be specified as well. */
523 VLOG_WARN("Invalid arguments to lport-add.");
527 if (ctx->argc == 5) {
529 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
530 VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
535 /* Create the logical port. */
536 lport = nbrec_logical_port_insert(ctx->txn);
537 nbrec_logical_port_set_name(lport, ctx->argv[2]);
538 if (ctx->argc == 5) {
539 nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
540 nbrec_logical_port_set_tag(lport, &tag, 1);
543 /* Insert the logical port into the logical switch. */
544 nbrec_logical_switch_verify_ports(lswitch);
545 struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
546 (lswitch->n_ports + 1));
547 memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
548 new_ports[lswitch->n_ports] = lport;
549 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
553 /* Removes lport 'lswitch->ports[idx]'. */
555 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
557 const struct nbrec_logical_port *lport = lswitch->ports[idx];
559 /* First remove 'lport' from the array of ports. This is what will
560 * actually cause the logical port to be deleted when the transaction is
561 * sent to the database server (due to garbage collection). */
562 struct nbrec_logical_port **new_ports
563 = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
564 new_ports[idx] = new_ports[lswitch->n_ports - 1];
565 nbrec_logical_switch_verify_ports(lswitch);
566 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
569 /* Delete 'lport' from the IDL. This won't have a real effect on the
570 * database server (the IDL will suppress it in fact) but it means that it
571 * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
572 nbrec_logical_port_delete(lport);
576 nbctl_lport_del(struct ctl_context *ctx)
578 const struct nbrec_logical_port *lport;
580 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
585 /* Find the switch that contains 'lport', then delete it. */
586 const struct nbrec_logical_switch *lswitch;
587 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
588 for (size_t i = 0; i < lswitch->n_ports; i++) {
589 if (lswitch->ports[i] == lport) {
590 remove_lport(lswitch, i);
596 VLOG_WARN("logical port %s is not part of any logical switch",
601 nbctl_lport_list(struct ctl_context *ctx)
603 const char *id = ctx->argv[1];
604 const struct nbrec_logical_switch *lswitch;
608 lswitch = lswitch_by_name_or_uuid(ctx, id);
614 for (i = 0; i < lswitch->n_ports; i++) {
615 const struct nbrec_logical_port *lport = lswitch->ports[i];
616 smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
617 UUID_ARGS(&lport->header_.uuid), lport->name);
619 const struct smap_node **nodes = smap_sort(&lports);
620 for (i = 0; i < smap_count(&lports); i++) {
621 const struct smap_node *node = nodes[i];
622 ds_put_format(&ctx->output, "%s\n", node->value);
624 smap_destroy(&lports);
629 nbctl_lport_get_parent(struct ctl_context *ctx)
631 const struct nbrec_logical_port *lport;
633 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
638 if (lport->parent_name) {
639 ds_put_format(&ctx->output, "%s\n", lport->parent_name);
644 nbctl_lport_get_tag(struct ctl_context *ctx)
646 const struct nbrec_logical_port *lport;
648 lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
653 if (lport->n_tag > 0) {
654 ds_put_format(&ctx->output, "%"PRId64"\n", lport->tag[0]);
659 nbctl_lport_set_addresses(struct ctl_context *ctx)
661 const char *id = ctx->argv[1];
662 const struct nbrec_logical_port *lport;
664 lport = lport_by_name_or_uuid(ctx, id);
670 for (i = 2; i < ctx->argc; i++) {
673 if (strcmp(ctx->argv[i], "unknown")
674 && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
675 ETH_ADDR_SCAN_ARGS(ea))) {
676 VLOG_ERR("Invalid address format (%s). See ovn-nb(5). "
677 "Hint: An Ethernet address must be "
678 "listed before an IP address, together as a single "
679 "argument.", ctx->argv[i]);
684 nbrec_logical_port_set_addresses(lport,
685 (const char **) ctx->argv + 2, ctx->argc - 2);
689 nbctl_lport_get_addresses(struct ctl_context *ctx)
691 const char *id = ctx->argv[1];
692 const struct nbrec_logical_port *lport;
693 struct svec addresses;
697 lport = lport_by_name_or_uuid(ctx, id);
702 svec_init(&addresses);
703 for (i = 0; i < lport->n_addresses; i++) {
704 svec_add(&addresses, lport->addresses[i]);
706 svec_sort(&addresses);
707 SVEC_FOR_EACH(i, mac, &addresses) {
708 ds_put_format(&ctx->output, "%s\n", mac);
710 svec_destroy(&addresses);
714 nbctl_lport_set_port_security(struct ctl_context *ctx)
716 const char *id = ctx->argv[1];
717 const struct nbrec_logical_port *lport;
719 lport = lport_by_name_or_uuid(ctx, id);
724 nbrec_logical_port_set_port_security(lport,
725 (const char **) ctx->argv + 2, ctx->argc - 2);
729 nbctl_lport_get_port_security(struct ctl_context *ctx)
731 const char *id = ctx->argv[1];
732 const struct nbrec_logical_port *lport;
737 lport = lport_by_name_or_uuid(ctx, id);
743 for (i = 0; i < lport->n_port_security; i++) {
744 svec_add(&addrs, lport->port_security[i]);
747 SVEC_FOR_EACH(i, addr, &addrs) {
748 ds_put_format(&ctx->output, "%s\n", addr);
750 svec_destroy(&addrs);
754 nbctl_lport_get_up(struct ctl_context *ctx)
756 const char *id = ctx->argv[1];
757 const struct nbrec_logical_port *lport;
759 lport = lport_by_name_or_uuid(ctx, id);
764 ds_put_format(&ctx->output,
765 "%s\n", (lport->up && *lport->up) ? "up" : "down");
769 nbctl_lport_set_enabled(struct ctl_context *ctx)
771 const char *id = ctx->argv[1];
772 const char *state = ctx->argv[2];
773 const struct nbrec_logical_port *lport;
775 lport = lport_by_name_or_uuid(ctx, id);
780 if (!strcasecmp(state, "enabled")) {
782 nbrec_logical_port_set_enabled(lport, &enabled, 1);
783 } else if (!strcasecmp(state, "disabled")) {
784 bool enabled = false;
785 nbrec_logical_port_set_enabled(lport, &enabled, 1);
787 VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
792 nbctl_lport_get_enabled(struct ctl_context *ctx)
794 const char *id = ctx->argv[1];
795 const struct nbrec_logical_port *lport;
797 lport = lport_by_name_or_uuid(ctx, id);
802 ds_put_format(&ctx->output, "%s\n",
803 !lport->enabled || *lport->enabled ? "enabled" : "disabled");
807 nbctl_lport_set_type(struct ctl_context *ctx)
809 const char *id = ctx->argv[1];
810 const char *type = ctx->argv[2];
811 const struct nbrec_logical_port *lport;
813 lport = lport_by_name_or_uuid(ctx, id);
818 nbrec_logical_port_set_type(lport, type);
822 nbctl_lport_get_type(struct ctl_context *ctx)
824 const char *id = ctx->argv[1];
825 const struct nbrec_logical_port *lport;
827 lport = lport_by_name_or_uuid(ctx, id);
832 ds_put_format(&ctx->output, "%s\n", lport->type);
836 nbctl_lport_set_options(struct ctl_context *ctx)
838 const char *id = ctx->argv[1];
839 const struct nbrec_logical_port *lport;
841 struct smap options = SMAP_INITIALIZER(&options);
843 lport = lport_by_name_or_uuid(ctx, id);
848 for (i = 2; i < ctx->argc; i++) {
850 value = xstrdup(ctx->argv[i]);
851 key = strsep(&value, "=");
853 smap_add(&options, key, value);
858 nbrec_logical_port_set_options(lport, &options);
860 smap_destroy(&options);
864 nbctl_lport_get_options(struct ctl_context *ctx)
866 const char *id = ctx->argv[1];
867 const struct nbrec_logical_port *lport;
868 struct smap_node *node;
870 lport = lport_by_name_or_uuid(ctx, id);
875 SMAP_FOR_EACH(node, &lport->options) {
876 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
886 dir_encode(const char *dir)
888 if (!strcmp(dir, "from-lport")) {
889 return DIR_FROM_LPORT;
890 } else if (!strcmp(dir, "to-lport")) {
898 acl_cmp(const void *acl1_, const void *acl2_)
900 const struct nbrec_acl *const *acl1p = acl1_;
901 const struct nbrec_acl *const *acl2p = acl2_;
902 const struct nbrec_acl *acl1 = *acl1p;
903 const struct nbrec_acl *acl2 = *acl2p;
905 int dir1 = dir_encode(acl1->direction);
906 int dir2 = dir_encode(acl2->direction);
909 return dir1 < dir2 ? -1 : 1;
910 } else if (acl1->priority != acl2->priority) {
911 return acl1->priority > acl2->priority ? -1 : 1;
913 return strcmp(acl1->match, acl2->match);
918 nbctl_acl_list(struct ctl_context *ctx)
920 const struct nbrec_logical_switch *lswitch;
921 const struct nbrec_acl **acls;
924 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
929 acls = xmalloc(sizeof *acls * lswitch->n_acls);
930 for (i = 0; i < lswitch->n_acls; i++) {
931 acls[i] = lswitch->acls[i];
934 qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
936 for (i = 0; i < lswitch->n_acls; i++) {
937 const struct nbrec_acl *acl = acls[i];
938 printf("%10s %5"PRId64" (%s) %s%s\n", acl->direction, acl->priority,
939 acl->match, acl->action, acl->log ? " log" : "");
946 nbctl_acl_add(struct ctl_context *ctx)
948 const struct nbrec_logical_switch *lswitch;
949 const char *action = ctx->argv[5];
950 const char *direction;
953 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
958 /* Validate direction. Only require the first letter. */
959 if (ctx->argv[2][0] == 't') {
960 direction = "to-lport";
961 } else if (ctx->argv[2][0] == 'f') {
962 direction = "from-lport";
964 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
968 /* Validate priority. */
969 if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 0
970 || priority > 32767) {
971 VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
975 /* Validate action. */
976 if (strcmp(action, "allow") && strcmp(action, "allow-related")
977 && strcmp(action, "drop") && strcmp(action, "reject")) {
978 VLOG_WARN("Invalid action '%s'", action);
982 /* Create the acl. */
983 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
984 nbrec_acl_set_priority(acl, priority);
985 nbrec_acl_set_direction(acl, direction);
986 nbrec_acl_set_match(acl, ctx->argv[4]);
987 nbrec_acl_set_action(acl, action);
988 if (shash_find(&ctx->options, "--log") != NULL) {
989 nbrec_acl_set_log(acl, true);
992 /* Insert the acl into the logical switch. */
993 nbrec_logical_switch_verify_acls(lswitch);
994 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls *
995 (lswitch->n_acls + 1));
996 memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls);
997 new_acls[lswitch->n_acls] = acl;
998 nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1);
1003 nbctl_acl_del(struct ctl_context *ctx)
1005 const struct nbrec_logical_switch *lswitch;
1006 const char *direction;
1007 int64_t priority = 0;
1009 lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
1014 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1015 VLOG_WARN("Invalid number of arguments");
1019 if (ctx->argc == 2) {
1020 /* If direction, priority, and match are not specified, delete
1022 nbrec_logical_switch_verify_acls(lswitch);
1023 nbrec_logical_switch_set_acls(lswitch, NULL, 0);
1027 /* Validate direction. Only require first letter. */
1028 if (ctx->argv[2][0] == 't') {
1029 direction = "to-lport";
1030 } else if (ctx->argv[2][0] == 'f') {
1031 direction = "from-lport";
1033 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
1037 /* If priority and match are not specified, delete all ACLs with the
1038 * specified direction. */
1039 if (ctx->argc == 3) {
1040 struct nbrec_acl **new_acls
1041 = xmalloc(sizeof *new_acls * lswitch->n_acls);
1044 for (size_t i = 0; i < lswitch->n_acls; i++) {
1045 if (strcmp(direction, lswitch->acls[i]->direction)) {
1046 new_acls[n_acls++] = lswitch->acls[i];
1050 nbrec_logical_switch_verify_acls(lswitch);
1051 nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
1056 /* Validate priority. */
1057 if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 0
1058 || priority > 32767) {
1059 VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
1063 /* Remove the matching rule. */
1064 for (size_t i = 0; i < lswitch->n_acls; i++) {
1065 struct nbrec_acl *acl = lswitch->acls[i];
1067 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1068 !strcmp(direction, acl->direction)) {
1069 struct nbrec_acl **new_acls
1070 = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1071 new_acls[i] = lswitch->acls[lswitch->n_acls - 1];
1072 nbrec_logical_switch_verify_acls(lswitch);
1073 nbrec_logical_switch_set_acls(lswitch, new_acls,
1074 lswitch->n_acls - 1);
1081 static const struct ctl_table_class tables[] = {
1082 {&nbrec_table_logical_switch,
1083 {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
1084 {NULL, NULL, NULL}}},
1086 {&nbrec_table_logical_port,
1087 {{&nbrec_table_logical_port, &nbrec_logical_port_col_name, NULL},
1088 {NULL, NULL, NULL}}},
1091 {{NULL, NULL, NULL},
1092 {NULL, NULL, NULL}}},
1094 {&nbrec_table_logical_router,
1095 {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
1096 {NULL, NULL, NULL}}},
1098 {&nbrec_table_logical_router_port,
1099 {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
1101 {NULL, NULL, NULL}}},
1103 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
1107 run_prerequisites(struct ctl_command *commands, size_t n_commands,
1108 struct ovsdb_idl *idl)
1110 struct ctl_command *c;
1112 for (c = commands; c < &commands[n_commands]; c++) {
1113 if (c->syntax->prerequisites) {
1114 struct ctl_context ctx;
1116 ds_init(&c->output);
1119 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
1120 (c->syntax->prerequisites)(&ctx);
1121 ctl_context_done(&ctx, c);
1123 ovs_assert(!c->output.string);
1124 ovs_assert(!c->table);
1130 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
1131 struct ovsdb_idl *idl)
1133 struct ovsdb_idl_txn *txn;
1134 enum ovsdb_idl_txn_status status;
1135 struct ovsdb_symbol_table *symtab;
1136 struct ctl_context ctx;
1137 struct ctl_command *c;
1138 struct shash_node *node;
1141 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
1143 ovsdb_idl_txn_set_dry_run(txn);
1146 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
1148 symtab = ovsdb_symbol_table_create();
1149 for (c = commands; c < &commands[n_commands]; c++) {
1150 ds_init(&c->output);
1153 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
1154 for (c = commands; c < &commands[n_commands]; c++) {
1155 ctl_context_init_command(&ctx, c);
1156 if (c->syntax->run) {
1157 (c->syntax->run)(&ctx);
1159 ctl_context_done_command(&ctx, c);
1161 if (ctx.try_again) {
1162 ctl_context_done(&ctx, NULL);
1166 ctl_context_done(&ctx, NULL);
1168 SHASH_FOR_EACH (node, &symtab->sh) {
1169 struct ovsdb_symbol *symbol = node->data;
1170 if (!symbol->created) {
1171 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
1172 "with \"-- --id=%s create ...\")",
1173 node->name, node->name);
1175 if (!symbol->strong_ref) {
1176 if (!symbol->weak_ref) {
1177 VLOG_WARN("row id \"%s\" was created but no reference to it "
1178 "was inserted, so it will not actually appear in "
1179 "the database", node->name);
1181 VLOG_WARN("row id \"%s\" was created but only a weak "
1182 "reference to it was inserted, so it will not "
1183 "actually appear in the database", node->name);
1188 status = ovsdb_idl_txn_commit_block(txn);
1189 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
1190 for (c = commands; c < &commands[n_commands]; c++) {
1191 if (c->syntax->postprocess) {
1192 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
1193 (c->syntax->postprocess)(&ctx);
1194 ctl_context_done(&ctx, c);
1198 error = xstrdup(ovsdb_idl_txn_get_error(txn));
1201 case TXN_UNCOMMITTED:
1202 case TXN_INCOMPLETE:
1206 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1207 ctl_fatal("transaction aborted");
1217 ctl_fatal("transaction error: %s", error);
1219 case TXN_NOT_LOCKED:
1220 /* Should not happen--we never call ovsdb_idl_set_lock(). */
1221 ctl_fatal("database not locked");
1228 ovsdb_symbol_table_destroy(symtab);
1230 for (c = commands; c < &commands[n_commands]; c++) {
1231 struct ds *ds = &c->output;
1234 table_print(c->table, &table_style);
1235 } else if (oneline) {
1239 for (j = 0; j < ds->length; j++) {
1240 int ch = ds->string[j];
1243 fputs("\\n", stdout);
1247 fputs("\\\\", stdout);
1256 fputs(ds_cstr(ds), stdout);
1258 ds_destroy(&c->output);
1259 table_destroy(c->table);
1262 shash_destroy_free_data(&c->options);
1265 ovsdb_idl_txn_destroy(txn);
1266 ovsdb_idl_destroy(idl);
1271 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
1272 * resources and return so that the caller can try again. */
1274 ovsdb_idl_txn_abort(txn);
1275 ovsdb_idl_txn_destroy(txn);
1278 ovsdb_symbol_table_destroy(symtab);
1279 for (c = commands; c < &commands[n_commands]; c++) {
1280 ds_destroy(&c->output);
1281 table_destroy(c->table);
1287 /* Frees the current transaction and the underlying IDL and then calls
1290 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1291 * for a clean memory leak report from valgrind in the normal case. That makes
1292 * it easier to notice real memory leaks. */
1294 nbctl_exit(int status)
1297 ovsdb_idl_txn_abort(the_idl_txn);
1298 ovsdb_idl_txn_destroy(the_idl_txn);
1300 ovsdb_idl_destroy(the_idl);
1304 static const struct ctl_command_syntax nbctl_commands[] = {
1305 { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO },
1307 /* lswitch commands. */
1308 { "lswitch-add", 0, 1, "[LSWITCH]", NULL, nbctl_lswitch_add,
1310 { "lswitch-del", 1, 1, "LSWITCH", NULL, nbctl_lswitch_del,
1312 { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO },
1315 { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
1316 nbctl_acl_add, NULL, "--log", RW },
1317 { "acl-del", 1, 4, "LSWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
1318 nbctl_acl_del, NULL, "", RW },
1319 { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO },
1321 /* lport commands. */
1322 { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, nbctl_lport_add,
1324 { "lport-del", 1, 1, "LPORT", NULL, nbctl_lport_del, NULL, "", RO },
1325 { "lport-list", 1, 1, "LSWITCH", NULL, nbctl_lport_list, NULL, "", RO },
1326 { "lport-get-parent", 1, 1, "LPORT", NULL, nbctl_lport_get_parent, NULL,
1328 { "lport-get-tag", 1, 1, "LPORT", NULL, nbctl_lport_get_tag, NULL, "",
1330 { "lport-set-addresses", 1, INT_MAX, "LPORT [ADDRESS]...", NULL,
1331 nbctl_lport_set_addresses, NULL, "", RW },
1332 { "lport-get-addresses", 1, 1, "LPORT", NULL,
1333 nbctl_lport_get_addresses, NULL,
1335 { "lport-set-port-security", 0, INT_MAX, "LPORT [ADDRS]...", NULL,
1336 nbctl_lport_set_port_security, NULL, "", RW },
1337 { "lport-get-port-security", 1, 1, "LPORT", NULL,
1338 nbctl_lport_get_port_security, NULL, "", RO },
1339 { "lport-get-up", 1, 1, "LPORT", NULL, nbctl_lport_get_up, NULL, "", RO },
1340 { "lport-set-enabled", 2, 2, "LPORT STATE", NULL, nbctl_lport_set_enabled,
1342 { "lport-get-enabled", 1, 1, "LPORT", NULL, nbctl_lport_get_enabled, NULL,
1344 { "lport-set-type", 2, 2, "LPORT TYPE", NULL, nbctl_lport_set_type, NULL,
1346 { "lport-get-type", 1, 1, "LPORT", NULL, nbctl_lport_get_type, NULL, "",
1348 { "lport-set-options", 1, INT_MAX, "LPORT KEY=VALUE [KEY=VALUE]...", NULL,
1349 nbctl_lport_set_options, NULL, "", RW },
1350 { "lport-get-options", 1, 1, "LPORT", NULL, nbctl_lport_get_options, NULL,
1353 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
1356 /* Registers nbctl and common db commands. */
1358 nbctl_cmd_init(void)
1360 ctl_init(tables, NULL, nbctl_exit);
1361 ctl_register_commands(nbctl_commands);