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"
24 #include "fatal-signal.h"
25 #include "ovn/lib/ovn-nb-idl.h"
26 #include "poll-loop.h"
29 #include "stream-ssl.h"
31 #include "openvswitch/vlog.h"
33 VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
35 struct nbctl_context {
36 struct ovsdb_idl *idl;
37 struct ovsdb_idl_txn *txn;
40 static const char *db;
42 static const char *default_db(void);
48 %s: OVN northbound DB management utility\n\
49 usage: %s [OPTIONS] COMMAND [ARG...]\n\
52 show print overview of database contents\n\
53 show LSWITCH print overview of database contents for LSWITCH\n\
55 Logical switch commands:\n\
56 lswitch-add [LSWITCH] create a logical switch named LSWITCH\n\
57 lswitch-del LSWITCH delete LSWITCH and all its ports\n\
58 lswitch-list print the names of all logical switches\n\
59 lswitch-set-external-id LSWITCH KEY [VALUE]\n\
60 set or delete an external-id on LSWITCH\n\
61 lswitch-get-external-id LSWITCH [KEY]\n\
62 list one or all external-ids on LSWITCH\n\
64 Logical port commands:\n\
65 lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
66 lport-add LSWITCH LPORT PARENT TAG\n\
67 add logical port LPORT on LSWITCH with PARENT\n\
69 lport-del LPORT delete LPORT from its attached switch\n\
70 lport-list LSWITCH print the names of all logical ports on LSWITCH\n\
71 lport-get-parent LPORT get the parent of LPORT if set\n\
72 lport-get-tag LPORT get the LPORT's tag if set\n\
73 lport-set-external-id LPORT KEY [VALUE]\n\
74 set or delete an external-id on LPORT\n\
75 lport-get-external-id LPORT [KEY]\n\
76 list one or all external-ids on LPORT\n\
77 lport-set-macs LPORT [MAC]...\n\
78 set MAC addresses for LPORT.\n\
79 lport-get-macs LPORT get a list of MAC addresses on LPORT\n\
80 lport-set-port-security LPORT [ADDRS]...\n\
81 set port security addresses for LPORT.\n\
82 lport-get-port-security LPORT get LPORT's port security addresses\n\
83 lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
86 --db=DATABASE connect to DATABASE\n\
88 -h, --help display this help message\n\
89 -o, --options list available options\n\
90 -V, --version display version information\n\
91 ", program_name, program_name, default_db());
93 stream_usage("database", true, true, false);
96 static const struct nbrec_logical_switch *
97 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
99 const struct nbrec_logical_switch *lswitch = NULL;
100 bool is_uuid = false;
101 bool duplicate = false;
102 struct uuid lswitch_uuid;
104 if (uuid_from_string(&lswitch_uuid, id)) {
106 lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
111 const struct nbrec_logical_switch *iter;
113 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
114 if (strcmp(iter->name, id)) {
118 VLOG_WARN("There is more than one logical switch named '%s'. "
128 if (!lswitch && !duplicate) {
129 VLOG_WARN("lswitch not found for %s: '%s'",
130 is_uuid ? "UUID" : "name", id);
137 print_lswitch(const struct nbctl_context *nb_ctx,
138 const struct nbrec_logical_switch *lswitch)
140 const struct nbrec_logical_port *lport;
142 printf(" lswitch "UUID_FMT" (%s)\n",
143 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
145 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
148 if (lport->lswitch == lswitch) {
149 printf(" lport %s\n", lport->name);
150 if (lport->parent_name && lport->n_tag) {
151 printf(" parent: %s, tag:%"PRIu64"\n",
152 lport->parent_name, lport->tag[0]);
156 for (i=0; i < lport->n_macs; i++) {
157 printf(" %s", lport->macs[i]);
166 do_show(struct ovs_cmdl_context *ctx)
168 struct nbctl_context *nb_ctx = ctx->pvt;
169 const struct nbrec_logical_switch *lswitch;
171 if (ctx->argc == 2) {
172 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
174 print_lswitch(nb_ctx, lswitch);
177 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
178 print_lswitch(nb_ctx, lswitch);
184 do_lswitch_add(struct ovs_cmdl_context *ctx)
186 struct nbctl_context *nb_ctx = ctx->pvt;
187 struct nbrec_logical_switch *lswitch;
189 lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
190 if (ctx->argc == 2) {
191 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
196 do_lswitch_del(struct ovs_cmdl_context *ctx)
198 struct nbctl_context *nb_ctx = ctx->pvt;
199 const char *id = ctx->argv[1];
200 const struct nbrec_logical_switch *lswitch;
202 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
207 nbrec_logical_switch_delete(lswitch);
211 do_lswitch_list(struct ovs_cmdl_context *ctx)
213 struct nbctl_context *nb_ctx = ctx->pvt;
214 const struct nbrec_logical_switch *lswitch;
216 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
217 printf(UUID_FMT " (%s)\n",
218 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
223 do_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
225 struct nbctl_context *nb_ctx = ctx->pvt;
226 const char *id = ctx->argv[1];
227 const struct nbrec_logical_switch *lswitch;
228 struct smap new_external_ids;
230 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
235 smap_init(&new_external_ids);
236 smap_clone(&new_external_ids, &lswitch->external_ids);
237 if (ctx->argc == 4) {
238 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
240 smap_remove(&new_external_ids, ctx->argv[2]);
242 nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
243 smap_destroy(&new_external_ids);
247 do_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
249 struct nbctl_context *nb_ctx = ctx->pvt;
250 const char *id = ctx->argv[1];
251 const struct nbrec_logical_switch *lswitch;
253 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
258 if (ctx->argc == 3) {
259 const char *key = ctx->argv[2];
262 /* List one external ID */
264 value = smap_get(&lswitch->external_ids, key);
266 printf("%s\n", value);
269 struct smap_node *node;
271 /* List all external IDs */
273 SMAP_FOR_EACH(node, &lswitch->external_ids) {
274 printf("%s=%s\n", node->key, node->value);
279 static const struct nbrec_logical_port *
280 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
282 const struct nbrec_logical_port *lport = NULL;
283 bool is_uuid = false;
284 struct uuid lport_uuid;
286 if (uuid_from_string(&lport_uuid, id)) {
288 lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
292 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
293 if (!strcmp(lport->name, id)) {
300 VLOG_WARN("lport not found for %s: '%s'",
301 is_uuid ? "UUID" : "name", id);
308 do_lport_add(struct ovs_cmdl_context *ctx)
310 struct nbctl_context *nb_ctx = ctx->pvt;
311 struct nbrec_logical_port *lport;
312 const struct nbrec_logical_switch *lswitch;
315 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
320 if (ctx->argc != 3 && ctx->argc != 5) {
321 /* If a parent_name is specififed, a tag must be specified as well. */
322 VLOG_WARN("Invalid arguments to lport-add.");
326 if (ctx->argc == 5) {
328 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
329 VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
334 /* Finally, create the transaction. */
335 lport = nbrec_logical_port_insert(nb_ctx->txn);
336 nbrec_logical_port_set_name(lport, ctx->argv[2]);
337 nbrec_logical_port_set_lswitch(lport, lswitch);
338 if (ctx->argc == 5) {
339 nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
340 nbrec_logical_port_set_tag(lport, &tag, 1);
345 do_lport_del(struct ovs_cmdl_context *ctx)
347 struct nbctl_context *nb_ctx = ctx->pvt;
348 const struct nbrec_logical_port *lport;
350 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
355 nbrec_logical_port_delete(lport);
359 is_lswitch(const struct nbrec_logical_switch *lswitch,
360 struct uuid *lswitch_uuid, const char *name)
363 return uuid_equals(lswitch_uuid, &lswitch->header_.uuid);
365 return !strcmp(lswitch->name, name);
371 do_lport_list(struct ovs_cmdl_context *ctx)
373 struct nbctl_context *nb_ctx = ctx->pvt;
374 const char *id = ctx->argv[1];
375 const struct nbrec_logical_port *lport;
376 bool is_uuid = false;
377 struct uuid lswitch_uuid;
379 if (uuid_from_string(&lswitch_uuid, id)) {
383 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
386 match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL);
388 match = is_lswitch(lport->lswitch, NULL, id);
393 printf(UUID_FMT " (%s)\n",
394 UUID_ARGS(&lport->header_.uuid), lport->name);
399 do_lport_get_parent(struct ovs_cmdl_context *ctx)
401 struct nbctl_context *nb_ctx = ctx->pvt;
402 const struct nbrec_logical_port *lport;
404 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
409 if (lport->parent_name) {
410 printf("%s\n", lport->parent_name);
415 do_lport_get_tag(struct ovs_cmdl_context *ctx)
417 struct nbctl_context *nb_ctx = ctx->pvt;
418 const struct nbrec_logical_port *lport;
420 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
425 if (lport->n_tag > 0) {
426 printf("%"PRId64"\n", lport->tag[0]);
431 do_lport_set_external_id(struct ovs_cmdl_context *ctx)
433 struct nbctl_context *nb_ctx = ctx->pvt;
434 const char *id = ctx->argv[1];
435 const struct nbrec_logical_port *lport;
436 struct smap new_external_ids;
438 lport = lport_by_name_or_uuid(nb_ctx, id);
443 smap_init(&new_external_ids);
444 smap_clone(&new_external_ids, &lport->external_ids);
445 if (ctx->argc == 4) {
446 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
448 smap_remove(&new_external_ids, ctx->argv[2]);
450 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
451 smap_destroy(&new_external_ids);
455 do_lport_get_external_id(struct ovs_cmdl_context *ctx)
457 struct nbctl_context *nb_ctx = ctx->pvt;
458 const char *id = ctx->argv[1];
459 const struct nbrec_logical_port *lport;
461 lport = lport_by_name_or_uuid(nb_ctx, id);
466 if (ctx->argc == 3) {
467 const char *key = ctx->argv[2];
470 /* List one external ID */
472 value = smap_get(&lport->external_ids, key);
474 printf("%s\n", value);
477 struct smap_node *node;
479 /* List all external IDs */
481 SMAP_FOR_EACH(node, &lport->external_ids) {
482 printf("%s=%s\n", node->key, node->value);
488 do_lport_set_macs(struct ovs_cmdl_context *ctx)
490 struct nbctl_context *nb_ctx = ctx->pvt;
491 const char *id = ctx->argv[1];
492 const struct nbrec_logical_port *lport;
494 lport = lport_by_name_or_uuid(nb_ctx, id);
499 nbrec_logical_port_set_macs(lport,
500 (const char **) ctx->argv + 2, ctx->argc - 2);
504 do_lport_get_macs(struct ovs_cmdl_context *ctx)
506 struct nbctl_context *nb_ctx = ctx->pvt;
507 const char *id = ctx->argv[1];
508 const struct nbrec_logical_port *lport;
511 lport = lport_by_name_or_uuid(nb_ctx, id);
516 for (i = 0; i < lport->n_macs; i++) {
517 printf("%s\n", lport->macs[i]);
522 do_lport_set_port_security(struct ovs_cmdl_context *ctx)
524 struct nbctl_context *nb_ctx = ctx->pvt;
525 const char *id = ctx->argv[1];
526 const struct nbrec_logical_port *lport;
528 lport = lport_by_name_or_uuid(nb_ctx, id);
533 nbrec_logical_port_set_port_security(lport,
534 (const char **) ctx->argv + 2, ctx->argc - 2);
538 do_lport_get_port_security(struct ovs_cmdl_context *ctx)
540 struct nbctl_context *nb_ctx = ctx->pvt;
541 const char *id = ctx->argv[1];
542 const struct nbrec_logical_port *lport;
545 lport = lport_by_name_or_uuid(nb_ctx, id);
550 for (i = 0; i < lport->n_port_security; i++) {
551 printf("%s\n", lport->port_security[i]);
556 do_lport_get_up(struct ovs_cmdl_context *ctx)
558 struct nbctl_context *nb_ctx = ctx->pvt;
559 const char *id = ctx->argv[1];
560 const struct nbrec_logical_port *lport;
562 lport = lport_by_name_or_uuid(nb_ctx, id);
567 printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
571 parse_options(int argc, char *argv[])
576 static const struct option long_options[] = {
577 {"db", required_argument, NULL, 'd'},
578 {"help", no_argument, NULL, 'h'},
579 {"options", no_argument, NULL, 'o'},
580 {"version", no_argument, NULL, 'V'},
582 STREAM_SSL_LONG_OPTIONS,
585 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
590 c = getopt_long(argc, argv, short_options, long_options, NULL);
596 VLOG_OPTION_HANDLERS;
597 STREAM_SSL_OPTION_HANDLERS;
608 ovs_cmdl_print_options(long_options);
612 ovs_print_version(0, 0);
627 static const struct ovs_cmdl_command all_commands[] = {
630 .usage = "[LSWITCH]",
636 .name = "lswitch-add",
637 .usage = "[LSWITCH]",
640 .handler = do_lswitch_add,
643 .name = "lswitch-del",
647 .handler = do_lswitch_del,
650 .name = "lswitch-list",
654 .handler = do_lswitch_list,
657 .name = "lswitch-set-external-id",
658 .usage = "LSWITCH KEY [VALUE]",
661 .handler = do_lswitch_set_external_id,
664 .name = "lswitch-get-external-id",
665 .usage = "LSWITCH [KEY]",
668 .handler = do_lswitch_get_external_id,
672 .usage = "LSWITCH LPORT [PARENT] [TAG]",
675 .handler = do_lport_add,
682 .handler = do_lport_del,
685 .name = "lport-list",
689 .handler = do_lport_list,
692 .name = "lport-get-parent",
696 .handler = do_lport_get_parent,
699 .name = "lport-get-tag",
703 .handler = do_lport_get_tag,
706 .name = "lport-set-external-id",
707 .usage = "LPORT KEY [VALUE]",
710 .handler = do_lport_set_external_id,
713 .name = "lport-get-external-id",
714 .usage = "LPORT [KEY]",
717 .handler = do_lport_get_external_id,
720 .name = "lport-set-macs",
721 .usage = "LPORT [MAC]...",
723 /* Accept however many arguments the system will allow. */
725 .handler = do_lport_set_macs,
728 .name = "lport-get-macs",
732 .handler = do_lport_get_macs,
735 .name = "lport-set-port-security",
736 .usage = "LPORT [ADDRS]...",
738 /* Accept however many arguments the system will allow. */
740 .handler = do_lport_set_port_security,
743 .name = "lport-get-port-security",
747 .handler = do_lport_get_port_security,
750 .name = "lport-get-up",
754 .handler = do_lport_get_up,
763 static const struct ovs_cmdl_command *
764 get_all_commands(void)
774 def = xasprintf("unix:%s/db.sock", ovs_rundir());
780 main(int argc, char *argv[])
782 extern struct vlog_module VLM_reconnect;
783 struct ovs_cmdl_context ctx;
784 struct nbctl_context nb_ctx = { .idl = NULL, };
785 enum ovsdb_idl_txn_status txn_status;
790 fatal_ignore_sigpipe();
791 set_program_name(argv[0]);
792 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
793 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
794 parse_options(argc, argv);
797 args = process_escape_args(argv);
799 nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
801 ctx.argc = argc - optind;
802 ctx.argv = argv + optind;
804 seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
806 ovsdb_idl_run(nb_ctx.idl);
808 if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
809 int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
810 VLOG_ERR("%s: database connection failed (%s)",
811 db, ovs_retval_to_string(retval));
816 if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
817 nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
818 ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
819 ovs_cmdl_run_command(&ctx, get_all_commands());
820 txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
821 if (txn_status == TXN_TRY_AGAIN) {
822 ovsdb_idl_txn_destroy(nb_ctx.txn);
830 if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
831 ovsdb_idl_wait(nb_ctx.idl);
837 ovsdb_idl_txn_destroy(nb_ctx.txn);
839 ovsdb_idl_destroy(nb_ctx.idl);