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"
27 #include "stream-ssl.h"
29 #include "openvswitch/vlog.h"
31 VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
33 struct nbctl_context {
34 struct ovsdb_idl *idl;
35 struct ovsdb_idl_txn *txn;
38 static const char *db;
40 static const char *default_db(void);
46 %s: OVN northbound DB management utility\n\
47 usage: %s [OPTIONS] COMMAND [ARG...]\n\
49 Logical Switch Commands:\n\
50 lswitch-add [name] Create a logical switch\n\
51 lswitch-del <lswitch> Delete a logical switch\n\
52 lswitch-list List configured logical switches\n\
53 lswitch-set-external-id <lswitch> <key> [value]\n\
54 Set or delete an external:id on a logical switch\n\
55 lswitch-get-external-id <lswitch> [key]\n\
56 List one or all external:ids set on a switch\n\
58 Logical Port Commands:\n\
59 lport-add <name> <lswitch> Create a logical port on a logical switch\n\
60 lport-del <lport> Delete a logical port (by name or UUID)\n\
61 lport-list <lswitch> List ports on a logical switch\n\
62 lport-set-external-id <lport> <key> [value]\n\
63 Set or delete an external:id on a logical port\n\
64 lport-get-external-id <lport> [key]\n\
65 List one or all external:ids set on a port\n\
66 lport-set-macs <lport> [MAC] [MAC] [...]\n\
67 Set MAC addresses for the logical port. Specify\n\
68 more than one using additional arguments.\n\
69 lport-get-macs <lport> Get a list of MAC addresses on the port.\n\
72 --db=DATABASE connect to DATABASE\n\
74 -h, --help display this help message\n\
75 -o, --options list available options\n\
76 -V, --version display version information\n\
77 ", program_name, program_name, default_db());
79 stream_usage("database", true, true, false);
82 static const struct nbrec_logical_switch *
83 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
85 const struct nbrec_logical_switch *lswitch = NULL;
87 bool duplicate = false;
88 struct uuid lswitch_uuid;
90 if (uuid_from_string(&lswitch_uuid, id)) {
92 lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
97 const struct nbrec_logical_switch *iter;
99 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
100 if (strcmp(iter->name, id)) {
104 VLOG_WARN("There is more than one logical switch named '%s'. "
114 if (!lswitch && !duplicate) {
115 VLOG_WARN("lswitch not found for %s: '%s'",
116 is_uuid ? "UUID" : "name", id);
123 do_lswitch_add(struct ovs_cmdl_context *ctx)
125 struct nbctl_context *nb_ctx = ctx->pvt;
126 struct nbrec_logical_switch *lswitch;
128 lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
129 if (ctx->argc == 2) {
130 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
135 do_lswitch_del(struct ovs_cmdl_context *ctx)
137 struct nbctl_context *nb_ctx = ctx->pvt;
138 const char *id = ctx->argv[1];
139 const struct nbrec_logical_switch *lswitch;
141 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
146 nbrec_logical_switch_delete(lswitch);
150 do_lswitch_list(struct ovs_cmdl_context *ctx)
152 struct nbctl_context *nb_ctx = ctx->pvt;
153 const struct nbrec_logical_switch *lswitch;
155 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
156 printf(UUID_FMT " (%s)\n",
157 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
162 do_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
164 struct nbctl_context *nb_ctx = ctx->pvt;
165 const char *id = ctx->argv[1];
166 const struct nbrec_logical_switch *lswitch;
167 struct smap new_external_ids;
169 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
174 smap_init(&new_external_ids);
175 smap_clone(&new_external_ids, &lswitch->external_ids);
176 if (ctx->argc == 4) {
177 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
179 smap_remove(&new_external_ids, ctx->argv[2]);
181 nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
182 smap_destroy(&new_external_ids);
186 do_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
188 struct nbctl_context *nb_ctx = ctx->pvt;
189 const char *id = ctx->argv[1];
190 const struct nbrec_logical_switch *lswitch;
192 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
197 if (ctx->argc == 3) {
198 const char *key = ctx->argv[2];
201 /* List one external ID */
203 value = smap_get(&lswitch->external_ids, key);
204 if (value && *value) {
205 printf("%s\n", value);
207 printf("external-id '%s' is not set.\n", key);
210 struct smap_node *node;
212 /* List all external IDs */
214 SMAP_FOR_EACH(node, &lswitch->external_ids) {
215 printf("%s=%s\n", node->key, node->value);
220 static const struct nbrec_logical_port *
221 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
223 const struct nbrec_logical_port *lport = NULL;
224 bool is_uuid = false;
225 struct uuid lport_uuid;
227 if (uuid_from_string(&lport_uuid, id)) {
229 lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
233 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
234 if (!strcmp(lport->name, id)) {
241 VLOG_WARN("lport not found for %s: '%s'",
242 is_uuid ? "UUID" : "name", id);
249 do_lport_add(struct ovs_cmdl_context *ctx)
251 struct nbctl_context *nb_ctx = ctx->pvt;
252 struct nbrec_logical_port *lport;
253 const struct nbrec_logical_switch *lswitch;
255 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[2]);
260 lport = nbrec_logical_port_insert(nb_ctx->txn);
261 nbrec_logical_port_set_name(lport, ctx->argv[1]);
262 nbrec_logical_port_set_lswitch(lport, lswitch);
266 do_lport_del(struct ovs_cmdl_context *ctx)
268 struct nbctl_context *nb_ctx = ctx->pvt;
269 const struct nbrec_logical_port *lport;
271 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
276 nbrec_logical_port_delete(lport);
280 is_lswitch(const struct nbrec_logical_switch *lswitch,
281 struct uuid *lswitch_uuid, const char *name)
284 return uuid_equals(lswitch_uuid, &lswitch->header_.uuid);
286 return !strcmp(lswitch->name, name);
292 do_lport_list(struct ovs_cmdl_context *ctx)
294 struct nbctl_context *nb_ctx = ctx->pvt;
295 const char *id = ctx->argv[1];
296 const struct nbrec_logical_port *lport;
297 bool is_uuid = false;
298 struct uuid lswitch_uuid;
300 if (uuid_from_string(&lswitch_uuid, id)) {
304 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
307 match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL);
309 match = is_lswitch(lport->lswitch, NULL, id);
314 printf(UUID_FMT " (%s)\n",
315 UUID_ARGS(&lport->header_.uuid), lport->name);
320 do_lport_set_external_id(struct ovs_cmdl_context *ctx)
322 struct nbctl_context *nb_ctx = ctx->pvt;
323 const char *id = ctx->argv[1];
324 const struct nbrec_logical_port *lport;
325 struct smap new_external_ids;
327 lport = lport_by_name_or_uuid(nb_ctx, id);
332 smap_init(&new_external_ids);
333 smap_clone(&new_external_ids, &lport->external_ids);
334 if (ctx->argc == 4) {
335 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
337 smap_remove(&new_external_ids, ctx->argv[2]);
339 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
340 smap_destroy(&new_external_ids);
344 do_lport_get_external_id(struct ovs_cmdl_context *ctx)
346 struct nbctl_context *nb_ctx = ctx->pvt;
347 const char *id = ctx->argv[1];
348 const struct nbrec_logical_port *lport;
350 lport = lport_by_name_or_uuid(nb_ctx, id);
355 if (ctx->argc == 3) {
356 const char *key = ctx->argv[2];
359 /* List one external ID */
361 value = smap_get(&lport->external_ids, key);
362 if (value && *value) {
363 printf("%s\n", value);
365 printf("external-id '%s' is not set.\n", key);
368 struct smap_node *node;
370 /* List all external IDs */
372 SMAP_FOR_EACH(node, &lport->external_ids) {
373 printf("%s=%s\n", node->key, node->value);
379 do_lport_set_macs(struct ovs_cmdl_context *ctx)
381 struct nbctl_context *nb_ctx = ctx->pvt;
382 const char *id = ctx->argv[1];
383 const struct nbrec_logical_port *lport;
385 lport = lport_by_name_or_uuid(nb_ctx, id);
390 nbrec_logical_port_set_macs(lport,
391 (const char **) ctx->argv + 2, ctx->argc - 2);
395 do_lport_get_macs(struct ovs_cmdl_context *ctx)
397 struct nbctl_context *nb_ctx = ctx->pvt;
398 const char *id = ctx->argv[1];
399 const struct nbrec_logical_port *lport;
402 lport = lport_by_name_or_uuid(nb_ctx, id);
407 for (i = 0; i < lport->n_macs; i++) {
408 printf("%s\n", lport->macs[i]);
413 parse_options(int argc, char *argv[])
418 static const struct option long_options[] = {
419 {"db", required_argument, NULL, 'd'},
420 {"help", no_argument, NULL, 'h'},
421 {"options", no_argument, NULL, 'o'},
422 {"version", no_argument, NULL, 'V'},
424 STREAM_SSL_LONG_OPTIONS,
427 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
432 c = getopt_long(argc, argv, short_options, long_options, NULL);
438 VLOG_OPTION_HANDLERS;
439 STREAM_SSL_OPTION_HANDLERS;
450 ovs_cmdl_print_options(long_options);
454 ovs_print_version(0, 0);
469 static const struct ovs_cmdl_command all_commands[] = {
471 .name = "lswitch-add",
472 .usage = "[lswitch]",
475 .handler = do_lswitch_add,
478 .name = "lswitch-del",
479 .usage = "<lswitch>",
482 .handler = do_lswitch_del,
485 .name = "lswitch-list",
489 .handler = do_lswitch_list,
492 .name = "lswitch-set-external-id",
493 .usage = "<lswitch> <key> [value]",
496 .handler = do_lswitch_set_external_id,
499 .name = "lswitch-get-external-id",
500 .usage = "<lswitch> [key]",
503 .handler = do_lswitch_get_external_id,
507 .usage = "<name> <lswitch>",
510 .handler = do_lport_add,
517 .handler = do_lport_del,
520 .name = "lport-list",
521 .usage = "<lswitch>",
524 .handler = do_lport_list,
527 .name = "lport-set-external-id",
528 .usage = "<lport> <key> [value]",
531 .handler = do_lport_set_external_id,
534 .name = "lport-get-external-id",
535 .usage = "<lport> [key]",
538 .handler = do_lport_get_external_id,
541 .name = "lport-set-macs",
542 .usage = "<lport> [MAC] [MAC] [...]",
544 /* Accept however many arguments the system will allow. */
546 .handler = do_lport_set_macs,
549 .name = "lport-get-macs",
553 .handler = do_lport_get_macs,
562 static const struct ovs_cmdl_command *
563 get_all_commands(void)
573 def = xasprintf("unix:%s/db.sock", ovs_rundir());
579 main(int argc, char *argv[])
581 extern struct vlog_module VLM_reconnect;
582 struct ovs_cmdl_context ctx;
583 struct nbctl_context nb_ctx = { .idl = NULL, };
584 enum ovsdb_idl_txn_status txn_status;
588 fatal_ignore_sigpipe();
589 set_program_name(argv[0]);
590 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
591 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
592 parse_options(argc, argv);
595 nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
597 ctx.argc = argc - optind;
598 ctx.argv = argv + optind;
600 seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
602 ovsdb_idl_run(nb_ctx.idl);
604 if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
605 int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
606 VLOG_ERR("%s: database connection failed (%s)",
607 db, ovs_retval_to_string(retval));
612 if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
613 nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
614 ovs_cmdl_run_command(&ctx, get_all_commands());
615 txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
616 if (txn_status == TXN_TRY_AGAIN) {
617 ovsdb_idl_txn_destroy(nb_ctx.txn);
625 if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
626 ovsdb_idl_wait(nb_ctx.idl);
632 ovsdb_idl_txn_destroy(nb_ctx.txn);
634 ovsdb_idl_destroy(nb_ctx.idl);