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.
21 #include "command-line.h"
23 #include "fatal-signal.h"
24 #include "ovn/ovn-nb-idl.h"
25 #include "poll-loop.h"
28 #include "stream-ssl.h"
30 #include "openvswitch/vlog.h"
32 VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
34 struct nbctl_context {
35 struct ovsdb_idl *idl;
36 struct ovsdb_idl_txn *txn;
39 static const char *db;
41 static const char *default_db(void);
47 %s: OVN northbound DB management utility\n\
48 usage: %s [OPTIONS] COMMAND [ARG...]\n\
50 Logical Switch Commands:\n\
51 lswitch-add [name] Create a logical switch\n\
52 lswitch-del <lswitch> Delete a logical switch\n\
53 lswitch-list List configured logical switches\n\
54 lswitch-set-external-id <lswitch> <key> [value]\n\
55 Set or delete an external:id on a logical switch\n\
56 lswitch-get-external-id <lswitch> [key]\n\
57 List one or all external:ids set on a switch\n\
59 Logical Port Commands:\n\
60 lport-add <lswitch> <lport> Create a logical port on a logical switch\n\
61 lport-del <lport> Delete a logical port (by name or UUID)\n\
62 lport-list <lswitch> List ports on a logical switch\n\
63 lport-set-external-id <lport> <key> [value]\n\
64 Set or delete an external:id on a logical port\n\
65 lport-get-external-id <lport> [key]\n\
66 List one or all external:ids set on a port\n\
67 lport-set-macs <lport> [MAC] [MAC] [...]\n\
68 Set MAC addresses for the logical port. Specify\n\
69 more than one using additional arguments.\n\
70 lport-get-macs <lport> Get a list of MAC addresses on the port.\n\
71 lport-get-up <lport> Get state of the port ('up' or 'down').\n\
74 --db=DATABASE connect to DATABASE\n\
76 -h, --help display this help message\n\
77 -o, --options list available options\n\
78 -V, --version display version information\n\
79 ", program_name, program_name, default_db());
81 stream_usage("database", true, true, false);
84 static const struct nbrec_logical_switch *
85 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
87 const struct nbrec_logical_switch *lswitch = NULL;
89 bool duplicate = false;
90 struct uuid lswitch_uuid;
92 if (uuid_from_string(&lswitch_uuid, id)) {
94 lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
99 const struct nbrec_logical_switch *iter;
101 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
102 if (strcmp(iter->name, id)) {
106 VLOG_WARN("There is more than one logical switch named '%s'. "
116 if (!lswitch && !duplicate) {
117 VLOG_WARN("lswitch not found for %s: '%s'",
118 is_uuid ? "UUID" : "name", id);
125 do_lswitch_add(struct ovs_cmdl_context *ctx)
127 struct nbctl_context *nb_ctx = ctx->pvt;
128 struct nbrec_logical_switch *lswitch;
130 lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
131 if (ctx->argc == 2) {
132 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
137 do_lswitch_del(struct ovs_cmdl_context *ctx)
139 struct nbctl_context *nb_ctx = ctx->pvt;
140 const char *id = ctx->argv[1];
141 const struct nbrec_logical_switch *lswitch;
143 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
148 nbrec_logical_switch_delete(lswitch);
152 do_lswitch_list(struct ovs_cmdl_context *ctx)
154 struct nbctl_context *nb_ctx = ctx->pvt;
155 const struct nbrec_logical_switch *lswitch;
157 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
158 printf(UUID_FMT " (%s)\n",
159 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
164 do_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
166 struct nbctl_context *nb_ctx = ctx->pvt;
167 const char *id = ctx->argv[1];
168 const struct nbrec_logical_switch *lswitch;
169 struct smap new_external_ids;
171 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
176 smap_init(&new_external_ids);
177 smap_clone(&new_external_ids, &lswitch->external_ids);
178 if (ctx->argc == 4) {
179 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
181 smap_remove(&new_external_ids, ctx->argv[2]);
183 nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
184 smap_destroy(&new_external_ids);
188 do_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
190 struct nbctl_context *nb_ctx = ctx->pvt;
191 const char *id = ctx->argv[1];
192 const struct nbrec_logical_switch *lswitch;
194 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
199 if (ctx->argc == 3) {
200 const char *key = ctx->argv[2];
203 /* List one external ID */
205 value = smap_get(&lswitch->external_ids, key);
206 if (value && *value) {
207 printf("%s\n", value);
209 printf("external-id '%s' is not set.\n", key);
212 struct smap_node *node;
214 /* List all external IDs */
216 SMAP_FOR_EACH(node, &lswitch->external_ids) {
217 printf("%s=%s\n", node->key, node->value);
222 static const struct nbrec_logical_port *
223 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
225 const struct nbrec_logical_port *lport = NULL;
226 bool is_uuid = false;
227 struct uuid lport_uuid;
229 if (uuid_from_string(&lport_uuid, id)) {
231 lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
235 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
236 if (!strcmp(lport->name, id)) {
243 VLOG_WARN("lport not found for %s: '%s'",
244 is_uuid ? "UUID" : "name", id);
251 do_lport_add(struct ovs_cmdl_context *ctx)
253 struct nbctl_context *nb_ctx = ctx->pvt;
254 struct nbrec_logical_port *lport;
255 const struct nbrec_logical_switch *lswitch;
257 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
262 lport = nbrec_logical_port_insert(nb_ctx->txn);
263 nbrec_logical_port_set_name(lport, ctx->argv[2]);
264 nbrec_logical_port_set_lswitch(lport, lswitch);
268 do_lport_del(struct ovs_cmdl_context *ctx)
270 struct nbctl_context *nb_ctx = ctx->pvt;
271 const struct nbrec_logical_port *lport;
273 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
278 nbrec_logical_port_delete(lport);
282 is_lswitch(const struct nbrec_logical_switch *lswitch,
283 struct uuid *lswitch_uuid, const char *name)
286 return uuid_equals(lswitch_uuid, &lswitch->header_.uuid);
288 return !strcmp(lswitch->name, name);
294 do_lport_list(struct ovs_cmdl_context *ctx)
296 struct nbctl_context *nb_ctx = ctx->pvt;
297 const char *id = ctx->argv[1];
298 const struct nbrec_logical_port *lport;
299 bool is_uuid = false;
300 struct uuid lswitch_uuid;
302 if (uuid_from_string(&lswitch_uuid, id)) {
306 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
309 match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL);
311 match = is_lswitch(lport->lswitch, NULL, id);
316 printf(UUID_FMT " (%s)\n",
317 UUID_ARGS(&lport->header_.uuid), lport->name);
322 do_lport_set_external_id(struct ovs_cmdl_context *ctx)
324 struct nbctl_context *nb_ctx = ctx->pvt;
325 const char *id = ctx->argv[1];
326 const struct nbrec_logical_port *lport;
327 struct smap new_external_ids;
329 lport = lport_by_name_or_uuid(nb_ctx, id);
334 smap_init(&new_external_ids);
335 smap_clone(&new_external_ids, &lport->external_ids);
336 if (ctx->argc == 4) {
337 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
339 smap_remove(&new_external_ids, ctx->argv[2]);
341 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
342 smap_destroy(&new_external_ids);
346 do_lport_get_external_id(struct ovs_cmdl_context *ctx)
348 struct nbctl_context *nb_ctx = ctx->pvt;
349 const char *id = ctx->argv[1];
350 const struct nbrec_logical_port *lport;
352 lport = lport_by_name_or_uuid(nb_ctx, id);
357 if (ctx->argc == 3) {
358 const char *key = ctx->argv[2];
361 /* List one external ID */
363 value = smap_get(&lport->external_ids, key);
364 if (value && *value) {
365 printf("%s\n", value);
367 printf("external-id '%s' is not set.\n", key);
370 struct smap_node *node;
372 /* List all external IDs */
374 SMAP_FOR_EACH(node, &lport->external_ids) {
375 printf("%s=%s\n", node->key, node->value);
381 do_lport_set_macs(struct ovs_cmdl_context *ctx)
383 struct nbctl_context *nb_ctx = ctx->pvt;
384 const char *id = ctx->argv[1];
385 const struct nbrec_logical_port *lport;
387 lport = lport_by_name_or_uuid(nb_ctx, id);
392 nbrec_logical_port_set_macs(lport,
393 (const char **) ctx->argv + 2, ctx->argc - 2);
397 do_lport_get_macs(struct ovs_cmdl_context *ctx)
399 struct nbctl_context *nb_ctx = ctx->pvt;
400 const char *id = ctx->argv[1];
401 const struct nbrec_logical_port *lport;
404 lport = lport_by_name_or_uuid(nb_ctx, id);
409 for (i = 0; i < lport->n_macs; i++) {
410 printf("%s\n", lport->macs[i]);
415 do_lport_get_up(struct ovs_cmdl_context *ctx)
417 struct nbctl_context *nb_ctx = ctx->pvt;
418 const char *id = ctx->argv[1];
419 const struct nbrec_logical_port *lport;
421 lport = lport_by_name_or_uuid(nb_ctx, id);
426 printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
430 parse_options(int argc, char *argv[])
435 static const struct option long_options[] = {
436 {"db", required_argument, NULL, 'd'},
437 {"help", no_argument, NULL, 'h'},
438 {"options", no_argument, NULL, 'o'},
439 {"version", no_argument, NULL, 'V'},
441 STREAM_SSL_LONG_OPTIONS,
444 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
449 c = getopt_long(argc, argv, short_options, long_options, NULL);
455 VLOG_OPTION_HANDLERS;
456 STREAM_SSL_OPTION_HANDLERS;
467 ovs_cmdl_print_options(long_options);
471 ovs_print_version(0, 0);
486 static const struct ovs_cmdl_command all_commands[] = {
488 .name = "lswitch-add",
489 .usage = "[lswitch]",
492 .handler = do_lswitch_add,
495 .name = "lswitch-del",
496 .usage = "<lswitch>",
499 .handler = do_lswitch_del,
502 .name = "lswitch-list",
506 .handler = do_lswitch_list,
509 .name = "lswitch-set-external-id",
510 .usage = "<lswitch> <key> [value]",
513 .handler = do_lswitch_set_external_id,
516 .name = "lswitch-get-external-id",
517 .usage = "<lswitch> [key]",
520 .handler = do_lswitch_get_external_id,
524 .usage = "<lswitch> <name>",
527 .handler = do_lport_add,
534 .handler = do_lport_del,
537 .name = "lport-list",
538 .usage = "<lswitch>",
541 .handler = do_lport_list,
544 .name = "lport-set-external-id",
545 .usage = "<lport> <key> [value]",
548 .handler = do_lport_set_external_id,
551 .name = "lport-get-external-id",
552 .usage = "<lport> [key]",
555 .handler = do_lport_get_external_id,
558 .name = "lport-set-macs",
559 .usage = "<lport> [MAC] [MAC] [...]",
561 /* Accept however many arguments the system will allow. */
563 .handler = do_lport_set_macs,
566 .name = "lport-get-macs",
570 .handler = do_lport_get_macs,
573 .name = "lport-get-up",
577 .handler = do_lport_get_up,
586 static const struct ovs_cmdl_command *
587 get_all_commands(void)
597 def = xasprintf("unix:%s/db.sock", ovs_rundir());
603 main(int argc, char *argv[])
605 extern struct vlog_module VLM_reconnect;
606 struct ovs_cmdl_context ctx;
607 struct nbctl_context nb_ctx = { .idl = NULL, };
608 enum ovsdb_idl_txn_status txn_status;
613 fatal_ignore_sigpipe();
614 set_program_name(argv[0]);
615 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
616 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
617 parse_options(argc, argv);
620 args = process_escape_args(argv);
622 nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
624 ctx.argc = argc - optind;
625 ctx.argv = argv + optind;
627 seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
629 ovsdb_idl_run(nb_ctx.idl);
631 if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
632 int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
633 VLOG_ERR("%s: database connection failed (%s)",
634 db, ovs_retval_to_string(retval));
639 if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
640 nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
641 ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
642 ovs_cmdl_run_command(&ctx, get_all_commands());
643 txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
644 if (txn_status == TXN_TRY_AGAIN) {
645 ovsdb_idl_txn_destroy(nb_ctx.txn);
653 if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
654 ovsdb_idl_wait(nb_ctx.idl);
660 ovsdb_idl_txn_destroy(nb_ctx.txn);
662 ovsdb_idl_destroy(nb_ctx.idl);