]> git.proxmox.com Git - mirror_ovs.git/blob - ovn/utilities/ovn-nbctl.c
ovn-sbctl: Remove unused enum.
[mirror_ovs.git] / ovn / utilities / ovn-nbctl.c
1 /*
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:
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
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.
13 */
14
15 #include <config.h>
16
17 #include <getopt.h>
18 #include <inttypes.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21
22 #include "command-line.h"
23 #include "db-ctl-base.h"
24 #include "dirs.h"
25 #include "fatal-signal.h"
26 #include "openvswitch/json.h"
27 #include "ovn/lib/ovn-nb-idl.h"
28 #include "packets.h"
29 #include "poll-loop.h"
30 #include "process.h"
31 #include "smap.h"
32 #include "sset.h"
33 #include "stream.h"
34 #include "stream-ssl.h"
35 #include "svec.h"
36 #include "table.h"
37 #include "timeval.h"
38 #include "util.h"
39 #include "openvswitch/vlog.h"
40
41 VLOG_DEFINE_THIS_MODULE(nbctl);
42
43 /* --db: The database server to contact. */
44 static const char *db;
45
46 /* --oneline: Write each command's output as a single line? */
47 static bool oneline;
48
49 /* --dry-run: Do not commit any changes. */
50 static bool dry_run;
51
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. */
57 };
58 static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE;
59
60 /* Should we wait (if specified by 'wait_type') even if the commands don't
61 * change the database at all? */
62 static bool force_wait = false;
63
64 /* --timeout: Time to wait for a connection to 'db'. */
65 static int timeout;
66
67 /* Format for table output. */
68 static struct table_style table_style = TABLE_STYLE_DEFAULT;
69
70 /* The IDL we're using and the current transaction, if any.
71 * This is for use by nbctl_exit() only, to allow it to clean up.
72 * Other code should use its context arguments. */
73 static struct ovsdb_idl *the_idl;
74 static struct ovsdb_idl_txn *the_idl_txn;
75 OVS_NO_RETURN static void nbctl_exit(int status);
76
77 static void nbctl_cmd_init(void);
78 OVS_NO_RETURN static void usage(void);
79 static void parse_options(int argc, char *argv[], struct shash *local_options);
80 static const char *nbctl_default_db(void);
81 static void run_prerequisites(struct ctl_command[], size_t n_commands,
82 struct ovsdb_idl *);
83 static bool do_nbctl(const char *args, struct ctl_command *, size_t n,
84 struct ovsdb_idl *);
85 static const struct nbrec_dhcp_options *dhcp_options_get(
86 struct ctl_context *ctx, const char *id, bool must_exist);
87
88 int
89 main(int argc, char *argv[])
90 {
91 struct ovsdb_idl *idl;
92 struct ctl_command *commands;
93 struct shash local_options;
94 unsigned int seqno;
95 size_t n_commands;
96 char *args;
97
98 set_program_name(argv[0]);
99 fatal_ignore_sigpipe();
100 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
101 vlog_set_levels_from_string_assert("reconnect:warn");
102 nbrec_init();
103
104 nbctl_cmd_init();
105
106 /* Log our arguments. This is often valuable for debugging systems. */
107 args = process_escape_args(argv);
108 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
109 "Called as %s", args);
110
111 /* Parse command line. */
112 shash_init(&local_options);
113 parse_options(argc, argv, &local_options);
114 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
115 &n_commands);
116
117 if (timeout) {
118 time_alarm(timeout);
119 }
120
121 /* Initialize IDL. */
122 idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
123 run_prerequisites(commands, n_commands, idl);
124
125 /* Execute the commands.
126 *
127 * 'seqno' is the database sequence number for which we last tried to
128 * execute our transaction. There's no point in trying to commit more than
129 * once for any given sequence number, because if the transaction fails
130 * it's because the database changed and we need to obtain an up-to-date
131 * view of the database before we try the transaction again. */
132 seqno = ovsdb_idl_get_seqno(idl);
133 for (;;) {
134 ovsdb_idl_run(idl);
135 if (!ovsdb_idl_is_alive(idl)) {
136 int retval = ovsdb_idl_get_last_error(idl);
137 ctl_fatal("%s: database connection failed (%s)",
138 db, ovs_retval_to_string(retval));
139 }
140
141 if (seqno != ovsdb_idl_get_seqno(idl)) {
142 seqno = ovsdb_idl_get_seqno(idl);
143 if (do_nbctl(args, commands, n_commands, idl)) {
144 free(args);
145 exit(EXIT_SUCCESS);
146 }
147 }
148
149 if (seqno == ovsdb_idl_get_seqno(idl)) {
150 ovsdb_idl_wait(idl);
151 poll_block();
152 }
153 }
154 }
155
156 static const char *
157 nbctl_default_db(void)
158 {
159 static char *def;
160 if (!def) {
161 def = getenv("OVN_NB_DB");
162 if (!def) {
163 def = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
164 }
165 }
166 return def;
167 }
168
169 static void
170 parse_options(int argc, char *argv[], struct shash *local_options)
171 {
172 enum {
173 OPT_DB = UCHAR_MAX + 1,
174 OPT_NO_SYSLOG,
175 OPT_NO_WAIT,
176 OPT_WAIT,
177 OPT_DRY_RUN,
178 OPT_ONELINE,
179 OPT_LOCAL,
180 OPT_COMMANDS,
181 OPT_OPTIONS,
182 VLOG_OPTION_ENUMS,
183 TABLE_OPTION_ENUMS
184 };
185 static const struct option global_long_options[] = {
186 {"db", required_argument, NULL, OPT_DB},
187 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
188 {"no-wait", no_argument, NULL, OPT_NO_WAIT},
189 {"wait", required_argument, NULL, OPT_WAIT},
190 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
191 {"oneline", no_argument, NULL, OPT_ONELINE},
192 {"timeout", required_argument, NULL, 't'},
193 {"help", no_argument, NULL, 'h'},
194 {"commands", no_argument, NULL, OPT_COMMANDS},
195 {"options", no_argument, NULL, OPT_OPTIONS},
196 {"version", no_argument, NULL, 'V'},
197 VLOG_LONG_OPTIONS,
198 STREAM_SSL_LONG_OPTIONS,
199 TABLE_LONG_OPTIONS,
200 {NULL, 0, NULL, 0},
201 };
202 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
203 char *tmp, *short_options;
204
205 struct option *options;
206 size_t allocated_options;
207 size_t n_options;
208 size_t i;
209
210 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
211 short_options = xasprintf("+%s", tmp);
212 free(tmp);
213
214 /* We want to parse both global and command-specific options here, but
215 * getopt_long() isn't too convenient for the job. We copy our global
216 * options into a dynamic array, then append all of the command-specific
217 * options. */
218 options = xmemdup(global_long_options, sizeof global_long_options);
219 allocated_options = ARRAY_SIZE(global_long_options);
220 n_options = n_global_long_options;
221 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
222 table_style.format = TF_LIST;
223
224 for (;;) {
225 int idx;
226 int c;
227
228 c = getopt_long(argc, argv, short_options, options, &idx);
229 if (c == -1) {
230 break;
231 }
232
233 switch (c) {
234 case OPT_DB:
235 db = optarg;
236 break;
237
238 case OPT_ONELINE:
239 oneline = true;
240 break;
241
242 case OPT_NO_SYSLOG:
243 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
244 break;
245
246 case OPT_NO_WAIT:
247 wait_type = NBCTL_WAIT_NONE;
248 break;
249
250 case OPT_WAIT:
251 if (!strcmp(optarg, "none")) {
252 wait_type = NBCTL_WAIT_NONE;
253 } else if (!strcmp(optarg, "sb")) {
254 wait_type = NBCTL_WAIT_SB;
255 } else if (!strcmp(optarg, "hv")) {
256 wait_type = NBCTL_WAIT_HV;
257 } else {
258 ctl_fatal("argument to --wait must be "
259 "\"none\", \"sb\", or \"hv\"");
260 }
261 break;
262
263 case OPT_DRY_RUN:
264 dry_run = true;
265 break;
266
267 case OPT_LOCAL:
268 if (shash_find(local_options, options[idx].name)) {
269 ctl_fatal("'%s' option specified multiple times",
270 options[idx].name);
271 }
272 shash_add_nocopy(local_options,
273 xasprintf("--%s", options[idx].name),
274 nullable_xstrdup(optarg));
275 break;
276
277 case 'h':
278 usage();
279 exit(EXIT_SUCCESS);
280
281 case OPT_COMMANDS:
282 ctl_print_commands();
283
284 case OPT_OPTIONS:
285 ctl_print_options(global_long_options);
286
287 case 'V':
288 ovs_print_version(0, 0);
289 printf("DB Schema %s\n", nbrec_get_db_version());
290 exit(EXIT_SUCCESS);
291
292 case 't':
293 timeout = strtoul(optarg, NULL, 10);
294 if (timeout < 0) {
295 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
296 }
297 break;
298
299 VLOG_OPTION_HANDLERS
300 TABLE_OPTION_HANDLERS(&table_style)
301 STREAM_SSL_OPTION_HANDLERS
302
303 case '?':
304 exit(EXIT_FAILURE);
305
306 default:
307 abort();
308 }
309 }
310 free(short_options);
311
312 if (!db) {
313 db = nbctl_default_db();
314 }
315
316 for (i = n_global_long_options; options[i].name; i++) {
317 free(CONST_CAST(char *, options[i].name));
318 }
319 free(options);
320 }
321
322 static void
323 usage(void)
324 {
325 printf("\
326 %s: OVN northbound DB management utility\n\
327 usage: %s [OPTIONS] COMMAND [ARG...]\n\
328 \n\
329 General commands:\n\
330 init initialize the database\n\
331 show print overview of database contents\n\
332 show SWITCH print overview of database contents for SWITCH\n\
333 show ROUTER print overview of database contents for ROUTER\n\
334 \n\
335 Logical switch commands:\n\
336 ls-add [SWITCH] create a logical switch named SWITCH\n\
337 ls-del SWITCH delete SWITCH and all its ports\n\
338 ls-list print the names of all logical switches\n\
339 \n\
340 ACL commands:\n\
341 acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
342 add an ACL to SWITCH\n\
343 acl-del SWITCH [DIRECTION [PRIORITY MATCH]]\n\
344 remove ACLs from SWITCH\n\
345 acl-list SWITCH print ACLs for SWITCH\n\
346 \n\
347 Logical switch port commands:\n\
348 lsp-add SWITCH PORT add logical port PORT on SWITCH\n\
349 lsp-add SWITCH PORT PARENT TAG\n\
350 add logical port PORT on SWITCH with PARENT\n\
351 on TAG\n\
352 lsp-del PORT delete PORT from its attached switch\n\
353 lsp-list SWITCH print the names of all logical ports on SWITCH\n\
354 lsp-get-parent PORT get the parent of PORT if set\n\
355 lsp-get-tag PORT get the PORT's tag if set\n\
356 lsp-set-addresses PORT [ADDRESS]...\n\
357 set MAC or MAC+IP addresses for PORT.\n\
358 lsp-get-addresses PORT get a list of MAC or MAC+IP addresses on PORT\n\
359 lsp-set-port-security PORT [ADDRS]...\n\
360 set port security addresses for PORT.\n\
361 lsp-get-port-security PORT get PORT's port security addresses\n\
362 lsp-get-up PORT get state of PORT ('up' or 'down')\n\
363 lsp-set-enabled PORT STATE\n\
364 set administrative state PORT\n\
365 ('enabled' or 'disabled')\n\
366 lsp-get-enabled PORT get administrative state PORT\n\
367 ('enabled' or 'disabled')\n\
368 lsp-set-type PORT TYPE set the type for PORT\n\
369 lsp-get-type PORT get the type for PORT\n\
370 lsp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\
371 set options related to the type of PORT\n\
372 lsp-get-options PORT get the type specific options for PORT\n\
373 lsp-set-dhcpv4-options PORT [DHCP_OPTIONS_UUID]\n\
374 set dhcpv4 options for PORT\n\
375 lsp-get-dhcpv4-options PORT get the dhcpv4 options for PORT\n\
376 \n\
377 Logical router commands:\n\
378 lr-add [ROUTER] create a logical router named ROUTER\n\
379 lr-del ROUTER delete ROUTER and all its ports\n\
380 lr-list print the names of all logical routers\n\
381 \n\
382 Logical router port commands:\n\
383 lrp-add ROUTER PORT MAC NETWORK... [peer=PEER]\n\
384 add logical port PORT on ROUTER\n\
385 lrp-del PORT delete PORT from its attached router\n\
386 lrp-list ROUTER print the names of all ports on ROUTER\n\
387 lrp-set-enabled PORT STATE\n\
388 set administrative state PORT\n\
389 ('enabled' or 'disabled')\n\
390 lrp-get-enabled PORT get administrative state PORT\n\
391 ('enabled' or 'disabled')\n\
392 \n\
393 Route commands:\n\
394 lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
395 add a route to ROUTER\n\
396 lr-route-del ROUTER [PREFIX]\n\
397 remove routes from ROUTER\n\
398 lr-route-list ROUTER print routes for ROUTER\n\
399 \n\
400 \n\
401 DHCP Options commands:\n\
402 dhcp-options-create CIDR [EXTERNAL_IDS]\n\
403 create a DHCP options row with CIDR\n\
404 dhcp-options-del DHCP_OPTIONS_UUID\n\
405 delete DHCP_OPTIONS_UUID\n\
406 dhcp-options-list \n\
407 lists the DHCP_Options rows\n\
408 dhcp-options-set-options DHCP_OPTIONS_UUID KEY=VALUE [KEY=VALUE]...\n\
409 set DHCP options for DHCP_OPTIONS_UUID\n\
410 dhcp-options-get-options DHCO_OPTIONS_UUID \n\
411 displays the DHCP options for DHCP_OPTIONS_UUID\n\
412 \n\
413 %s\
414 \n\
415 Synchronization command (use with --wait=sb|hv):\n\
416 sync wait even for earlier changes to take effect\n\
417 \n\
418 Options:\n\
419 --db=DATABASE connect to DATABASE\n\
420 (default: %s)\n\
421 --no-wait, --wait=none do not wait for OVN reconfiguration (default)\n\
422 --wait=sb wait for southbound database update\n\
423 --wait=hv wait for all chassis to catch up\n\
424 -t, --timeout=SECS wait at most SECS seconds\n\
425 --dry-run do not commit changes to database\n\
426 --oneline print exactly one line of output per command\n",
427 program_name, program_name, ctl_get_db_cmd_usage(), nbctl_default_db());
428 vlog_usage();
429 printf("\
430 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
431 printf("\n\
432 Other options:\n\
433 -h, --help display this help message\n\
434 -V, --version display version information\n");
435 exit(EXIT_SUCCESS);
436 }
437 \f
438
439 /* Find a logical router given its id. */
440 static const struct nbrec_logical_router *
441 lr_by_name_or_uuid(struct ctl_context *ctx, const char *id,
442 bool must_exist)
443 {
444 const struct nbrec_logical_router *lr = NULL;
445 bool is_uuid = false;
446 struct uuid lr_uuid;
447
448 if (uuid_from_string(&lr_uuid, id)) {
449 is_uuid = true;
450 lr = nbrec_logical_router_get_for_uuid(ctx->idl, &lr_uuid);
451 }
452
453 if (!lr) {
454 const struct nbrec_logical_router *iter;
455
456 NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
457 if (strcmp(iter->name, id)) {
458 continue;
459 }
460 if (lr) {
461 ctl_fatal("Multiple logical routers named '%s'. "
462 "Use a UUID.", id);
463 }
464 lr = iter;
465 }
466 }
467
468 if (!lr && must_exist) {
469 ctl_fatal("%s: router %s not found", id, is_uuid ? "UUID" : "name");
470 }
471
472 return lr;
473 }
474
475 static const struct nbrec_logical_switch *
476 ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
477 {
478 const struct nbrec_logical_switch *ls = NULL;
479
480 struct uuid ls_uuid;
481 bool is_uuid = uuid_from_string(&ls_uuid, id);
482 if (is_uuid) {
483 ls = nbrec_logical_switch_get_for_uuid(ctx->idl, &ls_uuid);
484 }
485
486 if (!ls) {
487 const struct nbrec_logical_switch *iter;
488
489 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
490 if (strcmp(iter->name, id)) {
491 continue;
492 }
493 if (ls) {
494 ctl_fatal("Multiple logical switches named '%s'. "
495 "Use a UUID.", id);
496 }
497 ls = iter;
498 }
499 }
500
501 if (!ls && must_exist) {
502 ctl_fatal("%s: switch %s not found", id, is_uuid ? "UUID" : "name");
503 }
504
505 return ls;
506 }
507
508 /* Given pointer to logical router, this routine prints the router
509 * information. */
510 static void
511 print_lr(const struct nbrec_logical_router *lr, struct ds *s)
512 {
513 ds_put_format(s, " router "UUID_FMT" (%s)\n",
514 UUID_ARGS(&lr->header_.uuid), lr->name);
515
516 for (size_t i = 0; i < lr->n_ports; i++) {
517 const struct nbrec_logical_router_port *lrp = lr->ports[i];
518 ds_put_format(s, " port %s\n", lrp->name);
519 if (lrp->mac) {
520 ds_put_cstr(s, " mac: ");
521 ds_put_format(s, "\"%s\"\n", lrp->mac);
522 }
523 if (lrp->n_networks) {
524 ds_put_cstr(s, " networks: [");
525 for (size_t j = 0; j < lrp->n_networks; j++) {
526 ds_put_format(s, "%s\"%s\"",
527 j == 0 ? "" : ", ",
528 lrp->networks[j]);
529 }
530 ds_put_cstr(s, "]\n");
531 }
532 }
533 }
534
535 static void
536 print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
537 {
538 ds_put_format(s, " switch "UUID_FMT" (%s)\n",
539 UUID_ARGS(&ls->header_.uuid), ls->name);
540
541 for (size_t i = 0; i < ls->n_ports; i++) {
542 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
543
544 ds_put_format(s, " port %s\n", lsp->name);
545 if (lsp->parent_name) {
546 ds_put_format(s, " parent: %s\n", lsp->parent_name);
547 }
548 if (lsp->n_tag) {
549 ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
550 }
551 if (lsp->n_addresses) {
552 ds_put_cstr(s, " addresses: [");
553 for (size_t j = 0; j < lsp->n_addresses; j++) {
554 ds_put_format(s, "%s\"%s\"",
555 j == 0 ? "" : ", ",
556 lsp->addresses[j]);
557 }
558 ds_put_cstr(s, "]\n");
559 }
560 }
561 }
562
563 static void
564 nbctl_init(struct ctl_context *ctx OVS_UNUSED)
565 {
566 }
567
568 static void
569 nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED)
570 {
571 if (wait_type != NBCTL_WAIT_NONE) {
572 force_wait = true;
573 } else {
574 VLOG_INFO("\"sync\" command has no effect without --wait");
575 }
576 }
577
578 static void
579 nbctl_sync(struct ctl_context *ctx OVS_UNUSED)
580 {
581 }
582
583 static void
584 nbctl_show(struct ctl_context *ctx)
585 {
586 const struct nbrec_logical_switch *ls;
587
588 if (ctx->argc == 2) {
589 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
590 if (ls) {
591 print_ls(ls, &ctx->output);
592 }
593 } else {
594 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
595 print_ls(ls, &ctx->output);
596 }
597 }
598 const struct nbrec_logical_router *lr;
599
600 if (ctx->argc == 2) {
601 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
602 if (lr) {
603 print_lr(lr, &ctx->output);
604 }
605 } else {
606 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
607 print_lr(lr, &ctx->output);
608 }
609 }
610 }
611
612 static void
613 nbctl_ls_add(struct ctl_context *ctx)
614 {
615 const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
616
617 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
618 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
619 if (may_exist && add_duplicate) {
620 ctl_fatal("--may-exist and --add-duplicate may not be used together");
621 }
622
623 if (ls_name) {
624 if (!add_duplicate) {
625 const struct nbrec_logical_switch *ls;
626 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
627 if (!strcmp(ls->name, ls_name)) {
628 if (may_exist) {
629 return;
630 }
631 ctl_fatal("%s: a switch with this name already exists",
632 ls_name);
633 }
634 }
635 }
636 } else if (may_exist) {
637 ctl_fatal("--may-exist requires specifying a name");
638 } else if (add_duplicate) {
639 ctl_fatal("--add-duplicate requires specifying a name");
640 }
641
642 struct nbrec_logical_switch *ls;
643 ls = nbrec_logical_switch_insert(ctx->txn);
644 if (ls_name) {
645 nbrec_logical_switch_set_name(ls, ls_name);
646 }
647 }
648
649 static void
650 nbctl_ls_del(struct ctl_context *ctx)
651 {
652 bool must_exist = !shash_find(&ctx->options, "--if-exists");
653 const char *id = ctx->argv[1];
654 const struct nbrec_logical_switch *ls;
655
656 ls = ls_by_name_or_uuid(ctx, id, must_exist);
657 if (!ls) {
658 return;
659 }
660
661 nbrec_logical_switch_delete(ls);
662 }
663
664 static void
665 nbctl_ls_list(struct ctl_context *ctx)
666 {
667 const struct nbrec_logical_switch *ls;
668 struct smap lswitches;
669
670 smap_init(&lswitches);
671 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
672 smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
673 UUID_ARGS(&ls->header_.uuid), ls->name);
674 }
675 const struct smap_node **nodes = smap_sort(&lswitches);
676 for (size_t i = 0; i < smap_count(&lswitches); i++) {
677 const struct smap_node *node = nodes[i];
678 ds_put_format(&ctx->output, "%s\n", node->value);
679 }
680 smap_destroy(&lswitches);
681 free(nodes);
682 }
683 \f
684 static const struct nbrec_logical_switch_port *
685 lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
686 bool must_exist)
687 {
688 const struct nbrec_logical_switch_port *lsp = NULL;
689
690 struct uuid lsp_uuid;
691 bool is_uuid = uuid_from_string(&lsp_uuid, id);
692 if (is_uuid) {
693 lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
694 }
695
696 if (!lsp) {
697 NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
698 if (!strcmp(lsp->name, id)) {
699 break;
700 }
701 }
702 }
703
704 if (!lsp && must_exist) {
705 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
706 }
707
708 return lsp;
709 }
710
711 /* Returns the logical switch that contains 'lsp'. */
712 static const struct nbrec_logical_switch *
713 lsp_to_ls(const struct ovsdb_idl *idl,
714 const struct nbrec_logical_switch_port *lsp)
715 {
716 const struct nbrec_logical_switch *ls;
717 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, idl) {
718 for (size_t i = 0; i < ls->n_ports; i++) {
719 if (ls->ports[i] == lsp) {
720 return ls;
721 }
722 }
723 }
724
725 /* Can't happen because of the database schema */
726 ctl_fatal("logical port %s is not part of any logical switch",
727 lsp->name);
728 }
729
730 static const char *
731 ls_get_name(const struct nbrec_logical_switch *ls,
732 char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
733 {
734 if (ls->name[0]) {
735 return ls->name;
736 }
737 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&ls->header_.uuid));
738 return uuid_s;
739 }
740
741 static void
742 nbctl_lsp_add(struct ctl_context *ctx)
743 {
744 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
745
746 const struct nbrec_logical_switch *ls;
747 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
748
749 const char *parent_name;
750 int64_t tag;
751 if (ctx->argc == 3) {
752 parent_name = NULL;
753 tag = -1;
754 } else if (ctx->argc == 5) {
755 /* Validate tag. */
756 parent_name = ctx->argv[3];
757 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag)
758 || tag < 0 || tag > 4095) {
759 ctl_fatal("%s: invalid tag", ctx->argv[4]);
760 }
761 } else {
762 ctl_fatal("lsp-add with parent must also specify a tag");
763 }
764
765 const char *lsp_name = ctx->argv[2];
766 const struct nbrec_logical_switch_port *lsp;
767 lsp = lsp_by_name_or_uuid(ctx, lsp_name, false);
768 if (lsp) {
769 if (!may_exist) {
770 ctl_fatal("%s: a port with this name already exists",
771 lsp_name);
772 }
773
774 const struct nbrec_logical_switch *lsw;
775 lsw = lsp_to_ls(ctx->idl, lsp);
776 if (lsw != ls) {
777 char uuid_s[UUID_LEN + 1];
778 ctl_fatal("%s: port already exists but in switch %s", lsp_name,
779 ls_get_name(lsw, uuid_s, sizeof uuid_s));
780 }
781
782 if (parent_name) {
783 if (!lsp->parent_name) {
784 ctl_fatal("%s: port already exists but has no parent",
785 lsp_name);
786 } else if (strcmp(parent_name, lsp->parent_name)) {
787 ctl_fatal("%s: port already exists with different parent %s",
788 lsp_name, lsp->parent_name);
789 }
790
791 if (!lsp->n_tag) {
792 ctl_fatal("%s: port already exists but has no tag",
793 lsp_name);
794 } else if (lsp->tag[0] != tag) {
795 ctl_fatal("%s: port already exists with different "
796 "tag %"PRId64, lsp_name, lsp->tag[0]);
797 }
798 } else {
799 if (lsp->parent_name) {
800 ctl_fatal("%s: port already exists but has parent %s",
801 lsp_name, lsp->parent_name);
802 }
803 }
804
805 return;
806 }
807
808 /* Create the logical port. */
809 lsp = nbrec_logical_switch_port_insert(ctx->txn);
810 nbrec_logical_switch_port_set_name(lsp, lsp_name);
811 if (tag >= 0) {
812 nbrec_logical_switch_port_set_parent_name(lsp, parent_name);
813 nbrec_logical_switch_port_set_tag(lsp, &tag, 1);
814 }
815
816 /* Insert the logical port into the logical switch. */
817 nbrec_logical_switch_verify_ports(ls);
818 struct nbrec_logical_switch_port **new_ports = xmalloc(sizeof *new_ports *
819 (ls->n_ports + 1));
820 memcpy(new_ports, ls->ports, sizeof *new_ports * ls->n_ports);
821 new_ports[ls->n_ports] = CONST_CAST(struct nbrec_logical_switch_port *,
822 lsp);
823 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports + 1);
824 free(new_ports);
825 }
826
827 /* Removes logical switch port 'ls->ports[idx]'. */
828 static void
829 remove_lsp(const struct nbrec_logical_switch *ls, size_t idx)
830 {
831 const struct nbrec_logical_switch_port *lsp = ls->ports[idx];
832
833 /* First remove 'lsp' from the array of ports. This is what will
834 * actually cause the logical port to be deleted when the transaction is
835 * sent to the database server (due to garbage collection). */
836 struct nbrec_logical_switch_port **new_ports
837 = xmemdup(ls->ports, sizeof *new_ports * ls->n_ports);
838 new_ports[idx] = new_ports[ls->n_ports - 1];
839 nbrec_logical_switch_verify_ports(ls);
840 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports - 1);
841 free(new_ports);
842
843 /* Delete 'lsp' from the IDL. This won't have a real effect on the
844 * database server (the IDL will suppress it in fact) but it means that it
845 * won't show up when we iterate with NBREC_LOGICAL_SWITCH_PORT_FOR_EACH
846 * later. */
847 nbrec_logical_switch_port_delete(lsp);
848 }
849
850 static void
851 nbctl_lsp_del(struct ctl_context *ctx)
852 {
853 bool must_exist = !shash_find(&ctx->options, "--if-exists");
854 const struct nbrec_logical_switch_port *lsp;
855
856 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
857 if (!lsp) {
858 return;
859 }
860
861 /* Find the switch that contains 'lsp', then delete it. */
862 const struct nbrec_logical_switch *ls;
863 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
864 for (size_t i = 0; i < ls->n_ports; i++) {
865 if (ls->ports[i] == lsp) {
866 remove_lsp(ls, i);
867 return;
868 }
869 }
870 }
871
872 /* Can't happen because of the database schema. */
873 ctl_fatal("logical port %s is not part of any logical switch",
874 ctx->argv[1]);
875 }
876
877 static void
878 nbctl_lsp_list(struct ctl_context *ctx)
879 {
880 const char *id = ctx->argv[1];
881 const struct nbrec_logical_switch *ls;
882 struct smap lsps;
883 size_t i;
884
885 ls = ls_by_name_or_uuid(ctx, id, true);
886
887 smap_init(&lsps);
888 for (i = 0; i < ls->n_ports; i++) {
889 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
890 smap_add_format(&lsps, lsp->name, UUID_FMT " (%s)",
891 UUID_ARGS(&lsp->header_.uuid), lsp->name);
892 }
893 const struct smap_node **nodes = smap_sort(&lsps);
894 for (i = 0; i < smap_count(&lsps); i++) {
895 const struct smap_node *node = nodes[i];
896 ds_put_format(&ctx->output, "%s\n", node->value);
897 }
898 smap_destroy(&lsps);
899 free(nodes);
900 }
901
902 static void
903 nbctl_lsp_get_parent(struct ctl_context *ctx)
904 {
905 const struct nbrec_logical_switch_port *lsp;
906
907 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
908 if (lsp->parent_name) {
909 ds_put_format(&ctx->output, "%s\n", lsp->parent_name);
910 }
911 }
912
913 static void
914 nbctl_lsp_get_tag(struct ctl_context *ctx)
915 {
916 const struct nbrec_logical_switch_port *lsp;
917
918 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
919 if (lsp->n_tag > 0) {
920 ds_put_format(&ctx->output, "%"PRId64"\n", lsp->tag[0]);
921 }
922 }
923
924 static void
925 nbctl_lsp_set_addresses(struct ctl_context *ctx)
926 {
927 const char *id = ctx->argv[1];
928 const struct nbrec_logical_switch_port *lsp;
929
930 lsp = lsp_by_name_or_uuid(ctx, id, true);
931
932 int i;
933 for (i = 2; i < ctx->argc; i++) {
934 struct eth_addr ea;
935
936 if (strcmp(ctx->argv[i], "unknown") && strcmp(ctx->argv[i], "dynamic")
937 && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
938 ETH_ADDR_SCAN_ARGS(ea))) {
939 ctl_fatal("%s: Invalid address format. See ovn-nb(5). "
940 "Hint: An Ethernet address must be "
941 "listed before an IP address, together as a single "
942 "argument.", ctx->argv[i]);
943 }
944 }
945
946 nbrec_logical_switch_port_set_addresses(lsp,
947 (const char **) ctx->argv + 2, ctx->argc - 2);
948 }
949
950 static void
951 nbctl_lsp_get_addresses(struct ctl_context *ctx)
952 {
953 const char *id = ctx->argv[1];
954 const struct nbrec_logical_switch_port *lsp;
955 struct svec addresses;
956 const char *mac;
957 size_t i;
958
959 lsp = lsp_by_name_or_uuid(ctx, id, true);
960
961 svec_init(&addresses);
962 for (i = 0; i < lsp->n_addresses; i++) {
963 svec_add(&addresses, lsp->addresses[i]);
964 }
965 svec_sort(&addresses);
966 SVEC_FOR_EACH(i, mac, &addresses) {
967 ds_put_format(&ctx->output, "%s\n", mac);
968 }
969 svec_destroy(&addresses);
970 }
971
972 static void
973 nbctl_lsp_set_port_security(struct ctl_context *ctx)
974 {
975 const char *id = ctx->argv[1];
976 const struct nbrec_logical_switch_port *lsp;
977
978 lsp = lsp_by_name_or_uuid(ctx, id, true);
979 nbrec_logical_switch_port_set_port_security(lsp,
980 (const char **) ctx->argv + 2, ctx->argc - 2);
981 }
982
983 static void
984 nbctl_lsp_get_port_security(struct ctl_context *ctx)
985 {
986 const char *id = ctx->argv[1];
987 const struct nbrec_logical_switch_port *lsp;
988 struct svec addrs;
989 const char *addr;
990 size_t i;
991
992 lsp = lsp_by_name_or_uuid(ctx, id, true);
993 svec_init(&addrs);
994 for (i = 0; i < lsp->n_port_security; i++) {
995 svec_add(&addrs, lsp->port_security[i]);
996 }
997 svec_sort(&addrs);
998 SVEC_FOR_EACH(i, addr, &addrs) {
999 ds_put_format(&ctx->output, "%s\n", addr);
1000 }
1001 svec_destroy(&addrs);
1002 }
1003
1004 static void
1005 nbctl_lsp_get_up(struct ctl_context *ctx)
1006 {
1007 const char *id = ctx->argv[1];
1008 const struct nbrec_logical_switch_port *lsp;
1009
1010 lsp = lsp_by_name_or_uuid(ctx, id, true);
1011 ds_put_format(&ctx->output,
1012 "%s\n", (lsp->up && *lsp->up) ? "up" : "down");
1013 }
1014
1015 static bool
1016 parse_enabled(const char *state)
1017 {
1018 if (!strcasecmp(state, "enabled")) {
1019 return true;
1020 } else if (!strcasecmp(state, "disabled")) {
1021 return false;
1022 } else {
1023 ctl_fatal("%s: state must be \"enabled\" or \"disabled\"", state);
1024 }
1025 }
1026
1027 static void
1028 nbctl_lsp_set_enabled(struct ctl_context *ctx)
1029 {
1030 const char *id = ctx->argv[1];
1031 const char *state = ctx->argv[2];
1032 const struct nbrec_logical_switch_port *lsp;
1033
1034 lsp = lsp_by_name_or_uuid(ctx, id, true);
1035 bool enabled = parse_enabled(state);
1036 nbrec_logical_switch_port_set_enabled(lsp, &enabled, 1);
1037 }
1038
1039 static void
1040 nbctl_lsp_get_enabled(struct ctl_context *ctx)
1041 {
1042 const char *id = ctx->argv[1];
1043 const struct nbrec_logical_switch_port *lsp;
1044
1045 lsp = lsp_by_name_or_uuid(ctx, id, true);
1046 ds_put_format(&ctx->output, "%s\n",
1047 !lsp->enabled || *lsp->enabled ? "enabled" : "disabled");
1048 }
1049
1050 static void
1051 nbctl_lsp_set_type(struct ctl_context *ctx)
1052 {
1053 const char *id = ctx->argv[1];
1054 const char *type = ctx->argv[2];
1055 const struct nbrec_logical_switch_port *lsp;
1056
1057 lsp = lsp_by_name_or_uuid(ctx, id, true);
1058 nbrec_logical_switch_port_set_type(lsp, type);
1059 }
1060
1061 static void
1062 nbctl_lsp_get_type(struct ctl_context *ctx)
1063 {
1064 const char *id = ctx->argv[1];
1065 const struct nbrec_logical_switch_port *lsp;
1066
1067 lsp = lsp_by_name_or_uuid(ctx, id, true);
1068 ds_put_format(&ctx->output, "%s\n", lsp->type);
1069 }
1070
1071 static void
1072 nbctl_lsp_set_options(struct ctl_context *ctx)
1073 {
1074 const char *id = ctx->argv[1];
1075 const struct nbrec_logical_switch_port *lsp;
1076 size_t i;
1077 struct smap options = SMAP_INITIALIZER(&options);
1078
1079 lsp = lsp_by_name_or_uuid(ctx, id, true);
1080 for (i = 2; i < ctx->argc; i++) {
1081 char *key, *value;
1082 value = xstrdup(ctx->argv[i]);
1083 key = strsep(&value, "=");
1084 if (value) {
1085 smap_add(&options, key, value);
1086 }
1087 free(key);
1088 }
1089
1090 nbrec_logical_switch_port_set_options(lsp, &options);
1091
1092 smap_destroy(&options);
1093 }
1094
1095 static void
1096 nbctl_lsp_get_options(struct ctl_context *ctx)
1097 {
1098 const char *id = ctx->argv[1];
1099 const struct nbrec_logical_switch_port *lsp;
1100 struct smap_node *node;
1101
1102 lsp = lsp_by_name_or_uuid(ctx, id, true);
1103 SMAP_FOR_EACH(node, &lsp->options) {
1104 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1105 }
1106 }
1107
1108 static void
1109 nbctl_lsp_set_dhcpv4_options(struct ctl_context *ctx)
1110 {
1111 const char *id = ctx->argv[1];
1112 const struct nbrec_logical_switch_port *lsp;
1113
1114 lsp = lsp_by_name_or_uuid(ctx, id, true);
1115 const struct nbrec_dhcp_options *dhcp_opt = NULL;
1116 if (ctx->argc == 3 ) {
1117 dhcp_opt = dhcp_options_get(ctx, ctx->argv[2], true);
1118 }
1119
1120 if (dhcp_opt) {
1121 ovs_be32 ip;
1122 unsigned int plen;
1123 char *error = ip_parse_cidr(dhcp_opt->cidr, &ip, &plen);
1124 if (error){
1125 free(error);
1126 ctl_fatal("DHCP options cidr '%s' is not IPv4", dhcp_opt->cidr);
1127 return;
1128 }
1129 }
1130 nbrec_logical_switch_port_set_dhcpv4_options(lsp, dhcp_opt);
1131 }
1132
1133 static void
1134 nbctl_lsp_get_dhcpv4_options(struct ctl_context *ctx)
1135 {
1136 const char *id = ctx->argv[1];
1137 const struct nbrec_logical_switch_port *lsp;
1138
1139 lsp = lsp_by_name_or_uuid(ctx, id, true);
1140 if (lsp->dhcpv4_options) {
1141 ds_put_format(&ctx->output, UUID_FMT " (%s)\n",
1142 UUID_ARGS(&lsp->dhcpv4_options->header_.uuid),
1143 lsp->dhcpv4_options->cidr);
1144 }
1145 }
1146
1147 enum {
1148 DIR_FROM_LPORT,
1149 DIR_TO_LPORT
1150 };
1151
1152 static int
1153 dir_encode(const char *dir)
1154 {
1155 if (!strcmp(dir, "from-lport")) {
1156 return DIR_FROM_LPORT;
1157 } else if (!strcmp(dir, "to-lport")) {
1158 return DIR_TO_LPORT;
1159 }
1160
1161 OVS_NOT_REACHED();
1162 }
1163
1164 static int
1165 acl_cmp(const void *acl1_, const void *acl2_)
1166 {
1167 const struct nbrec_acl *const *acl1p = acl1_;
1168 const struct nbrec_acl *const *acl2p = acl2_;
1169 const struct nbrec_acl *acl1 = *acl1p;
1170 const struct nbrec_acl *acl2 = *acl2p;
1171
1172 int dir1 = dir_encode(acl1->direction);
1173 int dir2 = dir_encode(acl2->direction);
1174
1175 if (dir1 != dir2) {
1176 return dir1 < dir2 ? -1 : 1;
1177 } else if (acl1->priority != acl2->priority) {
1178 return acl1->priority > acl2->priority ? -1 : 1;
1179 } else {
1180 return strcmp(acl1->match, acl2->match);
1181 }
1182 }
1183
1184 static void
1185 nbctl_acl_list(struct ctl_context *ctx)
1186 {
1187 const struct nbrec_logical_switch *ls;
1188 const struct nbrec_acl **acls;
1189 size_t i;
1190
1191 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1192
1193 acls = xmalloc(sizeof *acls * ls->n_acls);
1194 for (i = 0; i < ls->n_acls; i++) {
1195 acls[i] = ls->acls[i];
1196 }
1197
1198 qsort(acls, ls->n_acls, sizeof *acls, acl_cmp);
1199
1200 for (i = 0; i < ls->n_acls; i++) {
1201 const struct nbrec_acl *acl = acls[i];
1202 ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s%s\n",
1203 acl->direction, acl->priority,
1204 acl->match, acl->action, acl->log ? " log" : "");
1205 }
1206
1207 free(acls);
1208 }
1209
1210 static const char *
1211 parse_direction(const char *arg)
1212 {
1213 /* Validate direction. Only require the first letter. */
1214 if (arg[0] == 't') {
1215 return "to-lport";
1216 } else if (arg[0] == 'f') {
1217 return "from-lport";
1218 } else {
1219 ctl_fatal("%s: direction must be \"to-lport\" or \"from-lport\"", arg);
1220 }
1221 }
1222
1223 static int
1224 parse_priority(const char *arg)
1225 {
1226 /* Validate priority. */
1227 int64_t priority;
1228 if (!ovs_scan(arg, "%"SCNd64, &priority)
1229 || priority < 0 || priority > 32767) {
1230 ctl_fatal("%s: priority must in range 0...32767", arg);
1231 }
1232 return priority;
1233 }
1234
1235 static void
1236 nbctl_acl_add(struct ctl_context *ctx)
1237 {
1238 const struct nbrec_logical_switch *ls;
1239 const char *action = ctx->argv[5];
1240
1241 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1242
1243 const char *direction = parse_direction(ctx->argv[2]);
1244 int64_t priority = parse_priority(ctx->argv[3]);
1245
1246 /* Validate action. */
1247 if (strcmp(action, "allow") && strcmp(action, "allow-related")
1248 && strcmp(action, "drop") && strcmp(action, "reject")) {
1249 ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
1250 "\"drop\", and \"reject\"", action);
1251 return;
1252 }
1253
1254 /* Create the acl. */
1255 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1256 nbrec_acl_set_priority(acl, priority);
1257 nbrec_acl_set_direction(acl, direction);
1258 nbrec_acl_set_match(acl, ctx->argv[4]);
1259 nbrec_acl_set_action(acl, action);
1260 if (shash_find(&ctx->options, "--log") != NULL) {
1261 nbrec_acl_set_log(acl, true);
1262 }
1263
1264 /* Insert the acl into the logical switch. */
1265 nbrec_logical_switch_verify_acls(ls);
1266 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * (ls->n_acls + 1));
1267 memcpy(new_acls, ls->acls, sizeof *new_acls * ls->n_acls);
1268 new_acls[ls->n_acls] = acl;
1269 nbrec_logical_switch_set_acls(ls, new_acls, ls->n_acls + 1);
1270 free(new_acls);
1271 }
1272
1273 static void
1274 nbctl_acl_del(struct ctl_context *ctx)
1275 {
1276 const struct nbrec_logical_switch *ls;
1277 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1278
1279 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1280 ctl_fatal("cannot specify priority without match");
1281 }
1282
1283 if (ctx->argc == 2) {
1284 /* If direction, priority, and match are not specified, delete
1285 * all ACLs. */
1286 nbrec_logical_switch_verify_acls(ls);
1287 nbrec_logical_switch_set_acls(ls, NULL, 0);
1288 return;
1289 }
1290
1291 const char *direction = parse_direction(ctx->argv[2]);
1292
1293 /* If priority and match are not specified, delete all ACLs with the
1294 * specified direction. */
1295 if (ctx->argc == 3) {
1296 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * ls->n_acls);
1297
1298 int n_acls = 0;
1299 for (size_t i = 0; i < ls->n_acls; i++) {
1300 if (strcmp(direction, ls->acls[i]->direction)) {
1301 new_acls[n_acls++] = ls->acls[i];
1302 }
1303 }
1304
1305 nbrec_logical_switch_verify_acls(ls);
1306 nbrec_logical_switch_set_acls(ls, new_acls, n_acls);
1307 free(new_acls);
1308 return;
1309 }
1310
1311 int64_t priority = parse_priority(ctx->argv[3]);
1312
1313 /* Remove the matching rule. */
1314 for (size_t i = 0; i < ls->n_acls; i++) {
1315 struct nbrec_acl *acl = ls->acls[i];
1316
1317 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1318 !strcmp(direction, acl->direction)) {
1319 struct nbrec_acl **new_acls
1320 = xmemdup(ls->acls, sizeof *new_acls * ls->n_acls);
1321 new_acls[i] = ls->acls[ls->n_acls - 1];
1322 nbrec_logical_switch_verify_acls(ls);
1323 nbrec_logical_switch_set_acls(ls, new_acls,
1324 ls->n_acls - 1);
1325 free(new_acls);
1326 return;
1327 }
1328 }
1329 }
1330 \f
1331 static void
1332 nbctl_lr_add(struct ctl_context *ctx)
1333 {
1334 const char *lr_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
1335
1336 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1337 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1338 if (may_exist && add_duplicate) {
1339 ctl_fatal("--may-exist and --add-duplicate may not be used together");
1340 }
1341
1342 if (lr_name) {
1343 if (!add_duplicate) {
1344 const struct nbrec_logical_router *lr;
1345 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1346 if (!strcmp(lr->name, lr_name)) {
1347 if (may_exist) {
1348 return;
1349 }
1350 ctl_fatal("%s: a router with this name already exists",
1351 lr_name);
1352 }
1353 }
1354 }
1355 } else if (may_exist) {
1356 ctl_fatal("--may-exist requires specifying a name");
1357 } else if (add_duplicate) {
1358 ctl_fatal("--add-duplicate requires specifying a name");
1359 }
1360
1361 struct nbrec_logical_router *lr;
1362 lr = nbrec_logical_router_insert(ctx->txn);
1363 if (lr_name) {
1364 nbrec_logical_router_set_name(lr, lr_name);
1365 }
1366 }
1367
1368 static void
1369 nbctl_lr_del(struct ctl_context *ctx)
1370 {
1371 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1372 const char *id = ctx->argv[1];
1373 const struct nbrec_logical_router *lr;
1374
1375 lr = lr_by_name_or_uuid(ctx, id, must_exist);
1376 if (!lr) {
1377 return;
1378 }
1379
1380 nbrec_logical_router_delete(lr);
1381 }
1382
1383 static void
1384 nbctl_lr_list(struct ctl_context *ctx)
1385 {
1386 const struct nbrec_logical_router *lr;
1387 struct smap lrs;
1388
1389 smap_init(&lrs);
1390 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
1391 smap_add_format(&lrs, lr->name, UUID_FMT " (%s)",
1392 UUID_ARGS(&lr->header_.uuid), lr->name);
1393 }
1394 const struct smap_node **nodes = smap_sort(&lrs);
1395 for (size_t i = 0; i < smap_count(&lrs); i++) {
1396 const struct smap_node *node = nodes[i];
1397 ds_put_format(&ctx->output, "%s\n", node->value);
1398 }
1399 smap_destroy(&lrs);
1400 free(nodes);
1401 }
1402
1403 static const struct nbrec_dhcp_options *
1404 dhcp_options_get(struct ctl_context *ctx, const char *id, bool must_exist)
1405 {
1406 struct uuid dhcp_opts_uuid;
1407 const struct nbrec_dhcp_options *dhcp_opts = NULL;
1408 if (uuid_from_string(&dhcp_opts_uuid, id)) {
1409 dhcp_opts = nbrec_dhcp_options_get_for_uuid(ctx->idl, &dhcp_opts_uuid);
1410 }
1411
1412 if (!dhcp_opts && must_exist) {
1413 ctl_fatal("%s: dhcp options UUID not found", id);
1414 }
1415 return dhcp_opts;
1416 }
1417
1418 static void
1419 nbctl_dhcp_options_create(struct ctl_context *ctx)
1420 {
1421 /* Validate the cidr */
1422 ovs_be32 ip;
1423 unsigned int plen;
1424 char *error = ip_parse_cidr(ctx->argv[1], &ip, &plen);
1425 if (error){
1426 /* check if its IPv6 cidr */
1427 free(error);
1428 struct in6_addr ipv6;
1429 error = ipv6_parse_cidr(ctx->argv[1], &ipv6, &plen);
1430 if (error) {
1431 free(error);
1432 ctl_fatal("Invalid cidr format '%s'", ctx->argv[1]);
1433 return;
1434 }
1435 }
1436
1437 struct nbrec_dhcp_options *dhcp_opts = nbrec_dhcp_options_insert(ctx->txn);
1438 nbrec_dhcp_options_set_cidr(dhcp_opts, ctx->argv[1]);
1439
1440 struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
1441 for (size_t i = 2; i < ctx->argc; i++) {
1442 char *key, *value;
1443 value = xstrdup(ctx->argv[i]);
1444 key = strsep(&value, "=");
1445 if (value) {
1446 smap_add(&ext_ids, key, value);
1447 }
1448 free(key);
1449 }
1450
1451 nbrec_dhcp_options_set_external_ids(dhcp_opts, &ext_ids);
1452 smap_destroy(&ext_ids);
1453 }
1454
1455 static void
1456 nbctl_dhcp_options_set_options(struct ctl_context *ctx)
1457 {
1458 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1459 ctx, ctx->argv[1], true);
1460
1461 struct smap dhcp_options = SMAP_INITIALIZER(&dhcp_options);
1462 for (size_t i = 2; i < ctx->argc; i++) {
1463 char *key, *value;
1464 value = xstrdup(ctx->argv[i]);
1465 key = strsep(&value, "=");
1466 if (value) {
1467 smap_add(&dhcp_options, key, value);
1468 }
1469 free(key);
1470 }
1471
1472 nbrec_dhcp_options_set_options(dhcp_opts, &dhcp_options);
1473 smap_destroy(&dhcp_options);
1474 }
1475
1476 static void
1477 nbctl_dhcp_options_get_options(struct ctl_context *ctx)
1478 {
1479 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1480 ctx, ctx->argv[1], true);
1481
1482 struct smap_node *node;
1483 SMAP_FOR_EACH(node, &dhcp_opts->options) {
1484 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1485 }
1486 }
1487
1488 static void
1489 nbctl_dhcp_options_del(struct ctl_context *ctx)
1490 {
1491 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1492 const char *id = ctx->argv[1];
1493 const struct nbrec_dhcp_options *dhcp_opts;
1494
1495 dhcp_opts = dhcp_options_get(ctx, id, must_exist);
1496 if (!dhcp_opts) {
1497 return;
1498 }
1499
1500 nbrec_dhcp_options_delete(dhcp_opts);
1501 }
1502
1503 static void
1504 nbctl_dhcp_options_list(struct ctl_context *ctx)
1505 {
1506 const struct nbrec_dhcp_options *dhcp_opts;
1507 struct smap dhcp_options;
1508
1509 smap_init(&dhcp_options);
1510 NBREC_DHCP_OPTIONS_FOR_EACH(dhcp_opts, ctx->idl) {
1511 smap_add_format(&dhcp_options, dhcp_opts->cidr, UUID_FMT,
1512 UUID_ARGS(&dhcp_opts->header_.uuid));
1513 }
1514 const struct smap_node **nodes = smap_sort(&dhcp_options);
1515 for (size_t i = 0; i < smap_count(&dhcp_options); i++) {
1516 const struct smap_node *node = nodes[i];
1517 ds_put_format(&ctx->output, "%s\n", node->value);
1518 }
1519 smap_destroy(&dhcp_options);
1520 free(nodes);
1521 }
1522
1523 /* The caller must free the returned string. */
1524 static char *
1525 normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
1526 {
1527 ovs_be32 network = ipv4 & be32_prefix_mask(plen);
1528 if (plen == 32) {
1529 return xasprintf(IP_FMT, IP_ARGS(network));
1530 } else {
1531 return xasprintf(IP_FMT"/%d", IP_ARGS(network), plen);
1532 }
1533 }
1534
1535 /* The caller must free the returned string. */
1536 static char *
1537 normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
1538 {
1539 char network_s[INET6_ADDRSTRLEN];
1540
1541 struct in6_addr mask = ipv6_create_mask(plen);
1542 struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
1543
1544 inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
1545 if (plen == 128) {
1546 return xasprintf("%s", network_s);
1547 } else {
1548 return xasprintf("%s/%d", network_s, plen);
1549 }
1550 }
1551
1552 /* The caller must free the returned string. */
1553 static char *
1554 normalize_prefix_str(const char *orig_prefix)
1555 {
1556 unsigned int plen;
1557 ovs_be32 ipv4;
1558 char *error;
1559
1560 error = ip_parse_cidr(orig_prefix, &ipv4, &plen);
1561 if (!error) {
1562 return normalize_ipv4_prefix(ipv4, plen);
1563 } else {
1564 struct in6_addr ipv6;
1565 free(error);
1566
1567 error = ipv6_parse_cidr(orig_prefix, &ipv6, &plen);
1568 if (error) {
1569 free(error);
1570 return NULL;
1571 }
1572 return normalize_ipv6_prefix(ipv6, plen);
1573 }
1574 }
1575 \f
1576 static void
1577 nbctl_lr_route_add(struct ctl_context *ctx)
1578 {
1579 const struct nbrec_logical_router *lr;
1580 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1581 char *prefix, *next_hop;
1582
1583 prefix = normalize_prefix_str(ctx->argv[2]);
1584 if (!prefix) {
1585 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1586 }
1587
1588 next_hop = normalize_prefix_str(ctx->argv[3]);
1589 if (!next_hop) {
1590 ctl_fatal("bad next hop argument: %s", ctx->argv[3]);
1591 }
1592
1593 if (strchr(prefix, '.')) {
1594 ovs_be32 hop_ipv4;
1595 if (!ip_parse(ctx->argv[3], &hop_ipv4)) {
1596 ctl_fatal("bad IPv4 nexthop argument: %s", ctx->argv[3]);
1597 }
1598 } else {
1599 struct in6_addr hop_ipv6;
1600 if (!ipv6_parse(ctx->argv[3], &hop_ipv6)) {
1601 ctl_fatal("bad IPv6 nexthop argument: %s", ctx->argv[3]);
1602 }
1603 }
1604
1605 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1606 for (int i = 0; i < lr->n_static_routes; i++) {
1607 const struct nbrec_logical_router_static_route *route
1608 = lr->static_routes[i];
1609 char *rt_prefix;
1610
1611 rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1612 if (!rt_prefix) {
1613 /* Ignore existing prefix we couldn't parse. */
1614 continue;
1615 }
1616
1617 if (strcmp(rt_prefix, prefix)) {
1618 free(rt_prefix);
1619 continue;
1620 }
1621
1622 if (!may_exist) {
1623 ctl_fatal("duplicate prefix: %s", prefix);
1624 }
1625
1626 /* Update the next hop for an existing route. */
1627 nbrec_logical_router_verify_static_routes(lr);
1628 nbrec_logical_router_static_route_verify_ip_prefix(route);
1629 nbrec_logical_router_static_route_verify_nexthop(route);
1630 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1631 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1632 if (ctx->argc == 5) {
1633 nbrec_logical_router_static_route_set_output_port(route,
1634 ctx->argv[4]);
1635 }
1636 free(rt_prefix);
1637 free(next_hop);
1638 free(prefix);
1639 return;
1640 }
1641
1642 struct nbrec_logical_router_static_route *route;
1643 route = nbrec_logical_router_static_route_insert(ctx->txn);
1644 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
1645 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
1646 if (ctx->argc == 5) {
1647 nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]);
1648 }
1649
1650 nbrec_logical_router_verify_static_routes(lr);
1651 struct nbrec_logical_router_static_route **new_routes
1652 = xmalloc(sizeof *new_routes * (lr->n_static_routes + 1));
1653 memcpy(new_routes, lr->static_routes,
1654 sizeof *new_routes * lr->n_static_routes);
1655 new_routes[lr->n_static_routes] = route;
1656 nbrec_logical_router_set_static_routes(lr, new_routes,
1657 lr->n_static_routes + 1);
1658 free(new_routes);
1659 free(next_hop);
1660 free(prefix);
1661 }
1662
1663 static void
1664 nbctl_lr_route_del(struct ctl_context *ctx)
1665 {
1666 const struct nbrec_logical_router *lr;
1667 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1668
1669 if (ctx->argc == 2) {
1670 /* If a prefix is not specified, delete all routes. */
1671 nbrec_logical_router_set_static_routes(lr, NULL, 0);
1672 return;
1673 }
1674
1675 char *prefix = normalize_prefix_str(ctx->argv[2]);
1676 if (!prefix) {
1677 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
1678 }
1679
1680 for (int i = 0; i < lr->n_static_routes; i++) {
1681 char *rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
1682 if (!rt_prefix) {
1683 /* Ignore existing prefix we couldn't parse. */
1684 continue;
1685 }
1686
1687 if (!strcmp(prefix, rt_prefix)) {
1688 struct nbrec_logical_router_static_route **new_routes
1689 = xmemdup(lr->static_routes,
1690 sizeof *new_routes * lr->n_static_routes);
1691
1692 new_routes[i] = lr->static_routes[lr->n_static_routes - 1];
1693 nbrec_logical_router_verify_static_routes(lr);
1694 nbrec_logical_router_set_static_routes(lr, new_routes,
1695 lr->n_static_routes - 1);
1696 free(new_routes);
1697 free(rt_prefix);
1698 free(prefix);
1699 return;
1700 }
1701 free(rt_prefix);
1702 }
1703
1704 if (!shash_find(&ctx->options, "--if-exists")) {
1705 ctl_fatal("no matching prefix: %s", prefix);
1706 }
1707 free(prefix);
1708 }
1709 \f
1710 static const struct nbrec_logical_router_port *
1711 lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
1712 {
1713 const struct nbrec_logical_router_port *lrp = NULL;
1714
1715 struct uuid lrp_uuid;
1716 bool is_uuid = uuid_from_string(&lrp_uuid, id);
1717 if (is_uuid) {
1718 lrp = nbrec_logical_router_port_get_for_uuid(ctx->idl, &lrp_uuid);
1719 }
1720
1721 if (!lrp) {
1722 NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrp, ctx->idl) {
1723 if (!strcmp(lrp->name, id)) {
1724 break;
1725 }
1726 }
1727 }
1728
1729 if (!lrp && must_exist) {
1730 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
1731 }
1732
1733 return lrp;
1734 }
1735
1736 /* Returns the logical router that contains 'lrp'. */
1737 static const struct nbrec_logical_router *
1738 lrp_to_lr(const struct ovsdb_idl *idl,
1739 const struct nbrec_logical_router_port *lrp)
1740 {
1741 const struct nbrec_logical_router *lr;
1742 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, idl) {
1743 for (size_t i = 0; i < lr->n_ports; i++) {
1744 if (lr->ports[i] == lrp) {
1745 return lr;
1746 }
1747 }
1748 }
1749
1750 /* Can't happen because of the database schema */
1751 ctl_fatal("port %s is not part of any logical router",
1752 lrp->name);
1753 }
1754
1755 static const char *
1756 lr_get_name(const struct nbrec_logical_router *lr, char uuid_s[UUID_LEN + 1],
1757 size_t uuid_s_size)
1758 {
1759 if (lr->name[0]) {
1760 return lr->name;
1761 }
1762 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lr->header_.uuid));
1763 return uuid_s;
1764 }
1765
1766 static void
1767 nbctl_lrp_add(struct ctl_context *ctx)
1768 {
1769 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1770
1771 const struct nbrec_logical_router *lr;
1772 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1773
1774 const char *lrp_name = ctx->argv[2];
1775 const char *mac = ctx->argv[3];
1776 const char **networks = (const char **) &ctx->argv[4];
1777
1778 int n_networks = ctx->argc - 4;
1779 for (int i = 4; i < ctx->argc; i++) {
1780 if (strchr(ctx->argv[i], '=')) {
1781 n_networks = i - 4;
1782 break;
1783 }
1784 }
1785
1786 if (!n_networks) {
1787 ctl_fatal("%s: router port requires specifying a network", lrp_name);
1788 }
1789
1790 char **settings = (char **) &ctx->argv[n_networks + 4];
1791 int n_settings = ctx->argc - 4 - n_networks;
1792
1793 const struct nbrec_logical_router_port *lrp;
1794 lrp = lrp_by_name_or_uuid(ctx, lrp_name, false);
1795 if (lrp) {
1796 if (!may_exist) {
1797 ctl_fatal("%s: a port with this name already exists",
1798 lrp_name);
1799 }
1800
1801 const struct nbrec_logical_router *bound_lr;
1802 bound_lr = lrp_to_lr(ctx->idl, lrp);
1803 if (bound_lr != lr) {
1804 char uuid_s[UUID_LEN + 1];
1805 ctl_fatal("%s: port already exists but in router %s", lrp_name,
1806 lr_get_name(bound_lr, uuid_s, sizeof uuid_s));
1807 }
1808
1809 if (strcmp(mac, lrp->mac)) {
1810 ctl_fatal("%s: port already exists with mac %s", lrp_name,
1811 lrp->mac);
1812 }
1813
1814 struct sset new_networks = SSET_INITIALIZER(&new_networks);
1815 for (int i = 0; i < n_networks; i++) {
1816 sset_add(&new_networks, networks[i]);
1817 }
1818
1819 struct sset orig_networks = SSET_INITIALIZER(&orig_networks);
1820 sset_add_array(&orig_networks, lrp->networks, lrp->n_networks);
1821
1822 if (!sset_equals(&orig_networks, &new_networks)) {
1823 ctl_fatal("%s: port already exists with different network",
1824 lrp_name);
1825 }
1826
1827 sset_destroy(&orig_networks);
1828 sset_destroy(&new_networks);
1829
1830 /* Special-case sanity-check of peer ports. */
1831 const char *peer = NULL;
1832 for (int i = 0; i < n_settings; i++) {
1833 if (!strncmp(settings[i], "peer=", 5)) {
1834 peer = settings[i] + 5;
1835 break;
1836 }
1837 }
1838
1839 if ((!peer != !lrp->peer) ||
1840 (lrp->peer && strcmp(peer, lrp->peer))) {
1841 ctl_fatal("%s: port already exists with mismatching peer",
1842 lrp_name);
1843 }
1844
1845 return;
1846 }
1847
1848 struct eth_addr ea;
1849 if (!ovs_scan(mac, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) {
1850 ctl_fatal("%s: invalid mac address %s", lrp_name, mac);
1851 }
1852
1853 for (int i = 0; i < n_networks; i++) {
1854 ovs_be32 ipv4;
1855 unsigned int plen;
1856 char *error = ip_parse_cidr(networks[i], &ipv4, &plen);
1857 if (error) {
1858 free(error);
1859 struct in6_addr ipv6;
1860 error = ipv6_parse_cidr(networks[i], &ipv6, &plen);
1861 if (error) {
1862 free(error);
1863 ctl_fatal("%s: invalid network address: %s", lrp_name,
1864 networks[i]);
1865 }
1866 }
1867 }
1868
1869 /* Create the logical port. */
1870 lrp = nbrec_logical_router_port_insert(ctx->txn);
1871 nbrec_logical_router_port_set_name(lrp, lrp_name);
1872 nbrec_logical_router_port_set_mac(lrp, mac);
1873 nbrec_logical_router_port_set_networks(lrp, networks, n_networks);
1874
1875 for (int i = 0; i < n_settings; i++) {
1876 ctl_set_column("Logical_Router_Port", &lrp->header_, settings[i],
1877 ctx->symtab);
1878 }
1879
1880 /* Insert the logical port into the logical router. */
1881 nbrec_logical_router_verify_ports(lr);
1882 struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
1883 (lr->n_ports + 1));
1884 memcpy(new_ports, lr->ports, sizeof *new_ports * lr->n_ports);
1885 new_ports[lr->n_ports] = CONST_CAST(struct nbrec_logical_router_port *,
1886 lrp);
1887 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports + 1);
1888 free(new_ports);
1889 }
1890
1891 /* Removes logical router port 'lr->ports[idx]'. */
1892 static void
1893 remove_lrp(const struct nbrec_logical_router *lr, size_t idx)
1894 {
1895 const struct nbrec_logical_router_port *lrp = lr->ports[idx];
1896
1897 /* First remove 'lrp' from the array of ports. This is what will
1898 * actually cause the logical port to be deleted when the transaction is
1899 * sent to the database server (due to garbage collection). */
1900 struct nbrec_logical_router_port **new_ports
1901 = xmemdup(lr->ports, sizeof *new_ports * lr->n_ports);
1902 new_ports[idx] = new_ports[lr->n_ports - 1];
1903 nbrec_logical_router_verify_ports(lr);
1904 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports - 1);
1905 free(new_ports);
1906
1907 /* Delete 'lrp' from the IDL. This won't have a real effect on
1908 * the database server (the IDL will suppress it in fact) but it
1909 * means that it won't show up when we iterate with
1910 * NBREC_LOGICAL_ROUTER_PORT_FOR_EACH later. */
1911 nbrec_logical_router_port_delete(lrp);
1912 }
1913
1914 static void
1915 nbctl_lrp_del(struct ctl_context *ctx)
1916 {
1917 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1918 const struct nbrec_logical_router_port *lrp;
1919
1920 lrp = lrp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
1921 if (!lrp) {
1922 return;
1923 }
1924
1925 /* Find the router that contains 'lrp', then delete it. */
1926 const struct nbrec_logical_router *lr;
1927 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1928 for (size_t i = 0; i < lr->n_ports; i++) {
1929 if (lr->ports[i] == lrp) {
1930 remove_lrp(lr, i);
1931 return;
1932 }
1933 }
1934 }
1935
1936 /* Can't happen because of the database schema. */
1937 ctl_fatal("logical port %s is not part of any logical router",
1938 ctx->argv[1]);
1939 }
1940
1941 /* Print a list of logical router ports. */
1942 static void
1943 nbctl_lrp_list(struct ctl_context *ctx)
1944 {
1945 const char *id = ctx->argv[1];
1946 const struct nbrec_logical_router *lr;
1947 struct smap lrps;
1948 size_t i;
1949
1950 lr = lr_by_name_or_uuid(ctx, id, true);
1951
1952 smap_init(&lrps);
1953 for (i = 0; i < lr->n_ports; i++) {
1954 const struct nbrec_logical_router_port *lrp = lr->ports[i];
1955 smap_add_format(&lrps, lrp->name, UUID_FMT " (%s)",
1956 UUID_ARGS(&lrp->header_.uuid), lrp->name);
1957 }
1958 const struct smap_node **nodes = smap_sort(&lrps);
1959 for (i = 0; i < smap_count(&lrps); i++) {
1960 const struct smap_node *node = nodes[i];
1961 ds_put_format(&ctx->output, "%s\n", node->value);
1962 }
1963 smap_destroy(&lrps);
1964 free(nodes);
1965 }
1966
1967 /* Set the logical router port admin-enabled state. */
1968 static void
1969 nbctl_lrp_set_enabled(struct ctl_context *ctx)
1970 {
1971 const char *id = ctx->argv[1];
1972 const char *state = ctx->argv[2];
1973 const struct nbrec_logical_router_port *lrp;
1974
1975 lrp = lrp_by_name_or_uuid(ctx, id, true);
1976 if (!lrp) {
1977 return;
1978 }
1979
1980 bool enabled = parse_enabled(state);
1981 nbrec_logical_router_port_set_enabled(lrp, &enabled, 1);
1982 }
1983
1984 /* Print admin-enabled state for logical router port. */
1985 static void
1986 nbctl_lrp_get_enabled(struct ctl_context *ctx)
1987 {
1988 const char *id = ctx->argv[1];
1989 const struct nbrec_logical_router_port *lrp;
1990
1991 lrp = lrp_by_name_or_uuid(ctx, id, true);
1992 if (!lrp) {
1993 return;
1994 }
1995
1996 ds_put_format(&ctx->output, "%s\n",
1997 !lrp->enabled ||
1998 *lrp->enabled ? "enabled" : "disabled");
1999 }
2000 \f
2001 struct ipv4_route {
2002 int plen;
2003 ovs_be32 addr;
2004 const struct nbrec_logical_router_static_route *route;
2005 };
2006
2007 static int
2008 ipv4_route_cmp(const void *route1_, const void *route2_)
2009 {
2010 const struct ipv4_route *route1p = route1_;
2011 const struct ipv4_route *route2p = route2_;
2012
2013 if (route1p->plen != route2p->plen) {
2014 return route1p->plen > route2p->plen ? -1 : 1;
2015 } else if (route1p->addr != route2p->addr) {
2016 return ntohl(route1p->addr) < ntohl(route2p->addr) ? -1 : 1;
2017 } else {
2018 return 0;
2019 }
2020 }
2021
2022 struct ipv6_route {
2023 int plen;
2024 struct in6_addr addr;
2025 const struct nbrec_logical_router_static_route *route;
2026 };
2027
2028 static int
2029 ipv6_route_cmp(const void *route1_, const void *route2_)
2030 {
2031 const struct ipv6_route *route1p = route1_;
2032 const struct ipv6_route *route2p = route2_;
2033
2034 if (route1p->plen != route2p->plen) {
2035 return route1p->plen > route2p->plen ? -1 : 1;
2036 }
2037 return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr));
2038 }
2039
2040 static void
2041 print_route(const struct nbrec_logical_router_static_route *route, struct ds *s)
2042 {
2043
2044 char *prefix = normalize_prefix_str(route->ip_prefix);
2045 char *next_hop = normalize_prefix_str(route->nexthop);
2046 ds_put_format(s, "%25s %25s", prefix, next_hop);
2047 free(prefix);
2048 free(next_hop);
2049
2050 if (route->output_port) {
2051 ds_put_format(s, " %s", route->output_port);
2052 }
2053 ds_put_char(s, '\n');
2054 }
2055
2056 static void
2057 nbctl_lr_route_list(struct ctl_context *ctx)
2058 {
2059 const struct nbrec_logical_router *lr;
2060 struct ipv4_route *ipv4_routes;
2061 struct ipv6_route *ipv6_routes;
2062 size_t n_ipv4_routes = 0;
2063 size_t n_ipv6_routes = 0;
2064
2065 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2066
2067 ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
2068 ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
2069
2070 for (int i = 0; i < lr->n_static_routes; i++) {
2071 const struct nbrec_logical_router_static_route *route
2072 = lr->static_routes[i];
2073 unsigned int plen;
2074 ovs_be32 ipv4;
2075 char *error;
2076
2077 error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen);
2078 if (!error) {
2079 ipv4_routes[n_ipv4_routes].plen = plen;
2080 ipv4_routes[n_ipv4_routes].addr = ipv4;
2081 ipv4_routes[n_ipv4_routes].route = route;
2082 n_ipv4_routes++;
2083 } else {
2084 free(error);
2085
2086 struct in6_addr ipv6;
2087 error = ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen);
2088 if (!error) {
2089 ipv6_routes[n_ipv6_routes].plen = plen;
2090 ipv6_routes[n_ipv6_routes].addr = ipv6;
2091 ipv6_routes[n_ipv6_routes].route = route;
2092 n_ipv6_routes++;
2093 } else {
2094 /* Invalid prefix. */
2095 VLOG_WARN("router "UUID_FMT" (%s) has invalid prefix: %s",
2096 UUID_ARGS(&lr->header_.uuid), lr->name,
2097 route->ip_prefix);
2098 free(error);
2099 continue;
2100 }
2101 }
2102 }
2103
2104 qsort(ipv4_routes, n_ipv4_routes, sizeof *ipv4_routes, ipv4_route_cmp);
2105 qsort(ipv6_routes, n_ipv6_routes, sizeof *ipv6_routes, ipv6_route_cmp);
2106
2107 if (n_ipv4_routes) {
2108 ds_put_cstr(&ctx->output, "IPv4 Routes\n");
2109 }
2110 for (int i = 0; i < n_ipv4_routes; i++) {
2111 print_route(ipv4_routes[i].route, &ctx->output);
2112 }
2113
2114 if (n_ipv6_routes) {
2115 ds_put_format(&ctx->output, "%sIPv6 Routes\n",
2116 n_ipv4_routes ? "\n" : "");
2117 }
2118 for (int i = 0; i < n_ipv6_routes; i++) {
2119 print_route(ipv6_routes[i].route, &ctx->output);
2120 }
2121
2122 free(ipv4_routes);
2123 free(ipv6_routes);
2124 }
2125
2126 static const struct ctl_table_class tables[] = {
2127 {&nbrec_table_nb_global,
2128 {{&nbrec_table_nb_global, NULL, NULL},
2129 {NULL, NULL, NULL}}},
2130
2131 {&nbrec_table_logical_switch,
2132 {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
2133 {NULL, NULL, NULL}}},
2134
2135 {&nbrec_table_logical_switch_port,
2136 {{&nbrec_table_logical_switch_port, &nbrec_logical_switch_port_col_name,
2137 NULL},
2138 {NULL, NULL, NULL}}},
2139
2140 {&nbrec_table_acl,
2141 {{NULL, NULL, NULL},
2142 {NULL, NULL, NULL}}},
2143
2144 {&nbrec_table_load_balancer,
2145 {{NULL, NULL, NULL},
2146 {NULL, NULL, NULL}}},
2147
2148 {&nbrec_table_logical_router,
2149 {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
2150 {NULL, NULL, NULL}}},
2151
2152 {&nbrec_table_logical_router_port,
2153 {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
2154 NULL},
2155 {NULL, NULL, NULL}}},
2156
2157 {&nbrec_table_logical_router_static_route,
2158 {{&nbrec_table_logical_router_static_route, NULL,
2159 NULL},
2160 {NULL, NULL, NULL}}},
2161
2162 {&nbrec_table_nat,
2163 {{&nbrec_table_nat, NULL,
2164 NULL},
2165 {NULL, NULL, NULL}}},
2166
2167 {&nbrec_table_address_set,
2168 {{&nbrec_table_address_set, &nbrec_address_set_col_name, NULL},
2169 {NULL, NULL, NULL}}},
2170
2171 {&nbrec_table_dhcp_options,
2172 {{&nbrec_table_dhcp_options, NULL,
2173 NULL},
2174 {NULL, NULL, NULL}}},
2175
2176 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
2177 };
2178 \f
2179 static void
2180 run_prerequisites(struct ctl_command *commands, size_t n_commands,
2181 struct ovsdb_idl *idl)
2182 {
2183 ovsdb_idl_add_table(idl, &nbrec_table_nb_global);
2184 if (wait_type == NBCTL_WAIT_SB) {
2185 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg);
2186 } else if (wait_type == NBCTL_WAIT_HV) {
2187 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg);
2188 }
2189
2190 for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) {
2191 if (c->syntax->prerequisites) {
2192 struct ctl_context ctx;
2193
2194 ds_init(&c->output);
2195 c->table = NULL;
2196
2197 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
2198 (c->syntax->prerequisites)(&ctx);
2199 ctl_context_done(&ctx, c);
2200
2201 ovs_assert(!c->output.string);
2202 ovs_assert(!c->table);
2203 }
2204 }
2205 }
2206
2207 static bool
2208 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
2209 struct ovsdb_idl *idl)
2210 {
2211 struct ovsdb_idl_txn *txn;
2212 enum ovsdb_idl_txn_status status;
2213 struct ovsdb_symbol_table *symtab;
2214 struct ctl_context ctx;
2215 struct ctl_command *c;
2216 struct shash_node *node;
2217 int64_t next_cfg = 0;
2218 char *error = NULL;
2219
2220 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
2221 if (dry_run) {
2222 ovsdb_idl_txn_set_dry_run(txn);
2223 }
2224
2225 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
2226
2227 const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl);
2228 if (!nb) {
2229 /* XXX add verification that table is empty */
2230 nb = nbrec_nb_global_insert(txn);
2231 }
2232
2233 if (wait_type != NBCTL_WAIT_NONE) {
2234 ovsdb_idl_txn_increment(txn, &nb->header_, &nbrec_nb_global_col_nb_cfg,
2235 force_wait);
2236 }
2237
2238 symtab = ovsdb_symbol_table_create();
2239 for (c = commands; c < &commands[n_commands]; c++) {
2240 ds_init(&c->output);
2241 c->table = NULL;
2242 }
2243 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
2244 for (c = commands; c < &commands[n_commands]; c++) {
2245 ctl_context_init_command(&ctx, c);
2246 if (c->syntax->run) {
2247 (c->syntax->run)(&ctx);
2248 }
2249 ctl_context_done_command(&ctx, c);
2250
2251 if (ctx.try_again) {
2252 ctl_context_done(&ctx, NULL);
2253 goto try_again;
2254 }
2255 }
2256 ctl_context_done(&ctx, NULL);
2257
2258 SHASH_FOR_EACH (node, &symtab->sh) {
2259 struct ovsdb_symbol *symbol = node->data;
2260 if (!symbol->created) {
2261 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
2262 "with \"-- --id=%s create ...\")",
2263 node->name, node->name);
2264 }
2265 if (!symbol->strong_ref) {
2266 if (!symbol->weak_ref) {
2267 VLOG_WARN("row id \"%s\" was created but no reference to it "
2268 "was inserted, so it will not actually appear in "
2269 "the database", node->name);
2270 } else {
2271 VLOG_WARN("row id \"%s\" was created but only a weak "
2272 "reference to it was inserted, so it will not "
2273 "actually appear in the database", node->name);
2274 }
2275 }
2276 }
2277
2278 status = ovsdb_idl_txn_commit_block(txn);
2279 if (wait_type != NBCTL_WAIT_NONE && status == TXN_SUCCESS) {
2280 next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
2281 }
2282 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
2283 for (c = commands; c < &commands[n_commands]; c++) {
2284 if (c->syntax->postprocess) {
2285 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
2286 (c->syntax->postprocess)(&ctx);
2287 ctl_context_done(&ctx, c);
2288 }
2289 }
2290 }
2291 error = xstrdup(ovsdb_idl_txn_get_error(txn));
2292
2293 switch (status) {
2294 case TXN_UNCOMMITTED:
2295 case TXN_INCOMPLETE:
2296 OVS_NOT_REACHED();
2297
2298 case TXN_ABORTED:
2299 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
2300 ctl_fatal("transaction aborted");
2301
2302 case TXN_UNCHANGED:
2303 case TXN_SUCCESS:
2304 break;
2305
2306 case TXN_TRY_AGAIN:
2307 goto try_again;
2308
2309 case TXN_ERROR:
2310 ctl_fatal("transaction error: %s", error);
2311
2312 case TXN_NOT_LOCKED:
2313 /* Should not happen--we never call ovsdb_idl_set_lock(). */
2314 ctl_fatal("database not locked");
2315
2316 default:
2317 OVS_NOT_REACHED();
2318 }
2319 free(error);
2320
2321 ovsdb_symbol_table_destroy(symtab);
2322
2323 for (c = commands; c < &commands[n_commands]; c++) {
2324 struct ds *ds = &c->output;
2325
2326 if (c->table) {
2327 table_print(c->table, &table_style);
2328 } else if (oneline) {
2329 size_t j;
2330
2331 ds_chomp(ds, '\n');
2332 for (j = 0; j < ds->length; j++) {
2333 int ch = ds->string[j];
2334 switch (ch) {
2335 case '\n':
2336 fputs("\\n", stdout);
2337 break;
2338
2339 case '\\':
2340 fputs("\\\\", stdout);
2341 break;
2342
2343 default:
2344 putchar(ch);
2345 }
2346 }
2347 putchar('\n');
2348 } else {
2349 fputs(ds_cstr(ds), stdout);
2350 }
2351 ds_destroy(&c->output);
2352 table_destroy(c->table);
2353 free(c->table);
2354
2355 shash_destroy_free_data(&c->options);
2356 }
2357 free(commands);
2358
2359 if (wait_type != NBCTL_WAIT_NONE && status != TXN_UNCHANGED) {
2360 ovsdb_idl_enable_reconnect(idl);
2361 for (;;) {
2362 ovsdb_idl_run(idl);
2363 NBREC_NB_GLOBAL_FOR_EACH (nb, idl) {
2364 int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB
2365 ? nb->sb_cfg
2366 : nb->hv_cfg);
2367 if (cur_cfg >= next_cfg) {
2368 goto done;
2369 }
2370 }
2371 ovsdb_idl_wait(idl);
2372 poll_block();
2373 }
2374 done: ;
2375 }
2376
2377 ovsdb_idl_txn_destroy(txn);
2378 ovsdb_idl_destroy(idl);
2379
2380 return true;
2381
2382 try_again:
2383 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
2384 * resources and return so that the caller can try again. */
2385 if (txn) {
2386 ovsdb_idl_txn_abort(txn);
2387 ovsdb_idl_txn_destroy(txn);
2388 the_idl_txn = NULL;
2389 }
2390 ovsdb_symbol_table_destroy(symtab);
2391 for (c = commands; c < &commands[n_commands]; c++) {
2392 ds_destroy(&c->output);
2393 table_destroy(c->table);
2394 free(c->table);
2395 }
2396 free(error);
2397 return false;
2398 }
2399
2400 /* Frees the current transaction and the underlying IDL and then calls
2401 * exit(status).
2402 *
2403 * Freeing the transaction and the IDL is not strictly necessary, but it makes
2404 * for a clean memory leak report from valgrind in the normal case. That makes
2405 * it easier to notice real memory leaks. */
2406 static void
2407 nbctl_exit(int status)
2408 {
2409 if (the_idl_txn) {
2410 ovsdb_idl_txn_abort(the_idl_txn);
2411 ovsdb_idl_txn_destroy(the_idl_txn);
2412 }
2413 ovsdb_idl_destroy(the_idl);
2414 exit(status);
2415 }
2416
2417 static const struct ctl_command_syntax nbctl_commands[] = {
2418 { "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW },
2419 { "sync", 0, 0, "", nbctl_pre_sync, nbctl_sync, NULL, "", RO },
2420 { "show", 0, 1, "[SWITCH]", NULL, nbctl_show, NULL, "", RO },
2421
2422 /* logical switch commands. */
2423 { "ls-add", 0, 1, "[SWITCH]", NULL, nbctl_ls_add, NULL,
2424 "--may-exist,--add-duplicate", RW },
2425 { "ls-del", 1, 1, "SWITCH", NULL, nbctl_ls_del, NULL, "--if-exists", RW },
2426 { "ls-list", 0, 0, "", NULL, nbctl_ls_list, NULL, "", RO },
2427
2428 /* acl commands. */
2429 { "acl-add", 5, 5, "SWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
2430 nbctl_acl_add, NULL, "--log", RW },
2431 { "acl-del", 1, 4, "SWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
2432 nbctl_acl_del, NULL, "", RW },
2433 { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_list, NULL, "", RO },
2434
2435 /* logical switch port commands. */
2436 { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add,
2437 NULL, "--may-exist", RW },
2438 { "lsp-del", 1, 1, "PORT", NULL, nbctl_lsp_del, NULL, "--if-exists", RW },
2439 { "lsp-list", 1, 1, "SWITCH", NULL, nbctl_lsp_list, NULL, "", RO },
2440 { "lsp-get-parent", 1, 1, "PORT", NULL, nbctl_lsp_get_parent, NULL,
2441 "", RO },
2442 { "lsp-get-tag", 1, 1, "PORT", NULL, nbctl_lsp_get_tag, NULL, "", RO },
2443 { "lsp-set-addresses", 1, INT_MAX, "PORT [ADDRESS]...", NULL,
2444 nbctl_lsp_set_addresses, NULL, "", RW },
2445 { "lsp-get-addresses", 1, 1, "PORT", NULL, nbctl_lsp_get_addresses, NULL,
2446 "", RO },
2447 { "lsp-set-port-security", 0, INT_MAX, "PORT [ADDRS]...", NULL,
2448 nbctl_lsp_set_port_security, NULL, "", RW },
2449 { "lsp-get-port-security", 1, 1, "PORT", NULL,
2450 nbctl_lsp_get_port_security, NULL, "", RO },
2451 { "lsp-get-up", 1, 1, "PORT", NULL, nbctl_lsp_get_up, NULL, "", RO },
2452 { "lsp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lsp_set_enabled,
2453 NULL, "", RW },
2454 { "lsp-get-enabled", 1, 1, "PORT", NULL, nbctl_lsp_get_enabled, NULL,
2455 "", RO },
2456 { "lsp-set-type", 2, 2, "PORT TYPE", NULL, nbctl_lsp_set_type, NULL,
2457 "", RW },
2458 { "lsp-get-type", 1, 1, "PORT", NULL, nbctl_lsp_get_type, NULL, "", RO },
2459 { "lsp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...", NULL,
2460 nbctl_lsp_set_options, NULL, "", RW },
2461 { "lsp-get-options", 1, 1, "PORT", NULL, nbctl_lsp_get_options, NULL,
2462 "", RO },
2463 { "lsp-set-dhcpv4-options", 1, 2, "PORT [DHCP_OPT_UUID]", NULL,
2464 nbctl_lsp_set_dhcpv4_options, NULL, "", RW },
2465 { "lsp-get-dhcpv4-options", 1, 1, "PORT", NULL,
2466 nbctl_lsp_get_dhcpv4_options, NULL, "", RO },
2467
2468 /* logical router commands. */
2469 { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL,
2470 "--may-exist,--add-duplicate", RW },
2471 { "lr-del", 1, 1, "ROUTER", NULL, nbctl_lr_del, NULL, "--if-exists", RW },
2472 { "lr-list", 0, 0, "", NULL, nbctl_lr_list, NULL, "", RO },
2473
2474 /* logical router port commands. */
2475 { "lrp-add", 4, INT_MAX,
2476 "ROUTER PORT MAC NETWORK... [COLUMN[:KEY]=VALUE]...",
2477 NULL, nbctl_lrp_add, NULL, "--may-exist", RW },
2478 { "lrp-del", 1, 1, "PORT", NULL, nbctl_lrp_del, NULL, "--if-exists", RW },
2479 { "lrp-list", 1, 1, "ROUTER", NULL, nbctl_lrp_list, NULL, "", RO },
2480 { "lrp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lrp_set_enabled,
2481 NULL, "", RW },
2482 { "lrp-get-enabled", 1, 1, "PORT", NULL, nbctl_lrp_get_enabled,
2483 NULL, "", RO },
2484
2485 /* logical router route commands. */
2486 { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL,
2487 nbctl_lr_route_add, NULL, "--may-exist", RW },
2488 { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del,
2489 NULL, "--if-exists", RW },
2490 { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL,
2491 "", RO },
2492
2493 /* DHCP_Options commands */
2494 {"dhcp-options-create", 1, INT_MAX, "CIDR [EXTERNAL:IDS]", NULL,
2495 nbctl_dhcp_options_create, NULL, "", RW },
2496 {"dhcp-options-del", 1, 1, "DHCP_OPT_UUID", NULL,
2497 nbctl_dhcp_options_del, NULL, "", RW},
2498 {"dhcp-options-list", 0, 0, "", NULL, nbctl_dhcp_options_list, NULL, "", RO},
2499 {"dhcp-options-set-options", 1, INT_MAX, "DHCP_OPT_UUID KEY=VALUE [KEY=VALUE]...",
2500 NULL, nbctl_dhcp_options_set_options, NULL, "", RW },
2501 {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL,
2502 nbctl_dhcp_options_get_options, NULL, "", RO },
2503
2504 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
2505 };
2506
2507 /* Registers nbctl and common db commands. */
2508 static void
2509 nbctl_cmd_init(void)
2510 {
2511 ctl_init(tables, NULL, nbctl_exit);
2512 ctl_register_commands(nbctl_commands);
2513 }