]> git.proxmox.com Git - mirror_ovs.git/blob - ovn/utilities/ovn-nbctl.c
ovn-nbctl, ovn-sbctl, ovs-vsctl: Remove gratuitous NULL checks.
[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 "ovn/lib/ovn-util.h"
29 #include "packets.h"
30 #include "poll-loop.h"
31 #include "process.h"
32 #include "smap.h"
33 #include "sset.h"
34 #include "stream.h"
35 #include "stream-ssl.h"
36 #include "svec.h"
37 #include "table.h"
38 #include "timeval.h"
39 #include "util.h"
40 #include "openvswitch/vlog.h"
41
42 VLOG_DEFINE_THIS_MODULE(nbctl);
43
44 /* --db: The database server to contact. */
45 static const char *db;
46
47 /* --oneline: Write each command's output as a single line? */
48 static bool oneline;
49
50 /* --dry-run: Do not commit any changes. */
51 static bool dry_run;
52
53 /* --wait=TYPE: Wait for configuration change to take effect? */
54 enum nbctl_wait_type {
55 NBCTL_WAIT_NONE, /* Do not wait. */
56 NBCTL_WAIT_SB, /* Wait for southbound database updates. */
57 NBCTL_WAIT_HV /* Wait for hypervisors to catch up. */
58 };
59 static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE;
60
61 /* Should we wait (if specified by 'wait_type') even if the commands don't
62 * change the database at all? */
63 static bool force_wait = false;
64
65 /* --timeout: Time to wait for a connection to 'db'. */
66 static int timeout;
67
68 /* Format for table output. */
69 static struct table_style table_style = TABLE_STYLE_DEFAULT;
70
71 /* The IDL we're using and the current transaction, if any.
72 * This is for use by nbctl_exit() only, to allow it to clean up.
73 * Other code should use its context arguments. */
74 static struct ovsdb_idl *the_idl;
75 static struct ovsdb_idl_txn *the_idl_txn;
76 OVS_NO_RETURN static void nbctl_exit(int status);
77
78 static void nbctl_cmd_init(void);
79 OVS_NO_RETURN static void usage(void);
80 static void parse_options(int argc, char *argv[], struct shash *local_options);
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
103 nbctl_cmd_init();
104
105 /* Log our arguments. This is often valuable for debugging systems. */
106 args = process_escape_args(argv);
107 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
108 "Called as %s", args);
109
110 /* Parse command line. */
111 shash_init(&local_options);
112 parse_options(argc, argv, &local_options);
113 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
114 &n_commands);
115
116 if (timeout) {
117 time_alarm(timeout);
118 }
119
120 /* Initialize IDL. */
121 idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
122 run_prerequisites(commands, n_commands, idl);
123
124 /* Execute the commands.
125 *
126 * 'seqno' is the database sequence number for which we last tried to
127 * execute our transaction. There's no point in trying to commit more than
128 * once for any given sequence number, because if the transaction fails
129 * it's because the database changed and we need to obtain an up-to-date
130 * view of the database before we try the transaction again. */
131 seqno = ovsdb_idl_get_seqno(idl);
132 for (;;) {
133 ovsdb_idl_run(idl);
134 if (!ovsdb_idl_is_alive(idl)) {
135 int retval = ovsdb_idl_get_last_error(idl);
136 ctl_fatal("%s: database connection failed (%s)",
137 db, ovs_retval_to_string(retval));
138 }
139
140 if (seqno != ovsdb_idl_get_seqno(idl)) {
141 seqno = ovsdb_idl_get_seqno(idl);
142 if (do_nbctl(args, commands, n_commands, idl)) {
143 free(args);
144 exit(EXIT_SUCCESS);
145 }
146 }
147
148 if (seqno == ovsdb_idl_get_seqno(idl)) {
149 ovsdb_idl_wait(idl);
150 poll_block();
151 }
152 }
153 }
154
155 static void
156 parse_options(int argc, char *argv[], struct shash *local_options)
157 {
158 enum {
159 OPT_DB = UCHAR_MAX + 1,
160 OPT_NO_SYSLOG,
161 OPT_NO_WAIT,
162 OPT_WAIT,
163 OPT_DRY_RUN,
164 OPT_ONELINE,
165 OPT_LOCAL,
166 OPT_COMMANDS,
167 OPT_OPTIONS,
168 OPT_BOOTSTRAP_CA_CERT,
169 VLOG_OPTION_ENUMS,
170 TABLE_OPTION_ENUMS,
171 SSL_OPTION_ENUMS,
172 };
173 static const struct option global_long_options[] = {
174 {"db", required_argument, NULL, OPT_DB},
175 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
176 {"no-wait", no_argument, NULL, OPT_NO_WAIT},
177 {"wait", required_argument, NULL, OPT_WAIT},
178 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
179 {"oneline", no_argument, NULL, OPT_ONELINE},
180 {"timeout", required_argument, NULL, 't'},
181 {"help", no_argument, NULL, 'h'},
182 {"commands", no_argument, NULL, OPT_COMMANDS},
183 {"options", no_argument, NULL, OPT_OPTIONS},
184 {"version", no_argument, NULL, 'V'},
185 VLOG_LONG_OPTIONS,
186 STREAM_SSL_LONG_OPTIONS,
187 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
188 TABLE_LONG_OPTIONS,
189 {NULL, 0, NULL, 0},
190 };
191 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
192 char *tmp, *short_options;
193
194 struct option *options;
195 size_t allocated_options;
196 size_t n_options;
197 size_t i;
198
199 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
200 short_options = xasprintf("+%s", tmp);
201 free(tmp);
202
203 /* We want to parse both global and command-specific options here, but
204 * getopt_long() isn't too convenient for the job. We copy our global
205 * options into a dynamic array, then append all of the command-specific
206 * options. */
207 options = xmemdup(global_long_options, sizeof global_long_options);
208 allocated_options = ARRAY_SIZE(global_long_options);
209 n_options = n_global_long_options;
210 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
211
212 for (;;) {
213 int idx;
214 int c;
215
216 c = getopt_long(argc, argv, short_options, options, &idx);
217 if (c == -1) {
218 break;
219 }
220
221 switch (c) {
222 case OPT_DB:
223 db = optarg;
224 break;
225
226 case OPT_ONELINE:
227 oneline = true;
228 break;
229
230 case OPT_NO_SYSLOG:
231 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
232 break;
233
234 case OPT_NO_WAIT:
235 wait_type = NBCTL_WAIT_NONE;
236 break;
237
238 case OPT_WAIT:
239 if (!strcmp(optarg, "none")) {
240 wait_type = NBCTL_WAIT_NONE;
241 } else if (!strcmp(optarg, "sb")) {
242 wait_type = NBCTL_WAIT_SB;
243 } else if (!strcmp(optarg, "hv")) {
244 wait_type = NBCTL_WAIT_HV;
245 } else {
246 ctl_fatal("argument to --wait must be "
247 "\"none\", \"sb\", or \"hv\"");
248 }
249 break;
250
251 case OPT_DRY_RUN:
252 dry_run = true;
253 break;
254
255 case OPT_LOCAL:
256 if (shash_find(local_options, options[idx].name)) {
257 ctl_fatal("'%s' option specified multiple times",
258 options[idx].name);
259 }
260 shash_add_nocopy(local_options,
261 xasprintf("--%s", options[idx].name),
262 nullable_xstrdup(optarg));
263 break;
264
265 case 'h':
266 usage();
267 exit(EXIT_SUCCESS);
268
269 case OPT_COMMANDS:
270 ctl_print_commands();
271
272 case OPT_OPTIONS:
273 ctl_print_options(global_long_options);
274
275 case 'V':
276 ovs_print_version(0, 0);
277 printf("DB Schema %s\n", nbrec_get_db_version());
278 exit(EXIT_SUCCESS);
279
280 case 't':
281 timeout = strtoul(optarg, NULL, 10);
282 if (timeout < 0) {
283 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
284 }
285 break;
286
287 VLOG_OPTION_HANDLERS
288 TABLE_OPTION_HANDLERS(&table_style)
289 STREAM_SSL_OPTION_HANDLERS
290
291 case OPT_BOOTSTRAP_CA_CERT:
292 stream_ssl_set_ca_cert_file(optarg, true);
293 break;
294
295 case '?':
296 exit(EXIT_FAILURE);
297
298 default:
299 abort();
300 }
301 }
302 free(short_options);
303
304 if (!db) {
305 db = default_nb_db();
306 }
307
308 for (i = n_global_long_options; options[i].name; i++) {
309 free(CONST_CAST(char *, options[i].name));
310 }
311 free(options);
312 }
313
314 static void
315 usage(void)
316 {
317 printf("\
318 %s: OVN northbound DB management utility\n\
319 usage: %s [OPTIONS] COMMAND [ARG...]\n\
320 \n\
321 General commands:\n\
322 init initialize the database\n\
323 show print overview of database contents\n\
324 show SWITCH print overview of database contents for SWITCH\n\
325 show ROUTER print overview of database contents for ROUTER\n\
326 \n\
327 Logical switch commands:\n\
328 ls-add [SWITCH] create a logical switch named SWITCH\n\
329 ls-del SWITCH delete SWITCH and all its ports\n\
330 ls-list print the names of all logical switches\n\
331 \n\
332 ACL commands:\n\
333 acl-add SWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
334 add an ACL to SWITCH\n\
335 acl-del SWITCH [DIRECTION [PRIORITY MATCH]]\n\
336 remove ACLs from SWITCH\n\
337 acl-list SWITCH print ACLs for SWITCH\n\
338 \n\
339 Logical switch port commands:\n\
340 lsp-add SWITCH PORT add logical port PORT on SWITCH\n\
341 lsp-add SWITCH PORT PARENT TAG\n\
342 add logical port PORT on SWITCH with PARENT\n\
343 on TAG\n\
344 lsp-del PORT delete PORT from its attached switch\n\
345 lsp-list SWITCH print the names of all logical ports on SWITCH\n\
346 lsp-get-parent PORT get the parent of PORT if set\n\
347 lsp-get-tag PORT get the PORT's tag if set\n\
348 lsp-set-addresses PORT [ADDRESS]...\n\
349 set MAC or MAC+IP addresses for PORT.\n\
350 lsp-get-addresses PORT get a list of MAC or MAC+IP addresses on PORT\n\
351 lsp-set-port-security PORT [ADDRS]...\n\
352 set port security addresses for PORT.\n\
353 lsp-get-port-security PORT get PORT's port security addresses\n\
354 lsp-get-up PORT get state of PORT ('up' or 'down')\n\
355 lsp-set-enabled PORT STATE\n\
356 set administrative state PORT\n\
357 ('enabled' or 'disabled')\n\
358 lsp-get-enabled PORT get administrative state PORT\n\
359 ('enabled' or 'disabled')\n\
360 lsp-set-type PORT TYPE set the type for PORT\n\
361 lsp-get-type PORT get the type for PORT\n\
362 lsp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\
363 set options related to the type of PORT\n\
364 lsp-get-options PORT get the type specific options for PORT\n\
365 lsp-set-dhcpv4-options PORT [DHCP_OPTIONS_UUID]\n\
366 set dhcpv4 options for PORT\n\
367 lsp-get-dhcpv4-options PORT get the dhcpv4 options for PORT\n\
368 \n\
369 Logical router commands:\n\
370 lr-add [ROUTER] create a logical router named ROUTER\n\
371 lr-del ROUTER delete ROUTER and all its ports\n\
372 lr-list print the names of all logical routers\n\
373 \n\
374 Logical router port commands:\n\
375 lrp-add ROUTER PORT MAC NETWORK... [peer=PEER]\n\
376 add logical port PORT on ROUTER\n\
377 lrp-del PORT delete PORT from its attached router\n\
378 lrp-list ROUTER print the names of all ports on ROUTER\n\
379 lrp-set-enabled PORT STATE\n\
380 set administrative state PORT\n\
381 ('enabled' or 'disabled')\n\
382 lrp-get-enabled PORT get administrative state PORT\n\
383 ('enabled' or 'disabled')\n\
384 \n\
385 Route commands:\n\
386 [--policy=POLICY] lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\
387 add a route to ROUTER\n\
388 lr-route-del ROUTER [PREFIX]\n\
389 remove routes from ROUTER\n\
390 lr-route-list ROUTER print routes for ROUTER\n\
391 \n\
392 NAT commands:\n\
393 lr-nat-add ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]\n\
394 add a NAT to ROUTER\n\
395 lr-nat-del ROUTER [TYPE [IP]]\n\
396 remove NATs from ROUTER\n\
397 lr-nat-list ROUTER print NATs for ROUTER\n\
398 \n\
399 LB commands:\n\
400 lb-add LB VIP[:PORT] IP[:PORT]... [PROTOCOL]\n\
401 create a load-balancer or add a VIP to an\n\
402 existing load balancer\n\
403 lb-del LB [VIP] remove a load-balancer or just the VIP from\n\
404 the load balancer\n\
405 lb-list [LB] print load-balancers\n\
406 lr-lb-add ROUTER LB add a load-balancer to ROUTER\n\
407 lr-lb-del ROUTER [LB] remove load-balancers from ROUTER\n\
408 lr-lb-list ROUTER print load-balancers\n\
409 ls-lb-add SWITCH LB add a load-balancer to SWITCH\n\
410 ls-lb-del SWITCH [LB] remove load-balancers from SWITCH\n\
411 ls-lb-list SWITCH print load-balancers\n\
412 \n\
413 DHCP Options commands:\n\
414 dhcp-options-create CIDR [EXTERNAL_IDS]\n\
415 create a DHCP options row with CIDR\n\
416 dhcp-options-del DHCP_OPTIONS_UUID\n\
417 delete DHCP_OPTIONS_UUID\n\
418 dhcp-options-list \n\
419 lists the DHCP_Options rows\n\
420 dhcp-options-set-options DHCP_OPTIONS_UUID KEY=VALUE [KEY=VALUE]...\n\
421 set DHCP options for DHCP_OPTIONS_UUID\n\
422 dhcp-options-get-options DHCO_OPTIONS_UUID \n\
423 displays the DHCP options for DHCP_OPTIONS_UUID\n\
424 \n\
425 Connection commands:\n\
426 get-connection print the connections\n\
427 del-connection delete the connections\n\
428 set-connection TARGET... set the list of connections to TARGET...\n\
429 \n\
430 SSL commands:\n\
431 get-ssl print the SSL configuration\n\
432 del-ssl delete the SSL configuration\n\
433 set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\n\
434 \n\
435 %s\
436 \n\
437 Synchronization command (use with --wait=sb|hv):\n\
438 sync wait even for earlier changes to take effect\n\
439 \n\
440 Options:\n\
441 --db=DATABASE connect to DATABASE\n\
442 (default: %s)\n\
443 --no-wait, --wait=none do not wait for OVN reconfiguration (default)\n\
444 --wait=sb wait for southbound database update\n\
445 --wait=hv wait for all chassis to catch up\n\
446 -t, --timeout=SECS wait at most SECS seconds\n\
447 --dry-run do not commit changes to database\n\
448 --oneline print exactly one line of output per command\n",
449 program_name, program_name, ctl_get_db_cmd_usage(),
450 default_nb_db());
451 table_usage();
452 vlog_usage();
453 printf("\
454 --no-syslog equivalent to --verbose=nbctl:syslog:warn\n");
455 printf("\n\
456 Other options:\n\
457 -h, --help display this help message\n\
458 -V, --version display version information\n");
459 stream_usage("database", true, true, false);
460 exit(EXIT_SUCCESS);
461 }
462 \f
463
464 /* Find a logical router given its id. */
465 static const struct nbrec_logical_router *
466 lr_by_name_or_uuid(struct ctl_context *ctx, const char *id,
467 bool must_exist)
468 {
469 const struct nbrec_logical_router *lr = NULL;
470 bool is_uuid = false;
471 struct uuid lr_uuid;
472
473 if (uuid_from_string(&lr_uuid, id)) {
474 is_uuid = true;
475 lr = nbrec_logical_router_get_for_uuid(ctx->idl, &lr_uuid);
476 }
477
478 if (!lr) {
479 const struct nbrec_logical_router *iter;
480
481 NBREC_LOGICAL_ROUTER_FOR_EACH(iter, ctx->idl) {
482 if (strcmp(iter->name, id)) {
483 continue;
484 }
485 if (lr) {
486 ctl_fatal("Multiple logical routers named '%s'. "
487 "Use a UUID.", id);
488 }
489 lr = iter;
490 }
491 }
492
493 if (!lr && must_exist) {
494 ctl_fatal("%s: router %s not found", id, is_uuid ? "UUID" : "name");
495 }
496
497 return lr;
498 }
499
500 static const struct nbrec_logical_switch *
501 ls_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
502 {
503 const struct nbrec_logical_switch *ls = NULL;
504
505 struct uuid ls_uuid;
506 bool is_uuid = uuid_from_string(&ls_uuid, id);
507 if (is_uuid) {
508 ls = nbrec_logical_switch_get_for_uuid(ctx->idl, &ls_uuid);
509 }
510
511 if (!ls) {
512 const struct nbrec_logical_switch *iter;
513
514 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
515 if (strcmp(iter->name, id)) {
516 continue;
517 }
518 if (ls) {
519 ctl_fatal("Multiple logical switches named '%s'. "
520 "Use a UUID.", id);
521 }
522 ls = iter;
523 }
524 }
525
526 if (!ls && must_exist) {
527 ctl_fatal("%s: switch %s not found", id, is_uuid ? "UUID" : "name");
528 }
529
530 return ls;
531 }
532
533 static const struct nbrec_load_balancer *
534 lb_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
535 {
536 const struct nbrec_load_balancer *lb = NULL;
537
538 struct uuid lb_uuid;
539 bool is_uuid = uuid_from_string(&lb_uuid, id);
540 if (is_uuid) {
541 lb = nbrec_load_balancer_get_for_uuid(ctx->idl, &lb_uuid);
542 }
543
544 if (!lb) {
545 const struct nbrec_load_balancer *iter;
546
547 NBREC_LOAD_BALANCER_FOR_EACH(iter, ctx->idl) {
548 if (strcmp(iter->name, id)) {
549 continue;
550 }
551 if (lb) {
552 ctl_fatal("Multiple load balancers named '%s'. "
553 "Use a UUID.", id);
554 }
555 lb = iter;
556 }
557 }
558
559 if (!lb && must_exist) {
560 ctl_fatal("%s: load balancer %s not found", id,
561 is_uuid ? "UUID" : "name");
562 }
563
564 return lb;
565 }
566
567 static void
568 print_alias(const struct smap *external_ids, const char *key, struct ds *s)
569 {
570 const char *alias = smap_get(external_ids, key);
571 if (alias && alias[0]) {
572 ds_put_format(s, " (aka %s)", alias);
573 }
574 }
575
576 /* Given pointer to logical router, this routine prints the router
577 * information. */
578 static void
579 print_lr(const struct nbrec_logical_router *lr, struct ds *s)
580 {
581 ds_put_format(s, "router "UUID_FMT" (%s)",
582 UUID_ARGS(&lr->header_.uuid), lr->name);
583 print_alias(&lr->external_ids, "neutron:router_name", s);
584 ds_put_char(s, '\n');
585
586 for (size_t i = 0; i < lr->n_ports; i++) {
587 const struct nbrec_logical_router_port *lrp = lr->ports[i];
588 ds_put_format(s, " port %s\n", lrp->name);
589 if (lrp->mac) {
590 ds_put_cstr(s, " mac: ");
591 ds_put_format(s, "\"%s\"\n", lrp->mac);
592 }
593 if (lrp->n_networks) {
594 ds_put_cstr(s, " networks: [");
595 for (size_t j = 0; j < lrp->n_networks; j++) {
596 ds_put_format(s, "%s\"%s\"",
597 j == 0 ? "" : ", ",
598 lrp->networks[j]);
599 }
600 ds_put_cstr(s, "]\n");
601 }
602 }
603
604 for (size_t i = 0; i < lr->n_nat; i++) {
605 const struct nbrec_nat *nat = lr->nat[i];
606 ds_put_format(s, " nat "UUID_FMT"\n",
607 UUID_ARGS(&nat->header_.uuid));
608 ds_put_cstr(s, " external ip: ");
609 ds_put_format(s, "\"%s\"\n", nat->external_ip);
610 ds_put_cstr(s, " logical ip: ");
611 ds_put_format(s, "\"%s\"\n", nat->logical_ip);
612 ds_put_cstr(s, " type: ");
613 ds_put_format(s, "\"%s\"\n", nat->type);
614 }
615 }
616
617 static void
618 print_ls(const struct nbrec_logical_switch *ls, struct ds *s)
619 {
620 ds_put_format(s, "switch "UUID_FMT" (%s)",
621 UUID_ARGS(&ls->header_.uuid), ls->name);
622 print_alias(&ls->external_ids, "neutron:network_name", s);
623 ds_put_char(s, '\n');
624
625 for (size_t i = 0; i < ls->n_ports; i++) {
626 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
627
628 ds_put_format(s, " port %s", lsp->name);
629 print_alias(&lsp->external_ids, "neutron:port_name", s);
630 ds_put_char(s, '\n');
631
632 if (lsp->type[0]) {
633 ds_put_format(s, " type: %s\n", lsp->type);
634 }
635 if (lsp->parent_name) {
636 ds_put_format(s, " parent: %s\n", lsp->parent_name);
637 }
638 if (lsp->n_tag) {
639 ds_put_format(s, " tag: %"PRIu64"\n", lsp->tag[0]);
640 }
641
642 /* Print the addresses, but not if there's just a single "router"
643 * address because that's just clutter. */
644 if (lsp->n_addresses
645 && !(lsp->n_addresses == 1
646 && !strcmp(lsp->addresses[0], "router"))) {
647 ds_put_cstr(s, " addresses: [");
648 for (size_t j = 0; j < lsp->n_addresses; j++) {
649 ds_put_format(s, "%s\"%s\"",
650 j == 0 ? "" : ", ",
651 lsp->addresses[j]);
652 }
653 ds_put_cstr(s, "]\n");
654 }
655
656 const char *router_port = smap_get(&lsp->options, "router-port");
657 if (router_port) {
658 ds_put_format(s, " router-port: %s\n", router_port);
659 }
660 }
661 }
662
663 static void
664 nbctl_init(struct ctl_context *ctx OVS_UNUSED)
665 {
666 }
667
668 static void
669 nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED)
670 {
671 if (wait_type != NBCTL_WAIT_NONE) {
672 force_wait = true;
673 } else {
674 VLOG_INFO("\"sync\" command has no effect without --wait");
675 }
676 }
677
678 static void
679 nbctl_sync(struct ctl_context *ctx OVS_UNUSED)
680 {
681 }
682
683 static void
684 nbctl_show(struct ctl_context *ctx)
685 {
686 const struct nbrec_logical_switch *ls;
687
688 if (ctx->argc == 2) {
689 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], false);
690 if (ls) {
691 print_ls(ls, &ctx->output);
692 }
693 } else {
694 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
695 print_ls(ls, &ctx->output);
696 }
697 }
698 const struct nbrec_logical_router *lr;
699
700 if (ctx->argc == 2) {
701 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], false);
702 if (lr) {
703 print_lr(lr, &ctx->output);
704 }
705 } else {
706 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
707 print_lr(lr, &ctx->output);
708 }
709 }
710 }
711
712 static void
713 nbctl_ls_add(struct ctl_context *ctx)
714 {
715 const char *ls_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
716
717 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
718 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
719 if (may_exist && add_duplicate) {
720 ctl_fatal("--may-exist and --add-duplicate may not be used together");
721 }
722
723 if (ls_name) {
724 if (!add_duplicate) {
725 const struct nbrec_logical_switch *ls;
726 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
727 if (!strcmp(ls->name, ls_name)) {
728 if (may_exist) {
729 return;
730 }
731 ctl_fatal("%s: a switch with this name already exists",
732 ls_name);
733 }
734 }
735 }
736 } else if (may_exist) {
737 ctl_fatal("--may-exist requires specifying a name");
738 } else if (add_duplicate) {
739 ctl_fatal("--add-duplicate requires specifying a name");
740 }
741
742 struct nbrec_logical_switch *ls;
743 ls = nbrec_logical_switch_insert(ctx->txn);
744 if (ls_name) {
745 nbrec_logical_switch_set_name(ls, ls_name);
746 }
747 }
748
749 static void
750 nbctl_ls_del(struct ctl_context *ctx)
751 {
752 bool must_exist = !shash_find(&ctx->options, "--if-exists");
753 const char *id = ctx->argv[1];
754 const struct nbrec_logical_switch *ls;
755
756 ls = ls_by_name_or_uuid(ctx, id, must_exist);
757 if (!ls) {
758 return;
759 }
760
761 nbrec_logical_switch_delete(ls);
762 }
763
764 static void
765 nbctl_ls_list(struct ctl_context *ctx)
766 {
767 const struct nbrec_logical_switch *ls;
768 struct smap lswitches;
769
770 smap_init(&lswitches);
771 NBREC_LOGICAL_SWITCH_FOR_EACH(ls, ctx->idl) {
772 smap_add_format(&lswitches, ls->name, UUID_FMT " (%s)",
773 UUID_ARGS(&ls->header_.uuid), ls->name);
774 }
775 const struct smap_node **nodes = smap_sort(&lswitches);
776 for (size_t i = 0; i < smap_count(&lswitches); i++) {
777 const struct smap_node *node = nodes[i];
778 ds_put_format(&ctx->output, "%s\n", node->value);
779 }
780 smap_destroy(&lswitches);
781 free(nodes);
782 }
783 \f
784 static const struct nbrec_logical_switch_port *
785 lsp_by_name_or_uuid(struct ctl_context *ctx, const char *id,
786 bool must_exist)
787 {
788 const struct nbrec_logical_switch_port *lsp = NULL;
789
790 struct uuid lsp_uuid;
791 bool is_uuid = uuid_from_string(&lsp_uuid, id);
792 if (is_uuid) {
793 lsp = nbrec_logical_switch_port_get_for_uuid(ctx->idl, &lsp_uuid);
794 }
795
796 if (!lsp) {
797 NBREC_LOGICAL_SWITCH_PORT_FOR_EACH(lsp, ctx->idl) {
798 if (!strcmp(lsp->name, id)) {
799 break;
800 }
801 }
802 }
803
804 if (!lsp && must_exist) {
805 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
806 }
807
808 return lsp;
809 }
810
811 /* Returns the logical switch that contains 'lsp'. */
812 static const struct nbrec_logical_switch *
813 lsp_to_ls(const struct ovsdb_idl *idl,
814 const struct nbrec_logical_switch_port *lsp)
815 {
816 const struct nbrec_logical_switch *ls;
817 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, idl) {
818 for (size_t i = 0; i < ls->n_ports; i++) {
819 if (ls->ports[i] == lsp) {
820 return ls;
821 }
822 }
823 }
824
825 /* Can't happen because of the database schema */
826 ctl_fatal("logical port %s is not part of any logical switch",
827 lsp->name);
828 }
829
830 static const char *
831 ls_get_name(const struct nbrec_logical_switch *ls,
832 char uuid_s[UUID_LEN + 1], size_t uuid_s_size)
833 {
834 if (ls->name[0]) {
835 return ls->name;
836 }
837 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&ls->header_.uuid));
838 return uuid_s;
839 }
840
841 static void
842 nbctl_lsp_add(struct ctl_context *ctx)
843 {
844 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
845
846 const struct nbrec_logical_switch *ls;
847 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
848
849 const char *parent_name;
850 int64_t tag;
851 if (ctx->argc == 3) {
852 parent_name = NULL;
853 tag = -1;
854 } else if (ctx->argc == 5) {
855 /* Validate tag. */
856 parent_name = ctx->argv[3];
857 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag)
858 || tag < 0 || tag > 4095) {
859 ctl_fatal("%s: invalid tag (must be in range 0 to 4095)",
860 ctx->argv[4]);
861 }
862 } else {
863 ctl_fatal("lsp-add with parent must also specify a tag");
864 }
865
866 const char *lsp_name = ctx->argv[2];
867 const struct nbrec_logical_switch_port *lsp;
868 lsp = lsp_by_name_or_uuid(ctx, lsp_name, false);
869 if (lsp) {
870 if (!may_exist) {
871 ctl_fatal("%s: a port with this name already exists",
872 lsp_name);
873 }
874
875 const struct nbrec_logical_switch *lsw;
876 lsw = lsp_to_ls(ctx->idl, lsp);
877 if (lsw != ls) {
878 char uuid_s[UUID_LEN + 1];
879 ctl_fatal("%s: port already exists but in switch %s", lsp_name,
880 ls_get_name(lsw, uuid_s, sizeof uuid_s));
881 }
882
883 if (parent_name) {
884 if (!lsp->parent_name) {
885 ctl_fatal("%s: port already exists but has no parent",
886 lsp_name);
887 } else if (strcmp(parent_name, lsp->parent_name)) {
888 ctl_fatal("%s: port already exists with different parent %s",
889 lsp_name, lsp->parent_name);
890 }
891
892 if (!lsp->n_tag_request) {
893 ctl_fatal("%s: port already exists but has no tag_request",
894 lsp_name);
895 } else if (lsp->tag_request[0] != tag) {
896 ctl_fatal("%s: port already exists with different "
897 "tag_request %"PRId64, lsp_name,
898 lsp->tag_request[0]);
899 }
900 } else {
901 if (lsp->parent_name) {
902 ctl_fatal("%s: port already exists but has parent %s",
903 lsp_name, lsp->parent_name);
904 }
905 }
906
907 return;
908 }
909
910 /* Create the logical port. */
911 lsp = nbrec_logical_switch_port_insert(ctx->txn);
912 nbrec_logical_switch_port_set_name(lsp, lsp_name);
913 if (tag >= 0) {
914 nbrec_logical_switch_port_set_parent_name(lsp, parent_name);
915 nbrec_logical_switch_port_set_tag_request(lsp, &tag, 1);
916 }
917
918 /* Insert the logical port into the logical switch. */
919 nbrec_logical_switch_verify_ports(ls);
920 struct nbrec_logical_switch_port **new_ports = xmalloc(sizeof *new_ports *
921 (ls->n_ports + 1));
922 memcpy(new_ports, ls->ports, sizeof *new_ports * ls->n_ports);
923 new_ports[ls->n_ports] = CONST_CAST(struct nbrec_logical_switch_port *,
924 lsp);
925 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports + 1);
926 free(new_ports);
927 }
928
929 /* Removes logical switch port 'ls->ports[idx]'. */
930 static void
931 remove_lsp(const struct nbrec_logical_switch *ls, size_t idx)
932 {
933 const struct nbrec_logical_switch_port *lsp = ls->ports[idx];
934
935 /* First remove 'lsp' from the array of ports. This is what will
936 * actually cause the logical port to be deleted when the transaction is
937 * sent to the database server (due to garbage collection). */
938 struct nbrec_logical_switch_port **new_ports
939 = xmemdup(ls->ports, sizeof *new_ports * ls->n_ports);
940 new_ports[idx] = new_ports[ls->n_ports - 1];
941 nbrec_logical_switch_verify_ports(ls);
942 nbrec_logical_switch_set_ports(ls, new_ports, ls->n_ports - 1);
943 free(new_ports);
944
945 /* Delete 'lsp' from the IDL. This won't have a real effect on the
946 * database server (the IDL will suppress it in fact) but it means that it
947 * won't show up when we iterate with NBREC_LOGICAL_SWITCH_PORT_FOR_EACH
948 * later. */
949 nbrec_logical_switch_port_delete(lsp);
950 }
951
952 static void
953 nbctl_lsp_del(struct ctl_context *ctx)
954 {
955 bool must_exist = !shash_find(&ctx->options, "--if-exists");
956 const struct nbrec_logical_switch_port *lsp;
957
958 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
959 if (!lsp) {
960 return;
961 }
962
963 /* Find the switch that contains 'lsp', then delete it. */
964 const struct nbrec_logical_switch *ls;
965 NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->idl) {
966 for (size_t i = 0; i < ls->n_ports; i++) {
967 if (ls->ports[i] == lsp) {
968 remove_lsp(ls, i);
969 return;
970 }
971 }
972 }
973
974 /* Can't happen because of the database schema. */
975 ctl_fatal("logical port %s is not part of any logical switch",
976 ctx->argv[1]);
977 }
978
979 static void
980 nbctl_lsp_list(struct ctl_context *ctx)
981 {
982 const char *id = ctx->argv[1];
983 const struct nbrec_logical_switch *ls;
984 struct smap lsps;
985 size_t i;
986
987 ls = ls_by_name_or_uuid(ctx, id, true);
988
989 smap_init(&lsps);
990 for (i = 0; i < ls->n_ports; i++) {
991 const struct nbrec_logical_switch_port *lsp = ls->ports[i];
992 smap_add_format(&lsps, lsp->name, UUID_FMT " (%s)",
993 UUID_ARGS(&lsp->header_.uuid), lsp->name);
994 }
995 const struct smap_node **nodes = smap_sort(&lsps);
996 for (i = 0; i < smap_count(&lsps); i++) {
997 const struct smap_node *node = nodes[i];
998 ds_put_format(&ctx->output, "%s\n", node->value);
999 }
1000 smap_destroy(&lsps);
1001 free(nodes);
1002 }
1003
1004 static void
1005 nbctl_lsp_get_parent(struct ctl_context *ctx)
1006 {
1007 const struct nbrec_logical_switch_port *lsp;
1008
1009 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
1010 if (lsp->parent_name) {
1011 ds_put_format(&ctx->output, "%s\n", lsp->parent_name);
1012 }
1013 }
1014
1015 static void
1016 nbctl_lsp_get_tag(struct ctl_context *ctx)
1017 {
1018 const struct nbrec_logical_switch_port *lsp;
1019
1020 lsp = lsp_by_name_or_uuid(ctx, ctx->argv[1], true);
1021 if (lsp->n_tag > 0) {
1022 ds_put_format(&ctx->output, "%"PRId64"\n", lsp->tag[0]);
1023 }
1024 }
1025
1026 static void
1027 nbctl_lsp_set_addresses(struct ctl_context *ctx)
1028 {
1029 const char *id = ctx->argv[1];
1030 const struct nbrec_logical_switch_port *lsp;
1031
1032 lsp = lsp_by_name_or_uuid(ctx, id, true);
1033
1034 int i;
1035 for (i = 2; i < ctx->argc; i++) {
1036 struct eth_addr ea;
1037
1038 if (strcmp(ctx->argv[i], "unknown") && strcmp(ctx->argv[i], "dynamic")
1039 && strcmp(ctx->argv[i], "router")
1040 && !ovs_scan(ctx->argv[i], ETH_ADDR_SCAN_FMT,
1041 ETH_ADDR_SCAN_ARGS(ea))) {
1042 ctl_fatal("%s: Invalid address format. See ovn-nb(5). "
1043 "Hint: An Ethernet address must be "
1044 "listed before an IP address, together as a single "
1045 "argument.", ctx->argv[i]);
1046 }
1047 }
1048
1049 nbrec_logical_switch_port_set_addresses(lsp,
1050 (const char **) ctx->argv + 2, ctx->argc - 2);
1051 }
1052
1053 static void
1054 nbctl_lsp_get_addresses(struct ctl_context *ctx)
1055 {
1056 const char *id = ctx->argv[1];
1057 const struct nbrec_logical_switch_port *lsp;
1058 struct svec addresses;
1059 const char *mac;
1060 size_t i;
1061
1062 lsp = lsp_by_name_or_uuid(ctx, id, true);
1063
1064 svec_init(&addresses);
1065 for (i = 0; i < lsp->n_addresses; i++) {
1066 svec_add(&addresses, lsp->addresses[i]);
1067 }
1068 svec_sort(&addresses);
1069 SVEC_FOR_EACH(i, mac, &addresses) {
1070 ds_put_format(&ctx->output, "%s\n", mac);
1071 }
1072 svec_destroy(&addresses);
1073 }
1074
1075 static void
1076 nbctl_lsp_set_port_security(struct ctl_context *ctx)
1077 {
1078 const char *id = ctx->argv[1];
1079 const struct nbrec_logical_switch_port *lsp;
1080
1081 lsp = lsp_by_name_or_uuid(ctx, id, true);
1082 nbrec_logical_switch_port_set_port_security(lsp,
1083 (const char **) ctx->argv + 2, ctx->argc - 2);
1084 }
1085
1086 static void
1087 nbctl_lsp_get_port_security(struct ctl_context *ctx)
1088 {
1089 const char *id = ctx->argv[1];
1090 const struct nbrec_logical_switch_port *lsp;
1091 struct svec addrs;
1092 const char *addr;
1093 size_t i;
1094
1095 lsp = lsp_by_name_or_uuid(ctx, id, true);
1096 svec_init(&addrs);
1097 for (i = 0; i < lsp->n_port_security; i++) {
1098 svec_add(&addrs, lsp->port_security[i]);
1099 }
1100 svec_sort(&addrs);
1101 SVEC_FOR_EACH(i, addr, &addrs) {
1102 ds_put_format(&ctx->output, "%s\n", addr);
1103 }
1104 svec_destroy(&addrs);
1105 }
1106
1107 static void
1108 nbctl_lsp_get_up(struct ctl_context *ctx)
1109 {
1110 const char *id = ctx->argv[1];
1111 const struct nbrec_logical_switch_port *lsp;
1112
1113 lsp = lsp_by_name_or_uuid(ctx, id, true);
1114 ds_put_format(&ctx->output,
1115 "%s\n", (lsp->up && *lsp->up) ? "up" : "down");
1116 }
1117
1118 static bool
1119 parse_enabled(const char *state)
1120 {
1121 if (!strcasecmp(state, "enabled")) {
1122 return true;
1123 } else if (!strcasecmp(state, "disabled")) {
1124 return false;
1125 } else {
1126 ctl_fatal("%s: state must be \"enabled\" or \"disabled\"", state);
1127 }
1128 }
1129
1130 static void
1131 nbctl_lsp_set_enabled(struct ctl_context *ctx)
1132 {
1133 const char *id = ctx->argv[1];
1134 const char *state = ctx->argv[2];
1135 const struct nbrec_logical_switch_port *lsp;
1136
1137 lsp = lsp_by_name_or_uuid(ctx, id, true);
1138 bool enabled = parse_enabled(state);
1139 nbrec_logical_switch_port_set_enabled(lsp, &enabled, 1);
1140 }
1141
1142 static void
1143 nbctl_lsp_get_enabled(struct ctl_context *ctx)
1144 {
1145 const char *id = ctx->argv[1];
1146 const struct nbrec_logical_switch_port *lsp;
1147
1148 lsp = lsp_by_name_or_uuid(ctx, id, true);
1149 ds_put_format(&ctx->output, "%s\n",
1150 !lsp->enabled || *lsp->enabled ? "enabled" : "disabled");
1151 }
1152
1153 static void
1154 nbctl_lsp_set_type(struct ctl_context *ctx)
1155 {
1156 const char *id = ctx->argv[1];
1157 const char *type = ctx->argv[2];
1158 const struct nbrec_logical_switch_port *lsp;
1159
1160 lsp = lsp_by_name_or_uuid(ctx, id, true);
1161 nbrec_logical_switch_port_set_type(lsp, type);
1162 }
1163
1164 static void
1165 nbctl_lsp_get_type(struct ctl_context *ctx)
1166 {
1167 const char *id = ctx->argv[1];
1168 const struct nbrec_logical_switch_port *lsp;
1169
1170 lsp = lsp_by_name_or_uuid(ctx, id, true);
1171 ds_put_format(&ctx->output, "%s\n", lsp->type);
1172 }
1173
1174 static void
1175 nbctl_lsp_set_options(struct ctl_context *ctx)
1176 {
1177 const char *id = ctx->argv[1];
1178 const struct nbrec_logical_switch_port *lsp;
1179 size_t i;
1180 struct smap options = SMAP_INITIALIZER(&options);
1181
1182 lsp = lsp_by_name_or_uuid(ctx, id, true);
1183 for (i = 2; i < ctx->argc; i++) {
1184 char *key, *value;
1185 value = xstrdup(ctx->argv[i]);
1186 key = strsep(&value, "=");
1187 if (value) {
1188 smap_add(&options, key, value);
1189 }
1190 free(key);
1191 }
1192
1193 nbrec_logical_switch_port_set_options(lsp, &options);
1194
1195 smap_destroy(&options);
1196 }
1197
1198 static void
1199 nbctl_lsp_get_options(struct ctl_context *ctx)
1200 {
1201 const char *id = ctx->argv[1];
1202 const struct nbrec_logical_switch_port *lsp;
1203 struct smap_node *node;
1204
1205 lsp = lsp_by_name_or_uuid(ctx, id, true);
1206 SMAP_FOR_EACH(node, &lsp->options) {
1207 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
1208 }
1209 }
1210
1211 static void
1212 nbctl_lsp_set_dhcpv4_options(struct ctl_context *ctx)
1213 {
1214 const char *id = ctx->argv[1];
1215 const struct nbrec_logical_switch_port *lsp;
1216
1217 lsp = lsp_by_name_or_uuid(ctx, id, true);
1218 const struct nbrec_dhcp_options *dhcp_opt = NULL;
1219 if (ctx->argc == 3 ) {
1220 dhcp_opt = dhcp_options_get(ctx, ctx->argv[2], true);
1221 }
1222
1223 if (dhcp_opt) {
1224 ovs_be32 ip;
1225 unsigned int plen;
1226 char *error = ip_parse_cidr(dhcp_opt->cidr, &ip, &plen);
1227 if (error){
1228 free(error);
1229 ctl_fatal("DHCP options cidr '%s' is not IPv4", dhcp_opt->cidr);
1230 }
1231 }
1232 nbrec_logical_switch_port_set_dhcpv4_options(lsp, dhcp_opt);
1233 }
1234
1235 static void
1236 nbctl_lsp_get_dhcpv4_options(struct ctl_context *ctx)
1237 {
1238 const char *id = ctx->argv[1];
1239 const struct nbrec_logical_switch_port *lsp;
1240
1241 lsp = lsp_by_name_or_uuid(ctx, id, true);
1242 if (lsp->dhcpv4_options) {
1243 ds_put_format(&ctx->output, UUID_FMT " (%s)\n",
1244 UUID_ARGS(&lsp->dhcpv4_options->header_.uuid),
1245 lsp->dhcpv4_options->cidr);
1246 }
1247 }
1248
1249 enum {
1250 DIR_FROM_LPORT,
1251 DIR_TO_LPORT
1252 };
1253
1254 static int
1255 dir_encode(const char *dir)
1256 {
1257 if (!strcmp(dir, "from-lport")) {
1258 return DIR_FROM_LPORT;
1259 } else if (!strcmp(dir, "to-lport")) {
1260 return DIR_TO_LPORT;
1261 }
1262
1263 OVS_NOT_REACHED();
1264 }
1265
1266 static int
1267 acl_cmp(const void *acl1_, const void *acl2_)
1268 {
1269 const struct nbrec_acl *const *acl1p = acl1_;
1270 const struct nbrec_acl *const *acl2p = acl2_;
1271 const struct nbrec_acl *acl1 = *acl1p;
1272 const struct nbrec_acl *acl2 = *acl2p;
1273
1274 int dir1 = dir_encode(acl1->direction);
1275 int dir2 = dir_encode(acl2->direction);
1276
1277 if (dir1 != dir2) {
1278 return dir1 < dir2 ? -1 : 1;
1279 } else if (acl1->priority != acl2->priority) {
1280 return acl1->priority > acl2->priority ? -1 : 1;
1281 } else {
1282 return strcmp(acl1->match, acl2->match);
1283 }
1284 }
1285
1286 static void
1287 nbctl_acl_list(struct ctl_context *ctx)
1288 {
1289 const struct nbrec_logical_switch *ls;
1290 const struct nbrec_acl **acls;
1291 size_t i;
1292
1293 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1294
1295 acls = xmalloc(sizeof *acls * ls->n_acls);
1296 for (i = 0; i < ls->n_acls; i++) {
1297 acls[i] = ls->acls[i];
1298 }
1299
1300 qsort(acls, ls->n_acls, sizeof *acls, acl_cmp);
1301
1302 for (i = 0; i < ls->n_acls; i++) {
1303 const struct nbrec_acl *acl = acls[i];
1304 ds_put_format(&ctx->output, "%10s %5"PRId64" (%s) %s%s\n",
1305 acl->direction, acl->priority,
1306 acl->match, acl->action, acl->log ? " log" : "");
1307 }
1308
1309 free(acls);
1310 }
1311
1312 static const char *
1313 parse_direction(const char *arg)
1314 {
1315 /* Validate direction. Only require the first letter. */
1316 if (arg[0] == 't') {
1317 return "to-lport";
1318 } else if (arg[0] == 'f') {
1319 return "from-lport";
1320 } else {
1321 ctl_fatal("%s: direction must be \"to-lport\" or \"from-lport\"", arg);
1322 }
1323 }
1324
1325 static int
1326 parse_priority(const char *arg)
1327 {
1328 /* Validate priority. */
1329 int64_t priority;
1330 if (!ovs_scan(arg, "%"SCNd64, &priority)
1331 || priority < 0 || priority > 32767) {
1332 ctl_fatal("%s: priority must in range 0...32767", arg);
1333 }
1334 return priority;
1335 }
1336
1337 static void
1338 nbctl_acl_add(struct ctl_context *ctx)
1339 {
1340 const struct nbrec_logical_switch *ls;
1341 const char *action = ctx->argv[5];
1342
1343 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1344
1345 const char *direction = parse_direction(ctx->argv[2]);
1346 int64_t priority = parse_priority(ctx->argv[3]);
1347
1348 /* Validate action. */
1349 if (strcmp(action, "allow") && strcmp(action, "allow-related")
1350 && strcmp(action, "drop") && strcmp(action, "reject")) {
1351 ctl_fatal("%s: action must be one of \"allow\", \"allow-related\", "
1352 "\"drop\", and \"reject\"", action);
1353 return;
1354 }
1355
1356 /* Create the acl. */
1357 struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
1358 nbrec_acl_set_priority(acl, priority);
1359 nbrec_acl_set_direction(acl, direction);
1360 nbrec_acl_set_match(acl, ctx->argv[4]);
1361 nbrec_acl_set_action(acl, action);
1362 if (shash_find(&ctx->options, "--log") != NULL) {
1363 nbrec_acl_set_log(acl, true);
1364 }
1365
1366 /* Check if same acl already exists for the ls */
1367 for (size_t i = 0; i < ls->n_acls; i++) {
1368 if (!acl_cmp(&ls->acls[i], &acl)) {
1369 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1370 if (!may_exist) {
1371 ctl_fatal("Same ACL already existed on the ls %s.",
1372 ctx->argv[1]);
1373 }
1374 return;
1375 }
1376 }
1377
1378 /* Insert the acl into the logical switch. */
1379 nbrec_logical_switch_verify_acls(ls);
1380 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * (ls->n_acls + 1));
1381 memcpy(new_acls, ls->acls, sizeof *new_acls * ls->n_acls);
1382 new_acls[ls->n_acls] = acl;
1383 nbrec_logical_switch_set_acls(ls, new_acls, ls->n_acls + 1);
1384 free(new_acls);
1385 }
1386
1387 static void
1388 nbctl_acl_del(struct ctl_context *ctx)
1389 {
1390 const struct nbrec_logical_switch *ls;
1391 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1392
1393 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
1394 ctl_fatal("cannot specify priority without match");
1395 }
1396
1397 if (ctx->argc == 2) {
1398 /* If direction, priority, and match are not specified, delete
1399 * all ACLs. */
1400 nbrec_logical_switch_verify_acls(ls);
1401 nbrec_logical_switch_set_acls(ls, NULL, 0);
1402 return;
1403 }
1404
1405 const char *direction = parse_direction(ctx->argv[2]);
1406
1407 /* If priority and match are not specified, delete all ACLs with the
1408 * specified direction. */
1409 if (ctx->argc == 3) {
1410 struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls * ls->n_acls);
1411
1412 int n_acls = 0;
1413 for (size_t i = 0; i < ls->n_acls; i++) {
1414 if (strcmp(direction, ls->acls[i]->direction)) {
1415 new_acls[n_acls++] = ls->acls[i];
1416 }
1417 }
1418
1419 nbrec_logical_switch_verify_acls(ls);
1420 nbrec_logical_switch_set_acls(ls, new_acls, n_acls);
1421 free(new_acls);
1422 return;
1423 }
1424
1425 int64_t priority = parse_priority(ctx->argv[3]);
1426
1427 /* Remove the matching rule. */
1428 for (size_t i = 0; i < ls->n_acls; i++) {
1429 struct nbrec_acl *acl = ls->acls[i];
1430
1431 if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1432 !strcmp(direction, acl->direction)) {
1433 struct nbrec_acl **new_acls
1434 = xmemdup(ls->acls, sizeof *new_acls * ls->n_acls);
1435 new_acls[i] = ls->acls[ls->n_acls - 1];
1436 nbrec_logical_switch_verify_acls(ls);
1437 nbrec_logical_switch_set_acls(ls, new_acls,
1438 ls->n_acls - 1);
1439 free(new_acls);
1440 return;
1441 }
1442 }
1443 }
1444
1445 static void
1446 nbctl_lb_add(struct ctl_context *ctx)
1447 {
1448 const char *lb_name = ctx->argv[1];
1449 const char *lb_vip = ctx->argv[2];
1450 char *lb_ips = ctx->argv[3];
1451
1452 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1453 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1454
1455 const char *lb_proto;
1456 bool is_update_proto = false;
1457 bool is_vip_with_port = true;
1458
1459 if (ctx->argc == 4) {
1460 /* Default protocol. */
1461 lb_proto = "tcp";
1462 } else {
1463 /* Validate protocol. */
1464 lb_proto = ctx->argv[4];
1465 is_update_proto = true;
1466 if (strcmp(lb_proto, "tcp") && strcmp(lb_proto, "udp")) {
1467 ctl_fatal("%s: protocol must be one of \"tcp\", \"udp\".",
1468 lb_proto);
1469 }
1470 }
1471
1472 ovs_be32 ipv4 = 0;
1473 ovs_be16 port = 0;
1474 char *error = ip_parse_port(lb_vip, &ipv4, &port);
1475 if (error) {
1476 free(error);
1477 if (!ip_parse(lb_vip, &ipv4)) {
1478 ctl_fatal("%s: should be an IPv4 address (or an IPv4 address "
1479 "and a port number with : as a separator).", lb_vip);
1480 }
1481
1482 if (is_update_proto) {
1483 ctl_fatal("Protocol is unnecessary when no port of vip "
1484 "is given.");
1485 }
1486 is_vip_with_port = false;
1487 }
1488
1489 char *token = NULL, *save_ptr = NULL;
1490 struct ds lb_ips_new = DS_EMPTY_INITIALIZER;
1491 for (token = strtok_r(lb_ips, ",", &save_ptr);
1492 token != NULL; token = strtok_r(NULL, ",", &save_ptr)) {
1493 if (is_vip_with_port) {
1494 error = ip_parse_port(token, &ipv4, &port);
1495 if (error) {
1496 free(error);
1497 ds_destroy(&lb_ips_new);
1498 ctl_fatal("%s: should be an IPv4 address and a port "
1499 "number with : as a separator.", token);
1500 }
1501 } else {
1502 if (!ip_parse(token, &ipv4)) {
1503 ds_destroy(&lb_ips_new);
1504 ctl_fatal("%s: should be an IPv4 address.", token);
1505 }
1506 }
1507 ds_put_format(&lb_ips_new, "%s%s",
1508 lb_ips_new.length ? "," : "", token);
1509 }
1510
1511 const struct nbrec_load_balancer *lb = NULL;
1512 if (!add_duplicate) {
1513 lb = lb_by_name_or_uuid(ctx, lb_name, false);
1514 if (lb) {
1515 if (smap_get(&lb->vips, lb_vip)) {
1516 if (!may_exist) {
1517 ds_destroy(&lb_ips_new);
1518 ctl_fatal("%s: a load balancer with this vip (%s) "
1519 "already exists", lb_name, lb_vip);
1520 }
1521 /* Update the vips. */
1522 smap_replace(CONST_CAST(struct smap *, &lb->vips),
1523 lb_vip, ds_cstr(&lb_ips_new));
1524 } else {
1525 /* Add the new vips. */
1526 smap_add(CONST_CAST(struct smap *, &lb->vips),
1527 lb_vip, ds_cstr(&lb_ips_new));
1528 }
1529
1530 /* Update the load balancer. */
1531 if (is_update_proto) {
1532 nbrec_load_balancer_verify_protocol(lb);
1533 nbrec_load_balancer_set_protocol(lb, lb_proto);
1534 }
1535 nbrec_load_balancer_verify_vips(lb);
1536 nbrec_load_balancer_set_vips(lb, &lb->vips);
1537 ds_destroy(&lb_ips_new);
1538 return;
1539 }
1540 }
1541
1542 /* Create the load balancer. */
1543 lb = nbrec_load_balancer_insert(ctx->txn);
1544 nbrec_load_balancer_set_name(lb, lb_name);
1545 nbrec_load_balancer_set_protocol(lb, lb_proto);
1546 smap_add(CONST_CAST(struct smap *, &lb->vips),
1547 lb_vip, ds_cstr(&lb_ips_new));
1548 nbrec_load_balancer_set_vips(lb, &lb->vips);
1549 ds_destroy(&lb_ips_new);
1550 }
1551
1552 static void
1553 nbctl_lb_del(struct ctl_context *ctx)
1554 {
1555 const char *id = ctx->argv[1];
1556 const struct nbrec_load_balancer *lb = NULL;
1557 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1558
1559 lb = lb_by_name_or_uuid(ctx, id, false);
1560 if (!lb) {
1561 return;
1562 }
1563
1564 if (ctx->argc == 3) {
1565 const char *lb_vip = ctx->argv[2];
1566 if (smap_get(&lb->vips, lb_vip)) {
1567 smap_remove(CONST_CAST(struct smap *, &lb->vips), lb_vip);
1568 if (smap_is_empty(&lb->vips)) {
1569 nbrec_load_balancer_delete(lb);
1570 return;
1571 }
1572
1573 /* Delete the vip of the load balancer. */
1574 nbrec_load_balancer_verify_vips(lb);
1575 nbrec_load_balancer_set_vips(lb, &lb->vips);
1576 return;
1577 }
1578 if (must_exist) {
1579 ctl_fatal("vip %s is not part of the load balancer.",
1580 lb_vip);
1581 }
1582 return;
1583 }
1584 nbrec_load_balancer_delete(lb);
1585 }
1586
1587 static void
1588 lb_info_add_smap(const struct nbrec_load_balancer *lb,
1589 struct smap *lbs)
1590 {
1591 struct ds key = DS_EMPTY_INITIALIZER;
1592 struct ds val = DS_EMPTY_INITIALIZER;
1593 char *error, *protocol;
1594 ovs_be32 ipv4 = 0;
1595 ovs_be16 port = 0;
1596
1597 const struct smap_node **nodes = smap_sort(&lb->vips);
1598 if (nodes) {
1599 for (int i = 0; i < smap_count(&lb->vips); i++) {
1600 const struct smap_node *node = nodes[i];
1601 protocol = lb->protocol;
1602 error = ip_parse_port(node->key, &ipv4, &port);
1603 if (error) {
1604 free(error);
1605 protocol = "tcp/udp";
1606 }
1607
1608 i == 0 ? ds_put_format(&val,
1609 UUID_FMT " %-20.16s%-11.7s%-25.21s%s",
1610 UUID_ARGS(&lb->header_.uuid),
1611 lb->name, protocol,
1612 node->key, node->value)
1613 : ds_put_format(&val, "\n%60s%-11.7s%-25.21s%s",
1614 "", protocol,
1615 node->key, node->value);
1616 }
1617
1618 ds_put_format(&key, "%-20.16s", lb->name);
1619 smap_add(lbs, ds_cstr(&key), ds_cstr(&val));
1620
1621 ds_destroy(&key);
1622 ds_destroy(&val);
1623 free(nodes);
1624 }
1625 }
1626
1627 static void
1628 lb_info_print(struct ctl_context *ctx, struct smap *lbs)
1629 {
1630 const struct smap_node **nodes = smap_sort(lbs);
1631 if (nodes) {
1632 ds_put_format(&ctx->output, "%-40.36s%-20.16s%-11.7s%-25.21s%s\n",
1633 "UUID", "LB", "PROTO", "VIP", "IPs");
1634 for (size_t i = 0; i < smap_count(lbs); i++) {
1635 const struct smap_node *node = nodes[i];
1636 ds_put_format(&ctx->output, "%s\n", node->value);
1637 }
1638
1639 free(nodes);
1640 }
1641 }
1642
1643 static void
1644 lb_info_list_all(struct ctl_context *ctx,
1645 const char *lb_name, bool lb_check)
1646 {
1647 const struct nbrec_load_balancer *lb;
1648 struct smap lbs = SMAP_INITIALIZER(&lbs);
1649
1650 NBREC_LOAD_BALANCER_FOR_EACH(lb, ctx->idl) {
1651 if (lb_check && strcmp(lb->name, lb_name)) {
1652 continue;
1653 }
1654 lb_info_add_smap(lb, &lbs);
1655 }
1656
1657 lb_info_print(ctx, &lbs);
1658 smap_destroy(&lbs);
1659 }
1660
1661 static void
1662 nbctl_lb_list(struct ctl_context *ctx)
1663 {
1664 if (ctx->argc == 1) {
1665 lb_info_list_all(ctx, NULL, false);
1666 } else if (ctx->argc == 2) {
1667 lb_info_list_all(ctx, ctx->argv[1], true);
1668 }
1669 }
1670
1671 static void
1672 nbctl_lr_lb_add(struct ctl_context *ctx)
1673 {
1674 const struct nbrec_logical_router *lr;
1675 const struct nbrec_load_balancer *new_lb;
1676
1677 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1678 new_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true);
1679
1680 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1681 for (int i = 0; i < lr->n_load_balancer; i++) {
1682 const struct nbrec_load_balancer *lb
1683 = lr->load_balancer[i];
1684
1685 if (uuid_equals(&new_lb->header_.uuid, &lb->header_.uuid)) {
1686 if (may_exist) {
1687 return;
1688 }
1689 ctl_fatal(UUID_FMT " : a load balancer with this UUID already "
1690 "exists", UUID_ARGS(&lb->header_.uuid));
1691 }
1692 }
1693
1694 /* Insert the load balancer into the logical router. */
1695 nbrec_logical_router_verify_load_balancer(lr);
1696 struct nbrec_load_balancer **new_lbs
1697 = xmalloc(sizeof *new_lbs * (lr->n_load_balancer + 1));
1698
1699 memcpy(new_lbs, lr->load_balancer, sizeof *new_lbs * lr->n_load_balancer);
1700 new_lbs[lr->n_load_balancer] = CONST_CAST(struct nbrec_load_balancer *,
1701 new_lb);
1702 nbrec_logical_router_set_load_balancer(lr, new_lbs,
1703 lr->n_load_balancer + 1);
1704 free(new_lbs);
1705 }
1706
1707 static void
1708 nbctl_lr_lb_del(struct ctl_context *ctx)
1709 {
1710 const struct nbrec_logical_router *lr;
1711 const struct nbrec_load_balancer *del_lb;
1712 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
1713
1714 if (ctx->argc == 2) {
1715 /* If load-balancer is not specified, remove
1716 * all load-balancers from the logical router. */
1717 nbrec_logical_router_verify_load_balancer(lr);
1718 nbrec_logical_router_set_load_balancer(lr, NULL, 0);
1719 return;
1720 }
1721
1722 del_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true);
1723 for (size_t i = 0; i < lr->n_load_balancer; i++) {
1724 const struct nbrec_load_balancer *lb
1725 = lr->load_balancer[i];
1726
1727 if (uuid_equals(&del_lb->header_.uuid, &lb->header_.uuid)) {
1728 /* Remove the matching rule. */
1729 nbrec_logical_router_verify_load_balancer(lr);
1730
1731 struct nbrec_load_balancer **new_lbs
1732 = xmemdup(lr->load_balancer,
1733 sizeof *new_lbs * lr->n_load_balancer);
1734 new_lbs[i] = lr->load_balancer[lr->n_load_balancer - 1];
1735 nbrec_logical_router_set_load_balancer(lr, new_lbs,
1736 lr->n_load_balancer - 1);
1737 free(new_lbs);
1738 return;
1739 }
1740 }
1741
1742 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1743 if (must_exist) {
1744 ctl_fatal("load balancer %s is not part of any logical router.",
1745 del_lb->name);
1746 }
1747 }
1748
1749 static void
1750 nbctl_lr_lb_list(struct ctl_context *ctx)
1751 {
1752 const char *lr_name = ctx->argv[1];
1753 const struct nbrec_logical_router *lr;
1754 struct smap lbs = SMAP_INITIALIZER(&lbs);
1755
1756 lr = lr_by_name_or_uuid(ctx, lr_name, true);
1757 for (int i = 0; i < lr->n_load_balancer; i++) {
1758 const struct nbrec_load_balancer *lb
1759 = lr->load_balancer[i];
1760 lb_info_add_smap(lb, &lbs);
1761 }
1762
1763 lb_info_print(ctx, &lbs);
1764 smap_destroy(&lbs);
1765 }
1766
1767 static void
1768 nbctl_ls_lb_add(struct ctl_context *ctx)
1769 {
1770 const struct nbrec_logical_switch *ls;
1771 const struct nbrec_load_balancer *new_lb;
1772
1773 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1774 new_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true);
1775
1776 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1777 for (int i = 0; i < ls->n_load_balancer; i++) {
1778 const struct nbrec_load_balancer *lb
1779 = ls->load_balancer[i];
1780
1781 if (uuid_equals(&new_lb->header_.uuid, &lb->header_.uuid)) {
1782 if (may_exist) {
1783 return;
1784 }
1785 ctl_fatal(UUID_FMT " : a load balancer with this UUID already "
1786 "exists", UUID_ARGS(&lb->header_.uuid));
1787 }
1788 }
1789
1790 /* Insert the load balancer into the logical switch. */
1791 nbrec_logical_switch_verify_load_balancer(ls);
1792 struct nbrec_load_balancer **new_lbs
1793 = xmalloc(sizeof *new_lbs * (ls->n_load_balancer + 1));
1794
1795 memcpy(new_lbs, ls->load_balancer, sizeof *new_lbs * ls->n_load_balancer);
1796 new_lbs[ls->n_load_balancer] = CONST_CAST(struct nbrec_load_balancer *,
1797 new_lb);
1798 nbrec_logical_switch_set_load_balancer(ls, new_lbs,
1799 ls->n_load_balancer + 1);
1800 free(new_lbs);
1801 }
1802
1803 static void
1804 nbctl_ls_lb_del(struct ctl_context *ctx)
1805 {
1806 const struct nbrec_logical_switch *ls;
1807 const struct nbrec_load_balancer *del_lb;
1808 ls = ls_by_name_or_uuid(ctx, ctx->argv[1], true);
1809
1810 if (ctx->argc == 2) {
1811 /* If load-balancer is not specified, remove
1812 * all load-balancers from the logical switch. */
1813 nbrec_logical_switch_verify_load_balancer(ls);
1814 nbrec_logical_switch_set_load_balancer(ls, NULL, 0);
1815 return;
1816 }
1817
1818 del_lb = lb_by_name_or_uuid(ctx, ctx->argv[2], true);
1819 for (size_t i = 0; i < ls->n_load_balancer; i++) {
1820 const struct nbrec_load_balancer *lb
1821 = ls->load_balancer[i];
1822
1823 if (uuid_equals(&del_lb->header_.uuid, &lb->header_.uuid)) {
1824 /* Remove the matching rule. */
1825 nbrec_logical_switch_verify_load_balancer(ls);
1826
1827 struct nbrec_load_balancer **new_lbs
1828 = xmemdup(ls->load_balancer,
1829 sizeof *new_lbs * ls->n_load_balancer);
1830 new_lbs[i] = ls->load_balancer[ls->n_load_balancer - 1];
1831 nbrec_logical_switch_set_load_balancer(ls, new_lbs,
1832 ls->n_load_balancer - 1);
1833 free(new_lbs);
1834 return;
1835 }
1836 }
1837
1838 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1839 if (must_exist) {
1840 ctl_fatal("load balancer %s is not part of any logical switch.",
1841 del_lb->name);
1842 }
1843 }
1844
1845 static void
1846 nbctl_ls_lb_list(struct ctl_context *ctx)
1847 {
1848 const char *ls_name = ctx->argv[1];
1849 const struct nbrec_logical_switch *ls;
1850 struct smap lbs = SMAP_INITIALIZER(&lbs);
1851
1852 ls = ls_by_name_or_uuid(ctx, ls_name, true);
1853 for (int i = 0; i < ls->n_load_balancer; i++) {
1854 const struct nbrec_load_balancer *lb
1855 = ls->load_balancer[i];
1856 lb_info_add_smap(lb, &lbs);
1857 }
1858
1859 lb_info_print(ctx, &lbs);
1860 smap_destroy(&lbs);
1861 }
1862
1863 static void
1864 nbctl_lr_add(struct ctl_context *ctx)
1865 {
1866 const char *lr_name = ctx->argc == 2 ? ctx->argv[1] : NULL;
1867
1868 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
1869 bool add_duplicate = shash_find(&ctx->options, "--add-duplicate") != NULL;
1870 if (may_exist && add_duplicate) {
1871 ctl_fatal("--may-exist and --add-duplicate may not be used together");
1872 }
1873
1874 if (lr_name) {
1875 if (!add_duplicate) {
1876 const struct nbrec_logical_router *lr;
1877 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
1878 if (!strcmp(lr->name, lr_name)) {
1879 if (may_exist) {
1880 return;
1881 }
1882 ctl_fatal("%s: a router with this name already exists",
1883 lr_name);
1884 }
1885 }
1886 }
1887 } else if (may_exist) {
1888 ctl_fatal("--may-exist requires specifying a name");
1889 } else if (add_duplicate) {
1890 ctl_fatal("--add-duplicate requires specifying a name");
1891 }
1892
1893 struct nbrec_logical_router *lr;
1894 lr = nbrec_logical_router_insert(ctx->txn);
1895 if (lr_name) {
1896 nbrec_logical_router_set_name(lr, lr_name);
1897 }
1898 }
1899
1900 static void
1901 nbctl_lr_del(struct ctl_context *ctx)
1902 {
1903 bool must_exist = !shash_find(&ctx->options, "--if-exists");
1904 const char *id = ctx->argv[1];
1905 const struct nbrec_logical_router *lr;
1906
1907 lr = lr_by_name_or_uuid(ctx, id, must_exist);
1908 if (!lr) {
1909 return;
1910 }
1911
1912 nbrec_logical_router_delete(lr);
1913 }
1914
1915 static void
1916 nbctl_lr_list(struct ctl_context *ctx)
1917 {
1918 const struct nbrec_logical_router *lr;
1919 struct smap lrs;
1920
1921 smap_init(&lrs);
1922 NBREC_LOGICAL_ROUTER_FOR_EACH(lr, ctx->idl) {
1923 smap_add_format(&lrs, lr->name, UUID_FMT " (%s)",
1924 UUID_ARGS(&lr->header_.uuid), lr->name);
1925 }
1926 const struct smap_node **nodes = smap_sort(&lrs);
1927 for (size_t i = 0; i < smap_count(&lrs); i++) {
1928 const struct smap_node *node = nodes[i];
1929 ds_put_format(&ctx->output, "%s\n", node->value);
1930 }
1931 smap_destroy(&lrs);
1932 free(nodes);
1933 }
1934
1935 static const struct nbrec_dhcp_options *
1936 dhcp_options_get(struct ctl_context *ctx, const char *id, bool must_exist)
1937 {
1938 struct uuid dhcp_opts_uuid;
1939 const struct nbrec_dhcp_options *dhcp_opts = NULL;
1940 if (uuid_from_string(&dhcp_opts_uuid, id)) {
1941 dhcp_opts = nbrec_dhcp_options_get_for_uuid(ctx->idl, &dhcp_opts_uuid);
1942 }
1943
1944 if (!dhcp_opts && must_exist) {
1945 ctl_fatal("%s: dhcp options UUID not found", id);
1946 }
1947 return dhcp_opts;
1948 }
1949
1950 static void
1951 nbctl_dhcp_options_create(struct ctl_context *ctx)
1952 {
1953 /* Validate the cidr */
1954 ovs_be32 ip;
1955 unsigned int plen;
1956 char *error = ip_parse_cidr(ctx->argv[1], &ip, &plen);
1957 if (error){
1958 /* check if its IPv6 cidr */
1959 free(error);
1960 struct in6_addr ipv6;
1961 error = ipv6_parse_cidr(ctx->argv[1], &ipv6, &plen);
1962 if (error) {
1963 free(error);
1964 ctl_fatal("Invalid cidr format '%s'", ctx->argv[1]);
1965 }
1966 }
1967
1968 struct nbrec_dhcp_options *dhcp_opts = nbrec_dhcp_options_insert(ctx->txn);
1969 nbrec_dhcp_options_set_cidr(dhcp_opts, ctx->argv[1]);
1970
1971 struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
1972 for (size_t i = 2; i < ctx->argc; i++) {
1973 char *key, *value;
1974 value = xstrdup(ctx->argv[i]);
1975 key = strsep(&value, "=");
1976 if (value) {
1977 smap_add(&ext_ids, key, value);
1978 }
1979 free(key);
1980 }
1981
1982 nbrec_dhcp_options_set_external_ids(dhcp_opts, &ext_ids);
1983 smap_destroy(&ext_ids);
1984 }
1985
1986 static void
1987 nbctl_dhcp_options_set_options(struct ctl_context *ctx)
1988 {
1989 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
1990 ctx, ctx->argv[1], true);
1991
1992 struct smap dhcp_options = SMAP_INITIALIZER(&dhcp_options);
1993 for (size_t i = 2; i < ctx->argc; i++) {
1994 char *key, *value;
1995 value = xstrdup(ctx->argv[i]);
1996 key = strsep(&value, "=");
1997 if (value) {
1998 smap_add(&dhcp_options, key, value);
1999 }
2000 free(key);
2001 }
2002
2003 nbrec_dhcp_options_set_options(dhcp_opts, &dhcp_options);
2004 smap_destroy(&dhcp_options);
2005 }
2006
2007 static void
2008 nbctl_dhcp_options_get_options(struct ctl_context *ctx)
2009 {
2010 const struct nbrec_dhcp_options *dhcp_opts = dhcp_options_get(
2011 ctx, ctx->argv[1], true);
2012
2013 struct smap_node *node;
2014 SMAP_FOR_EACH(node, &dhcp_opts->options) {
2015 ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
2016 }
2017 }
2018
2019 static void
2020 nbctl_dhcp_options_del(struct ctl_context *ctx)
2021 {
2022 bool must_exist = !shash_find(&ctx->options, "--if-exists");
2023 const char *id = ctx->argv[1];
2024 const struct nbrec_dhcp_options *dhcp_opts;
2025
2026 dhcp_opts = dhcp_options_get(ctx, id, must_exist);
2027 if (!dhcp_opts) {
2028 return;
2029 }
2030
2031 nbrec_dhcp_options_delete(dhcp_opts);
2032 }
2033
2034 static void
2035 nbctl_dhcp_options_list(struct ctl_context *ctx)
2036 {
2037 const struct nbrec_dhcp_options *dhcp_opts;
2038 struct smap dhcp_options;
2039
2040 smap_init(&dhcp_options);
2041 NBREC_DHCP_OPTIONS_FOR_EACH(dhcp_opts, ctx->idl) {
2042 smap_add_format(&dhcp_options, dhcp_opts->cidr, UUID_FMT,
2043 UUID_ARGS(&dhcp_opts->header_.uuid));
2044 }
2045 const struct smap_node **nodes = smap_sort(&dhcp_options);
2046 for (size_t i = 0; i < smap_count(&dhcp_options); i++) {
2047 const struct smap_node *node = nodes[i];
2048 ds_put_format(&ctx->output, "%s\n", node->value);
2049 }
2050 smap_destroy(&dhcp_options);
2051 free(nodes);
2052 }
2053
2054 /* The caller must free the returned string. */
2055 static char *
2056 normalize_ipv4_prefix(ovs_be32 ipv4, unsigned int plen)
2057 {
2058 ovs_be32 network = ipv4 & be32_prefix_mask(plen);
2059 if (plen == 32) {
2060 return xasprintf(IP_FMT, IP_ARGS(network));
2061 } else {
2062 return xasprintf(IP_FMT"/%d", IP_ARGS(network), plen);
2063 }
2064 }
2065
2066 /* The caller must free the returned string. */
2067 static char *
2068 normalize_ipv6_prefix(struct in6_addr ipv6, unsigned int plen)
2069 {
2070 char network_s[INET6_ADDRSTRLEN];
2071
2072 struct in6_addr mask = ipv6_create_mask(plen);
2073 struct in6_addr network = ipv6_addr_bitand(&ipv6, &mask);
2074
2075 inet_ntop(AF_INET6, &network, network_s, INET6_ADDRSTRLEN);
2076 if (plen == 128) {
2077 return xasprintf("%s", network_s);
2078 } else {
2079 return xasprintf("%s/%d", network_s, plen);
2080 }
2081 }
2082
2083 /* The caller must free the returned string. */
2084 static char *
2085 normalize_prefix_str(const char *orig_prefix)
2086 {
2087 unsigned int plen;
2088 ovs_be32 ipv4;
2089 char *error;
2090
2091 error = ip_parse_cidr(orig_prefix, &ipv4, &plen);
2092 if (!error) {
2093 return normalize_ipv4_prefix(ipv4, plen);
2094 } else {
2095 struct in6_addr ipv6;
2096 free(error);
2097
2098 error = ipv6_parse_cidr(orig_prefix, &ipv6, &plen);
2099 if (error) {
2100 free(error);
2101 return NULL;
2102 }
2103 return normalize_ipv6_prefix(ipv6, plen);
2104 }
2105 }
2106 \f
2107 static void
2108 nbctl_lr_route_add(struct ctl_context *ctx)
2109 {
2110 const struct nbrec_logical_router *lr;
2111 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2112 char *prefix, *next_hop;
2113
2114 const char *policy = shash_find_data(&ctx->options, "--policy");
2115 if (policy && strcmp(policy, "src-ip") && strcmp(policy, "dst-ip")) {
2116 ctl_fatal("bad policy: %s", policy);
2117 }
2118
2119 prefix = normalize_prefix_str(ctx->argv[2]);
2120 if (!prefix) {
2121 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
2122 }
2123
2124 next_hop = normalize_prefix_str(ctx->argv[3]);
2125 if (!next_hop) {
2126 free(prefix);
2127 ctl_fatal("bad next hop argument: %s", ctx->argv[3]);
2128 }
2129
2130 if (strchr(prefix, '.')) {
2131 ovs_be32 hop_ipv4;
2132 if (!ip_parse(ctx->argv[3], &hop_ipv4)) {
2133 free(prefix);
2134 free(next_hop);
2135 ctl_fatal("bad IPv4 nexthop argument: %s", ctx->argv[3]);
2136 }
2137 } else {
2138 struct in6_addr hop_ipv6;
2139 if (!ipv6_parse(ctx->argv[3], &hop_ipv6)) {
2140 free(prefix);
2141 free(next_hop);
2142 ctl_fatal("bad IPv6 nexthop argument: %s", ctx->argv[3]);
2143 }
2144 }
2145
2146 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
2147 for (int i = 0; i < lr->n_static_routes; i++) {
2148 const struct nbrec_logical_router_static_route *route
2149 = lr->static_routes[i];
2150 char *rt_prefix;
2151
2152 rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
2153 if (!rt_prefix) {
2154 /* Ignore existing prefix we couldn't parse. */
2155 continue;
2156 }
2157
2158 if (strcmp(rt_prefix, prefix)) {
2159 free(rt_prefix);
2160 continue;
2161 }
2162
2163 if (!may_exist) {
2164 free(next_hop);
2165 free(rt_prefix);
2166 ctl_fatal("duplicate prefix: %s", prefix);
2167 }
2168
2169 /* Update the next hop for an existing route. */
2170 nbrec_logical_router_verify_static_routes(lr);
2171 nbrec_logical_router_static_route_verify_ip_prefix(route);
2172 nbrec_logical_router_static_route_verify_nexthop(route);
2173 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
2174 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
2175 if (ctx->argc == 5) {
2176 nbrec_logical_router_static_route_set_output_port(route,
2177 ctx->argv[4]);
2178 }
2179 if (policy) {
2180 nbrec_logical_router_static_route_set_policy(route, policy);
2181 }
2182 free(rt_prefix);
2183 free(next_hop);
2184 free(prefix);
2185 return;
2186 }
2187
2188 struct nbrec_logical_router_static_route *route;
2189 route = nbrec_logical_router_static_route_insert(ctx->txn);
2190 nbrec_logical_router_static_route_set_ip_prefix(route, prefix);
2191 nbrec_logical_router_static_route_set_nexthop(route, next_hop);
2192 if (ctx->argc == 5) {
2193 nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]);
2194 }
2195 if (policy) {
2196 nbrec_logical_router_static_route_set_policy(route, policy);
2197 }
2198
2199 nbrec_logical_router_verify_static_routes(lr);
2200 struct nbrec_logical_router_static_route **new_routes
2201 = xmalloc(sizeof *new_routes * (lr->n_static_routes + 1));
2202 memcpy(new_routes, lr->static_routes,
2203 sizeof *new_routes * lr->n_static_routes);
2204 new_routes[lr->n_static_routes] = route;
2205 nbrec_logical_router_set_static_routes(lr, new_routes,
2206 lr->n_static_routes + 1);
2207 free(new_routes);
2208 free(next_hop);
2209 free(prefix);
2210 }
2211
2212 static void
2213 nbctl_lr_route_del(struct ctl_context *ctx)
2214 {
2215 const struct nbrec_logical_router *lr;
2216 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2217
2218 if (ctx->argc == 2) {
2219 /* If a prefix is not specified, delete all routes. */
2220 nbrec_logical_router_set_static_routes(lr, NULL, 0);
2221 return;
2222 }
2223
2224 char *prefix = normalize_prefix_str(ctx->argv[2]);
2225 if (!prefix) {
2226 ctl_fatal("bad prefix argument: %s", ctx->argv[2]);
2227 }
2228
2229 for (int i = 0; i < lr->n_static_routes; i++) {
2230 char *rt_prefix = normalize_prefix_str(lr->static_routes[i]->ip_prefix);
2231 if (!rt_prefix) {
2232 /* Ignore existing prefix we couldn't parse. */
2233 continue;
2234 }
2235
2236 if (!strcmp(prefix, rt_prefix)) {
2237 struct nbrec_logical_router_static_route **new_routes
2238 = xmemdup(lr->static_routes,
2239 sizeof *new_routes * lr->n_static_routes);
2240
2241 new_routes[i] = lr->static_routes[lr->n_static_routes - 1];
2242 nbrec_logical_router_verify_static_routes(lr);
2243 nbrec_logical_router_set_static_routes(lr, new_routes,
2244 lr->n_static_routes - 1);
2245 free(new_routes);
2246 free(rt_prefix);
2247 free(prefix);
2248 return;
2249 }
2250 free(rt_prefix);
2251 }
2252
2253 if (!shash_find(&ctx->options, "--if-exists")) {
2254 ctl_fatal("no matching prefix: %s", prefix);
2255 }
2256 free(prefix);
2257 }
2258
2259 static void
2260 nbctl_lr_nat_add(struct ctl_context *ctx)
2261 {
2262 const struct nbrec_logical_router *lr;
2263 const char *nat_type = ctx->argv[2];
2264 const char *external_ip = ctx->argv[3];
2265 const char *logical_ip = ctx->argv[4];
2266 char *new_logical_ip = NULL;
2267
2268 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2269
2270 if (strcmp(nat_type, "dnat") && strcmp(nat_type, "snat")
2271 && strcmp(nat_type, "dnat_and_snat")) {
2272 ctl_fatal("%s: type must be one of \"dnat\", \"snat\" and "
2273 "\"dnat_and_snat\".", nat_type);
2274 }
2275
2276 ovs_be32 ipv4 = 0;
2277 unsigned int plen;
2278 if (!ip_parse(external_ip, &ipv4)) {
2279 ctl_fatal("%s: should be an IPv4 address.", external_ip);
2280 }
2281
2282 if (strcmp("snat", nat_type)) {
2283 if (!ip_parse(logical_ip, &ipv4)) {
2284 ctl_fatal("%s: should be an IPv4 address.", logical_ip);
2285 }
2286 new_logical_ip = xstrdup(logical_ip);
2287 } else {
2288 char *error = ip_parse_cidr(logical_ip, &ipv4, &plen);
2289 if (error) {
2290 free(error);
2291 ctl_fatal("%s: should be an IPv4 address or network.",
2292 logical_ip);
2293 }
2294 new_logical_ip = normalize_ipv4_prefix(ipv4, plen);
2295 }
2296
2297 const char *logical_port;
2298 const char *external_mac;
2299 if (ctx->argc == 6) {
2300 ctl_fatal("lr-nat-add with logical_port "
2301 "must also specify external_mac.");
2302 } else if (ctx->argc == 7) {
2303 if (strcmp(nat_type, "dnat_and_snat")) {
2304 ctl_fatal("logical_port and external_mac are only valid when "
2305 "type is \"dnat_and_snat\".");
2306 }
2307
2308 logical_port = ctx->argv[5];
2309 lsp_by_name_or_uuid(ctx, logical_port, true);
2310
2311 external_mac = ctx->argv[6];
2312 struct eth_addr ea;
2313 if (!eth_addr_from_string(external_mac, &ea)) {
2314 ctl_fatal("invalid mac address %s.", external_mac);
2315 }
2316 } else {
2317 logical_port = NULL;
2318 external_mac = NULL;
2319 }
2320
2321 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
2322 int is_snat = !strcmp("snat", nat_type);
2323 for (size_t i = 0; i < lr->n_nat; i++) {
2324 const struct nbrec_nat *nat = lr->nat[i];
2325 if (!strcmp(nat_type, nat->type)) {
2326 if (!strcmp(is_snat ? new_logical_ip : external_ip,
2327 is_snat ? nat->logical_ip : nat->external_ip)) {
2328 if (!strcmp(is_snat ? external_ip : new_logical_ip,
2329 is_snat ? nat->external_ip : nat->logical_ip)) {
2330 if (may_exist) {
2331 nbrec_nat_verify_logical_port(nat);
2332 nbrec_nat_verify_external_mac(nat);
2333 nbrec_nat_set_logical_port(nat, logical_port);
2334 nbrec_nat_set_external_mac(nat, external_mac);
2335 free(new_logical_ip);
2336 return;
2337 }
2338 ctl_fatal("%s, %s: a NAT with this external_ip and "
2339 "logical_ip already exists",
2340 external_ip, new_logical_ip);
2341 } else {
2342 ctl_fatal("a NAT with this type (%s) and %s (%s) "
2343 "already exists",
2344 nat_type,
2345 is_snat ? "logical_ip" : "external_ip",
2346 is_snat ? new_logical_ip : external_ip);
2347 }
2348 }
2349 }
2350 }
2351
2352 /* Create the NAT. */
2353 struct nbrec_nat *nat = nbrec_nat_insert(ctx->txn);
2354 nbrec_nat_set_type(nat, nat_type);
2355 nbrec_nat_set_external_ip(nat, external_ip);
2356 nbrec_nat_set_logical_ip(nat, new_logical_ip);
2357 if (logical_port && external_mac) {
2358 nbrec_nat_set_logical_port(nat, logical_port);
2359 nbrec_nat_set_external_mac(nat, external_mac);
2360 }
2361 free(new_logical_ip);
2362
2363 /* Insert the NAT into the logical router. */
2364 nbrec_logical_router_verify_nat(lr);
2365 struct nbrec_nat **new_nats = xmalloc(sizeof *new_nats * (lr->n_nat + 1));
2366 memcpy(new_nats, lr->nat, sizeof *new_nats * lr->n_nat);
2367 new_nats[lr->n_nat] = nat;
2368 nbrec_logical_router_set_nat(lr, new_nats, lr->n_nat + 1);
2369 free(new_nats);
2370 }
2371
2372 static void
2373 nbctl_lr_nat_del(struct ctl_context *ctx)
2374 {
2375 const struct nbrec_logical_router *lr;
2376 bool must_exist = !shash_find(&ctx->options, "--if-exists");
2377 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2378
2379 if (ctx->argc == 2) {
2380 /* If type, external_ip and logical_ip are not specified, delete
2381 * all NATs. */
2382 nbrec_logical_router_verify_nat(lr);
2383 nbrec_logical_router_set_nat(lr, NULL, 0);
2384 return;
2385 }
2386
2387 const char *nat_type = ctx->argv[2];
2388 if (strcmp(nat_type, "dnat") && strcmp(nat_type, "snat")
2389 && strcmp(nat_type, "dnat_and_snat")) {
2390 ctl_fatal("%s: type must be one of \"dnat\", \"snat\" and "
2391 "\"dnat_and_snat\".", nat_type);
2392 }
2393
2394 if (ctx->argc == 3) {
2395 /*Deletes all NATs with the specified type. */
2396 struct nbrec_nat **new_nats = xmalloc(sizeof *new_nats * lr->n_nat);
2397 int n_nat = 0;
2398 for (size_t i = 0; i < lr->n_nat; i++) {
2399 if (strcmp(nat_type, lr->nat[i]->type)) {
2400 new_nats[n_nat++] = lr->nat[i];
2401 }
2402 }
2403
2404 nbrec_logical_router_verify_nat(lr);
2405 nbrec_logical_router_set_nat(lr, new_nats, n_nat);
2406 free(new_nats);
2407 return;
2408 }
2409
2410 const char *nat_ip = ctx->argv[3];
2411 int is_snat = !strcmp("snat", nat_type);
2412 /* Remove the matching NAT. */
2413 for (size_t i = 0; i < lr->n_nat; i++) {
2414 struct nbrec_nat *nat = lr->nat[i];
2415 if (!strcmp(nat_type, nat->type) &&
2416 !strcmp(nat_ip, is_snat ? nat->logical_ip : nat->external_ip)) {
2417 struct nbrec_nat **new_nats
2418 = xmemdup(lr->nat, sizeof *new_nats * lr->n_nat);
2419 new_nats[i] = lr->nat[lr->n_nat - 1];
2420 nbrec_logical_router_verify_nat(lr);
2421 nbrec_logical_router_set_nat(lr, new_nats,
2422 lr->n_nat - 1);
2423 free(new_nats);
2424 return;
2425 }
2426 }
2427
2428 if (must_exist) {
2429 ctl_fatal("no matching NAT with the type (%s) and %s (%s)",
2430 nat_type, is_snat ? "logical_ip" : "external_ip", nat_ip);
2431 }
2432 }
2433
2434 static void
2435 nbctl_lr_nat_list(struct ctl_context *ctx)
2436 {
2437 const struct nbrec_logical_router *lr;
2438 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2439
2440 struct smap lr_nats = SMAP_INITIALIZER(&lr_nats);
2441 for (size_t i = 0; i < lr->n_nat; i++) {
2442 const struct nbrec_nat *nat = lr->nat[i];
2443 char *key = xasprintf("%-17.13s%s", nat->type, nat->external_ip);
2444 if (nat->external_mac && nat->logical_port) {
2445 smap_add_format(&lr_nats, key, "%-22.18s%-21.17s%s",
2446 nat->logical_ip, nat->external_mac,
2447 nat->logical_port);
2448 } else {
2449 smap_add_format(&lr_nats, key, "%s", nat->logical_ip);
2450 }
2451 free(key);
2452 }
2453
2454 const struct smap_node **nodes = smap_sort(&lr_nats);
2455 if (nodes) {
2456 ds_put_format(&ctx->output, "%-17.13s%-19.15s%-22.18s%-21.17s%s\n",
2457 "TYPE", "EXTERNAL_IP", "LOGICAL_IP", "EXTERNAL_MAC",
2458 "LOGICAL_PORT");
2459 for (size_t i = 0; i < smap_count(&lr_nats); i++) {
2460 const struct smap_node *node = nodes[i];
2461 ds_put_format(&ctx->output, "%-36.32s%s\n",
2462 node->key, node->value);
2463 }
2464 free(nodes);
2465 }
2466 smap_destroy(&lr_nats);
2467 }
2468
2469 \f
2470 static const struct nbrec_logical_router_port *
2471 lrp_by_name_or_uuid(struct ctl_context *ctx, const char *id, bool must_exist)
2472 {
2473 const struct nbrec_logical_router_port *lrp = NULL;
2474
2475 struct uuid lrp_uuid;
2476 bool is_uuid = uuid_from_string(&lrp_uuid, id);
2477 if (is_uuid) {
2478 lrp = nbrec_logical_router_port_get_for_uuid(ctx->idl, &lrp_uuid);
2479 }
2480
2481 if (!lrp) {
2482 NBREC_LOGICAL_ROUTER_PORT_FOR_EACH(lrp, ctx->idl) {
2483 if (!strcmp(lrp->name, id)) {
2484 break;
2485 }
2486 }
2487 }
2488
2489 if (!lrp && must_exist) {
2490 ctl_fatal("%s: port %s not found", id, is_uuid ? "UUID" : "name");
2491 }
2492
2493 return lrp;
2494 }
2495
2496 /* Returns the logical router that contains 'lrp'. */
2497 static const struct nbrec_logical_router *
2498 lrp_to_lr(const struct ovsdb_idl *idl,
2499 const struct nbrec_logical_router_port *lrp)
2500 {
2501 const struct nbrec_logical_router *lr;
2502 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, idl) {
2503 for (size_t i = 0; i < lr->n_ports; i++) {
2504 if (lr->ports[i] == lrp) {
2505 return lr;
2506 }
2507 }
2508 }
2509
2510 /* Can't happen because of the database schema */
2511 ctl_fatal("port %s is not part of any logical router",
2512 lrp->name);
2513 }
2514
2515 static const char *
2516 lr_get_name(const struct nbrec_logical_router *lr, char uuid_s[UUID_LEN + 1],
2517 size_t uuid_s_size)
2518 {
2519 if (lr->name[0]) {
2520 return lr->name;
2521 }
2522 snprintf(uuid_s, uuid_s_size, UUID_FMT, UUID_ARGS(&lr->header_.uuid));
2523 return uuid_s;
2524 }
2525
2526 static void
2527 nbctl_lrp_add(struct ctl_context *ctx)
2528 {
2529 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
2530
2531 const struct nbrec_logical_router *lr;
2532 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2533
2534 const char *lrp_name = ctx->argv[2];
2535 const char *mac = ctx->argv[3];
2536 const char **networks = (const char **) &ctx->argv[4];
2537
2538 int n_networks = ctx->argc - 4;
2539 for (int i = 4; i < ctx->argc; i++) {
2540 if (strchr(ctx->argv[i], '=')) {
2541 n_networks = i - 4;
2542 break;
2543 }
2544 }
2545
2546 if (!n_networks) {
2547 ctl_fatal("%s: router port requires specifying a network", lrp_name);
2548 }
2549
2550 char **settings = (char **) &ctx->argv[n_networks + 4];
2551 int n_settings = ctx->argc - 4 - n_networks;
2552
2553 const struct nbrec_logical_router_port *lrp;
2554 lrp = lrp_by_name_or_uuid(ctx, lrp_name, false);
2555 if (lrp) {
2556 if (!may_exist) {
2557 ctl_fatal("%s: a port with this name already exists",
2558 lrp_name);
2559 }
2560
2561 const struct nbrec_logical_router *bound_lr;
2562 bound_lr = lrp_to_lr(ctx->idl, lrp);
2563 if (bound_lr != lr) {
2564 char uuid_s[UUID_LEN + 1];
2565 ctl_fatal("%s: port already exists but in router %s", lrp_name,
2566 lr_get_name(bound_lr, uuid_s, sizeof uuid_s));
2567 }
2568
2569 if (strcmp(mac, lrp->mac)) {
2570 ctl_fatal("%s: port already exists with mac %s", lrp_name,
2571 lrp->mac);
2572 }
2573
2574 struct sset new_networks = SSET_INITIALIZER(&new_networks);
2575 for (int i = 0; i < n_networks; i++) {
2576 sset_add(&new_networks, networks[i]);
2577 }
2578
2579 struct sset orig_networks = SSET_INITIALIZER(&orig_networks);
2580 sset_add_array(&orig_networks, lrp->networks, lrp->n_networks);
2581
2582 bool same_networks = sset_equals(&orig_networks, &new_networks);
2583 sset_destroy(&orig_networks);
2584 sset_destroy(&new_networks);
2585 if (!same_networks) {
2586 ctl_fatal("%s: port already exists with different network",
2587 lrp_name);
2588 }
2589
2590 /* Special-case sanity-check of peer ports. */
2591 const char *peer = NULL;
2592 for (int i = 0; i < n_settings; i++) {
2593 if (!strncmp(settings[i], "peer=", 5)) {
2594 peer = settings[i] + 5;
2595 break;
2596 }
2597 }
2598
2599 if ((!peer != !lrp->peer) ||
2600 (lrp->peer && strcmp(peer, lrp->peer))) {
2601 ctl_fatal("%s: port already exists with mismatching peer",
2602 lrp_name);
2603 }
2604
2605 return;
2606 }
2607
2608 struct eth_addr ea;
2609 if (!eth_addr_from_string(mac, &ea)) {
2610 ctl_fatal("%s: invalid mac address %s", lrp_name, mac);
2611 }
2612
2613 for (int i = 0; i < n_networks; i++) {
2614 ovs_be32 ipv4;
2615 unsigned int plen;
2616 char *error = ip_parse_cidr(networks[i], &ipv4, &plen);
2617 if (error) {
2618 free(error);
2619 struct in6_addr ipv6;
2620 error = ipv6_parse_cidr(networks[i], &ipv6, &plen);
2621 if (error) {
2622 free(error);
2623 ctl_fatal("%s: invalid network address: %s", lrp_name,
2624 networks[i]);
2625 }
2626 }
2627 }
2628
2629 /* Create the logical port. */
2630 lrp = nbrec_logical_router_port_insert(ctx->txn);
2631 nbrec_logical_router_port_set_name(lrp, lrp_name);
2632 nbrec_logical_router_port_set_mac(lrp, mac);
2633 nbrec_logical_router_port_set_networks(lrp, networks, n_networks);
2634
2635 for (int i = 0; i < n_settings; i++) {
2636 ctl_set_column("Logical_Router_Port", &lrp->header_, settings[i],
2637 ctx->symtab);
2638 }
2639
2640 /* Insert the logical port into the logical router. */
2641 nbrec_logical_router_verify_ports(lr);
2642 struct nbrec_logical_router_port **new_ports = xmalloc(sizeof *new_ports *
2643 (lr->n_ports + 1));
2644 memcpy(new_ports, lr->ports, sizeof *new_ports * lr->n_ports);
2645 new_ports[lr->n_ports] = CONST_CAST(struct nbrec_logical_router_port *,
2646 lrp);
2647 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports + 1);
2648 free(new_ports);
2649 }
2650
2651 /* Removes logical router port 'lr->ports[idx]'. */
2652 static void
2653 remove_lrp(const struct nbrec_logical_router *lr, size_t idx)
2654 {
2655 const struct nbrec_logical_router_port *lrp = lr->ports[idx];
2656
2657 /* First remove 'lrp' from the array of ports. This is what will
2658 * actually cause the logical port to be deleted when the transaction is
2659 * sent to the database server (due to garbage collection). */
2660 struct nbrec_logical_router_port **new_ports
2661 = xmemdup(lr->ports, sizeof *new_ports * lr->n_ports);
2662 new_ports[idx] = new_ports[lr->n_ports - 1];
2663 nbrec_logical_router_verify_ports(lr);
2664 nbrec_logical_router_set_ports(lr, new_ports, lr->n_ports - 1);
2665 free(new_ports);
2666
2667 /* Delete 'lrp' from the IDL. This won't have a real effect on
2668 * the database server (the IDL will suppress it in fact) but it
2669 * means that it won't show up when we iterate with
2670 * NBREC_LOGICAL_ROUTER_PORT_FOR_EACH later. */
2671 nbrec_logical_router_port_delete(lrp);
2672 }
2673
2674 static void
2675 nbctl_lrp_del(struct ctl_context *ctx)
2676 {
2677 bool must_exist = !shash_find(&ctx->options, "--if-exists");
2678 const struct nbrec_logical_router_port *lrp;
2679
2680 lrp = lrp_by_name_or_uuid(ctx, ctx->argv[1], must_exist);
2681 if (!lrp) {
2682 return;
2683 }
2684
2685 /* Find the router that contains 'lrp', then delete it. */
2686 const struct nbrec_logical_router *lr;
2687 NBREC_LOGICAL_ROUTER_FOR_EACH (lr, ctx->idl) {
2688 for (size_t i = 0; i < lr->n_ports; i++) {
2689 if (lr->ports[i] == lrp) {
2690 remove_lrp(lr, i);
2691 return;
2692 }
2693 }
2694 }
2695
2696 /* Can't happen because of the database schema. */
2697 ctl_fatal("logical port %s is not part of any logical router",
2698 ctx->argv[1]);
2699 }
2700
2701 /* Print a list of logical router ports. */
2702 static void
2703 nbctl_lrp_list(struct ctl_context *ctx)
2704 {
2705 const char *id = ctx->argv[1];
2706 const struct nbrec_logical_router *lr;
2707 struct smap lrps;
2708 size_t i;
2709
2710 lr = lr_by_name_or_uuid(ctx, id, true);
2711
2712 smap_init(&lrps);
2713 for (i = 0; i < lr->n_ports; i++) {
2714 const struct nbrec_logical_router_port *lrp = lr->ports[i];
2715 smap_add_format(&lrps, lrp->name, UUID_FMT " (%s)",
2716 UUID_ARGS(&lrp->header_.uuid), lrp->name);
2717 }
2718 const struct smap_node **nodes = smap_sort(&lrps);
2719 for (i = 0; i < smap_count(&lrps); i++) {
2720 const struct smap_node *node = nodes[i];
2721 ds_put_format(&ctx->output, "%s\n", node->value);
2722 }
2723 smap_destroy(&lrps);
2724 free(nodes);
2725 }
2726
2727 /* Set the logical router port admin-enabled state. */
2728 static void
2729 nbctl_lrp_set_enabled(struct ctl_context *ctx)
2730 {
2731 const char *id = ctx->argv[1];
2732 const char *state = ctx->argv[2];
2733 const struct nbrec_logical_router_port *lrp;
2734
2735 lrp = lrp_by_name_or_uuid(ctx, id, true);
2736 if (!lrp) {
2737 return;
2738 }
2739
2740 bool enabled = parse_enabled(state);
2741 nbrec_logical_router_port_set_enabled(lrp, &enabled, 1);
2742 }
2743
2744 /* Print admin-enabled state for logical router port. */
2745 static void
2746 nbctl_lrp_get_enabled(struct ctl_context *ctx)
2747 {
2748 const char *id = ctx->argv[1];
2749 const struct nbrec_logical_router_port *lrp;
2750
2751 lrp = lrp_by_name_or_uuid(ctx, id, true);
2752 if (!lrp) {
2753 return;
2754 }
2755
2756 ds_put_format(&ctx->output, "%s\n",
2757 !lrp->enabled ||
2758 *lrp->enabled ? "enabled" : "disabled");
2759 }
2760 \f
2761 struct ipv4_route {
2762 int priority;
2763 ovs_be32 addr;
2764 const struct nbrec_logical_router_static_route *route;
2765 };
2766
2767 static int
2768 ipv4_route_cmp(const void *route1_, const void *route2_)
2769 {
2770 const struct ipv4_route *route1p = route1_;
2771 const struct ipv4_route *route2p = route2_;
2772
2773 if (route1p->priority != route2p->priority) {
2774 return route1p->priority > route2p->priority ? -1 : 1;
2775 } else if (route1p->addr != route2p->addr) {
2776 return ntohl(route1p->addr) < ntohl(route2p->addr) ? -1 : 1;
2777 } else {
2778 return 0;
2779 }
2780 }
2781
2782 struct ipv6_route {
2783 int priority;
2784 struct in6_addr addr;
2785 const struct nbrec_logical_router_static_route *route;
2786 };
2787
2788 static int
2789 ipv6_route_cmp(const void *route1_, const void *route2_)
2790 {
2791 const struct ipv6_route *route1p = route1_;
2792 const struct ipv6_route *route2p = route2_;
2793
2794 if (route1p->priority != route2p->priority) {
2795 return route1p->priority > route2p->priority ? -1 : 1;
2796 }
2797 return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr));
2798 }
2799
2800 static void
2801 print_route(const struct nbrec_logical_router_static_route *route, struct ds *s)
2802 {
2803
2804 char *prefix = normalize_prefix_str(route->ip_prefix);
2805 char *next_hop = normalize_prefix_str(route->nexthop);
2806 ds_put_format(s, "%25s %25s", prefix, next_hop);
2807 free(prefix);
2808 free(next_hop);
2809
2810 if (route->policy) {
2811 ds_put_format(s, " %s", route->policy);
2812 } else {
2813 ds_put_format(s, " %s", "dst-ip");
2814 }
2815
2816 if (route->output_port) {
2817 ds_put_format(s, " %s", route->output_port);
2818 }
2819 ds_put_char(s, '\n');
2820 }
2821
2822 static void
2823 nbctl_lr_route_list(struct ctl_context *ctx)
2824 {
2825 const struct nbrec_logical_router *lr;
2826 struct ipv4_route *ipv4_routes;
2827 struct ipv6_route *ipv6_routes;
2828 size_t n_ipv4_routes = 0;
2829 size_t n_ipv6_routes = 0;
2830
2831 lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
2832
2833 ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes);
2834 ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes);
2835
2836 for (int i = 0; i < lr->n_static_routes; i++) {
2837 const struct nbrec_logical_router_static_route *route
2838 = lr->static_routes[i];
2839 unsigned int plen;
2840 ovs_be32 ipv4;
2841 const char *policy = route->policy ? route->policy : "dst-ip";
2842 char *error;
2843 error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen);
2844 if (!error) {
2845 ipv4_routes[n_ipv4_routes].priority = !strcmp(policy, "dst-ip")
2846 ? (2 * plen) + 1
2847 : 2 * plen;
2848 ipv4_routes[n_ipv4_routes].addr = ipv4;
2849 ipv4_routes[n_ipv4_routes].route = route;
2850 n_ipv4_routes++;
2851 } else {
2852 free(error);
2853
2854 struct in6_addr ipv6;
2855 error = ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen);
2856 if (!error) {
2857 ipv6_routes[n_ipv6_routes].priority = !strcmp(policy, "dst-ip")
2858 ? (2 * plen) + 1
2859 : 2 * plen;
2860 ipv6_routes[n_ipv6_routes].addr = ipv6;
2861 ipv6_routes[n_ipv6_routes].route = route;
2862 n_ipv6_routes++;
2863 } else {
2864 /* Invalid prefix. */
2865 VLOG_WARN("router "UUID_FMT" (%s) has invalid prefix: %s",
2866 UUID_ARGS(&lr->header_.uuid), lr->name,
2867 route->ip_prefix);
2868 free(error);
2869 continue;
2870 }
2871 }
2872 }
2873
2874 qsort(ipv4_routes, n_ipv4_routes, sizeof *ipv4_routes, ipv4_route_cmp);
2875 qsort(ipv6_routes, n_ipv6_routes, sizeof *ipv6_routes, ipv6_route_cmp);
2876
2877 if (n_ipv4_routes) {
2878 ds_put_cstr(&ctx->output, "IPv4 Routes\n");
2879 }
2880 for (int i = 0; i < n_ipv4_routes; i++) {
2881 print_route(ipv4_routes[i].route, &ctx->output);
2882 }
2883
2884 if (n_ipv6_routes) {
2885 ds_put_format(&ctx->output, "%sIPv6 Routes\n",
2886 n_ipv4_routes ? "\n" : "");
2887 }
2888 for (int i = 0; i < n_ipv6_routes; i++) {
2889 print_route(ipv6_routes[i].route, &ctx->output);
2890 }
2891
2892 free(ipv4_routes);
2893 free(ipv6_routes);
2894 }
2895
2896 static void
2897 verify_connections(struct ctl_context *ctx)
2898 {
2899 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
2900 const struct nbrec_connection *conn;
2901
2902 nbrec_nb_global_verify_connections(nb_global);
2903
2904 NBREC_CONNECTION_FOR_EACH(conn, ctx->idl) {
2905 nbrec_connection_verify_target(conn);
2906 }
2907 }
2908
2909 static void
2910 pre_connection(struct ctl_context *ctx)
2911 {
2912 ovsdb_idl_add_column(ctx->idl, &nbrec_nb_global_col_connections);
2913 ovsdb_idl_add_column(ctx->idl, &nbrec_connection_col_target);
2914 }
2915
2916 static void
2917 cmd_get_connection(struct ctl_context *ctx)
2918 {
2919 const struct nbrec_connection *conn;
2920 struct svec targets;
2921 size_t i;
2922
2923 verify_connections(ctx);
2924
2925 /* Print the targets in sorted order for reproducibility. */
2926 svec_init(&targets);
2927
2928 NBREC_CONNECTION_FOR_EACH(conn, ctx->idl) {
2929 svec_add(&targets, conn->target);
2930 }
2931
2932 svec_sort_unique(&targets);
2933 for (i = 0; i < targets.n; i++) {
2934 ds_put_format(&ctx->output, "%s\n", targets.names[i]);
2935 }
2936 svec_destroy(&targets);
2937 }
2938
2939 static void
2940 delete_connections(struct ctl_context *ctx)
2941 {
2942 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
2943 const struct nbrec_connection *conn, *next;
2944
2945 /* Delete Manager rows pointed to by 'connection_options' column. */
2946 NBREC_CONNECTION_FOR_EACH_SAFE(conn, next, ctx->idl) {
2947 nbrec_connection_delete(conn);
2948 }
2949
2950 /* Delete 'Manager' row refs in 'manager_options' column. */
2951 nbrec_nb_global_set_connections(nb_global, NULL, 0);
2952 }
2953
2954 static void
2955 cmd_del_connection(struct ctl_context *ctx)
2956 {
2957 verify_connections(ctx);
2958 delete_connections(ctx);
2959 }
2960
2961 static void
2962 insert_connections(struct ctl_context *ctx, char *targets[], size_t n)
2963 {
2964 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
2965 struct nbrec_connection **connections;
2966 size_t i, conns=0;
2967
2968 /* Insert each connection in a new row in Connection table. */
2969 connections = xmalloc(n * sizeof *connections);
2970 for (i = 0; i < n; i++) {
2971 if (stream_verify_name(targets[i]) &&
2972 pstream_verify_name(targets[i])) {
2973 VLOG_WARN("target type \"%s\" is possibly erroneous", targets[i]);
2974 }
2975
2976 connections[conns] = nbrec_connection_insert(ctx->txn);
2977 nbrec_connection_set_target(connections[conns], targets[i]);
2978 conns++;
2979 }
2980
2981 /* Store uuids of new connection rows in 'connection' column. */
2982 nbrec_nb_global_set_connections(nb_global, connections, conns);
2983 free(connections);
2984 }
2985
2986 static void
2987 cmd_set_connection(struct ctl_context *ctx)
2988 {
2989 const size_t n = ctx->argc - 1;
2990
2991 verify_connections(ctx);
2992 delete_connections(ctx);
2993 insert_connections(ctx, &ctx->argv[1], n);
2994 }
2995
2996 static void
2997 pre_cmd_get_ssl(struct ctl_context *ctx)
2998 {
2999 ovsdb_idl_add_column(ctx->idl, &nbrec_nb_global_col_ssl);
3000
3001 ovsdb_idl_add_column(ctx->idl, &nbrec_ssl_col_private_key);
3002 ovsdb_idl_add_column(ctx->idl, &nbrec_ssl_col_certificate);
3003 ovsdb_idl_add_column(ctx->idl, &nbrec_ssl_col_ca_cert);
3004 ovsdb_idl_add_column(ctx->idl, &nbrec_ssl_col_bootstrap_ca_cert);
3005 }
3006
3007 static void
3008 cmd_get_ssl(struct ctl_context *ctx)
3009 {
3010 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
3011 const struct nbrec_ssl *ssl = nbrec_ssl_first(ctx->idl);
3012
3013 nbrec_nb_global_verify_ssl(nb_global);
3014 if (ssl) {
3015 nbrec_ssl_verify_private_key(ssl);
3016 nbrec_ssl_verify_certificate(ssl);
3017 nbrec_ssl_verify_ca_cert(ssl);
3018 nbrec_ssl_verify_bootstrap_ca_cert(ssl);
3019
3020 ds_put_format(&ctx->output, "Private key: %s\n", ssl->private_key);
3021 ds_put_format(&ctx->output, "Certificate: %s\n", ssl->certificate);
3022 ds_put_format(&ctx->output, "CA Certificate: %s\n", ssl->ca_cert);
3023 ds_put_format(&ctx->output, "Bootstrap: %s\n",
3024 ssl->bootstrap_ca_cert ? "true" : "false");
3025 }
3026 }
3027
3028 static void
3029 pre_cmd_del_ssl(struct ctl_context *ctx)
3030 {
3031 ovsdb_idl_add_column(ctx->idl, &nbrec_nb_global_col_ssl);
3032 }
3033
3034 static void
3035 cmd_del_ssl(struct ctl_context *ctx)
3036 {
3037 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
3038 const struct nbrec_ssl *ssl = nbrec_ssl_first(ctx->idl);
3039
3040 if (ssl) {
3041 nbrec_nb_global_verify_ssl(nb_global);
3042 nbrec_ssl_delete(ssl);
3043 nbrec_nb_global_set_ssl(nb_global, NULL);
3044 }
3045 }
3046
3047 static void
3048 pre_cmd_set_ssl(struct ctl_context *ctx)
3049 {
3050 ovsdb_idl_add_column(ctx->idl, &nbrec_nb_global_col_ssl);
3051 }
3052
3053 static void
3054 cmd_set_ssl(struct ctl_context *ctx)
3055 {
3056 bool bootstrap = shash_find(&ctx->options, "--bootstrap");
3057 const struct nbrec_nb_global *nb_global = nbrec_nb_global_first(ctx->idl);
3058 const struct nbrec_ssl *ssl = nbrec_ssl_first(ctx->idl);
3059
3060 nbrec_nb_global_verify_ssl(nb_global);
3061 if (ssl) {
3062 nbrec_ssl_delete(ssl);
3063 }
3064 ssl = nbrec_ssl_insert(ctx->txn);
3065
3066 nbrec_ssl_set_private_key(ssl, ctx->argv[1]);
3067 nbrec_ssl_set_certificate(ssl, ctx->argv[2]);
3068 nbrec_ssl_set_ca_cert(ssl, ctx->argv[3]);
3069
3070 nbrec_ssl_set_bootstrap_ca_cert(ssl, bootstrap);
3071
3072 nbrec_nb_global_set_ssl(nb_global, ssl);
3073 }
3074
3075 static const struct ctl_table_class tables[NBREC_N_TABLES] = {
3076 [NBREC_TABLE_DHCP_OPTIONS].row_ids
3077 = {{&nbrec_logical_switch_port_col_name, NULL,
3078 &nbrec_logical_switch_port_col_dhcpv4_options},
3079 {&nbrec_logical_switch_port_col_external_ids,
3080 "neutron:port_name", &nbrec_logical_switch_port_col_dhcpv4_options},
3081 {&nbrec_logical_switch_port_col_name, NULL,
3082 &nbrec_logical_switch_port_col_dhcpv6_options},
3083 {&nbrec_logical_switch_port_col_external_ids,
3084 "neutron:port_name", &nbrec_logical_switch_port_col_dhcpv6_options}},
3085
3086 [NBREC_TABLE_LOGICAL_SWITCH].row_ids
3087 = {{&nbrec_logical_switch_col_name, NULL, NULL},
3088 {&nbrec_logical_switch_col_external_ids, "neutron:network_name", NULL}},
3089
3090 [NBREC_TABLE_LOGICAL_SWITCH_PORT].row_ids
3091 = {{&nbrec_logical_switch_port_col_name, NULL, NULL},
3092 {&nbrec_logical_switch_port_col_external_ids,
3093 "neutron:port_name", NULL}},
3094
3095 [NBREC_TABLE_LOGICAL_ROUTER].row_ids
3096 = {{&nbrec_logical_router_col_name, NULL, NULL},
3097 {&nbrec_logical_router_col_external_ids, "neutron:router_name", NULL}},
3098
3099 [NBREC_TABLE_LOGICAL_ROUTER_PORT].row_ids[0]
3100 = {&nbrec_logical_router_port_col_name, NULL, NULL},
3101
3102 [NBREC_TABLE_ADDRESS_SET].row_ids[0]
3103 = {&nbrec_address_set_col_name, NULL, NULL},
3104 };
3105 \f
3106 static void
3107 run_prerequisites(struct ctl_command *commands, size_t n_commands,
3108 struct ovsdb_idl *idl)
3109 {
3110 ovsdb_idl_add_table(idl, &nbrec_table_nb_global);
3111 if (wait_type == NBCTL_WAIT_SB) {
3112 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg);
3113 } else if (wait_type == NBCTL_WAIT_HV) {
3114 ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg);
3115 }
3116
3117 for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) {
3118 if (c->syntax->prerequisites) {
3119 struct ctl_context ctx;
3120
3121 ds_init(&c->output);
3122 c->table = NULL;
3123
3124 ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
3125 (c->syntax->prerequisites)(&ctx);
3126 ctl_context_done(&ctx, c);
3127
3128 ovs_assert(!c->output.string);
3129 ovs_assert(!c->table);
3130 }
3131 }
3132 }
3133
3134 static bool
3135 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
3136 struct ovsdb_idl *idl)
3137 {
3138 struct ovsdb_idl_txn *txn;
3139 enum ovsdb_idl_txn_status status;
3140 struct ovsdb_symbol_table *symtab;
3141 struct ctl_context ctx;
3142 struct ctl_command *c;
3143 struct shash_node *node;
3144 int64_t next_cfg = 0;
3145 char *error = NULL;
3146
3147 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
3148 if (dry_run) {
3149 ovsdb_idl_txn_set_dry_run(txn);
3150 }
3151
3152 ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
3153
3154 const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl);
3155 if (!nb) {
3156 /* XXX add verification that table is empty */
3157 nb = nbrec_nb_global_insert(txn);
3158 }
3159
3160 if (wait_type != NBCTL_WAIT_NONE) {
3161 ovsdb_idl_txn_increment(txn, &nb->header_, &nbrec_nb_global_col_nb_cfg,
3162 force_wait);
3163 }
3164
3165 symtab = ovsdb_symbol_table_create();
3166 for (c = commands; c < &commands[n_commands]; c++) {
3167 ds_init(&c->output);
3168 c->table = NULL;
3169 }
3170 ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
3171 for (c = commands; c < &commands[n_commands]; c++) {
3172 ctl_context_init_command(&ctx, c);
3173 if (c->syntax->run) {
3174 (c->syntax->run)(&ctx);
3175 }
3176 ctl_context_done_command(&ctx, c);
3177
3178 if (ctx.try_again) {
3179 ctl_context_done(&ctx, NULL);
3180 goto try_again;
3181 }
3182 }
3183 ctl_context_done(&ctx, NULL);
3184
3185 SHASH_FOR_EACH (node, &symtab->sh) {
3186 struct ovsdb_symbol *symbol = node->data;
3187 if (!symbol->created) {
3188 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
3189 "with \"-- --id=%s create ...\")",
3190 node->name, node->name);
3191 }
3192 if (!symbol->strong_ref) {
3193 if (!symbol->weak_ref) {
3194 VLOG_WARN("row id \"%s\" was created but no reference to it "
3195 "was inserted, so it will not actually appear in "
3196 "the database", node->name);
3197 } else {
3198 VLOG_WARN("row id \"%s\" was created but only a weak "
3199 "reference to it was inserted, so it will not "
3200 "actually appear in the database", node->name);
3201 }
3202 }
3203 }
3204
3205 status = ovsdb_idl_txn_commit_block(txn);
3206 if (wait_type != NBCTL_WAIT_NONE && status == TXN_SUCCESS) {
3207 next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
3208 }
3209 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
3210 for (c = commands; c < &commands[n_commands]; c++) {
3211 if (c->syntax->postprocess) {
3212 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
3213 (c->syntax->postprocess)(&ctx);
3214 ctl_context_done(&ctx, c);
3215 }
3216 }
3217 }
3218 error = xstrdup(ovsdb_idl_txn_get_error(txn));
3219
3220 switch (status) {
3221 case TXN_UNCOMMITTED:
3222 case TXN_INCOMPLETE:
3223 OVS_NOT_REACHED();
3224
3225 case TXN_ABORTED:
3226 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
3227 ctl_fatal("transaction aborted");
3228
3229 case TXN_UNCHANGED:
3230 case TXN_SUCCESS:
3231 break;
3232
3233 case TXN_TRY_AGAIN:
3234 goto try_again;
3235
3236 case TXN_ERROR:
3237 ctl_fatal("transaction error: %s", error);
3238
3239 case TXN_NOT_LOCKED:
3240 /* Should not happen--we never call ovsdb_idl_set_lock(). */
3241 ctl_fatal("database not locked");
3242
3243 default:
3244 OVS_NOT_REACHED();
3245 }
3246 free(error);
3247
3248 ovsdb_symbol_table_destroy(symtab);
3249
3250 for (c = commands; c < &commands[n_commands]; c++) {
3251 struct ds *ds = &c->output;
3252
3253 if (c->table) {
3254 table_print(c->table, &table_style);
3255 } else if (oneline) {
3256 size_t j;
3257
3258 ds_chomp(ds, '\n');
3259 for (j = 0; j < ds->length; j++) {
3260 int ch = ds->string[j];
3261 switch (ch) {
3262 case '\n':
3263 fputs("\\n", stdout);
3264 break;
3265
3266 case '\\':
3267 fputs("\\\\", stdout);
3268 break;
3269
3270 default:
3271 putchar(ch);
3272 }
3273 }
3274 putchar('\n');
3275 } else {
3276 fputs(ds_cstr(ds), stdout);
3277 }
3278 ds_destroy(&c->output);
3279 table_destroy(c->table);
3280 free(c->table);
3281
3282 shash_destroy_free_data(&c->options);
3283 }
3284 free(commands);
3285
3286 if (wait_type != NBCTL_WAIT_NONE && status != TXN_UNCHANGED) {
3287 ovsdb_idl_enable_reconnect(idl);
3288 for (;;) {
3289 ovsdb_idl_run(idl);
3290 NBREC_NB_GLOBAL_FOR_EACH (nb, idl) {
3291 int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB
3292 ? nb->sb_cfg
3293 : nb->hv_cfg);
3294 if (cur_cfg >= next_cfg) {
3295 goto done;
3296 }
3297 }
3298 ovsdb_idl_wait(idl);
3299 poll_block();
3300 }
3301 done: ;
3302 }
3303
3304 ovsdb_idl_txn_destroy(txn);
3305 ovsdb_idl_destroy(idl);
3306
3307 return true;
3308
3309 try_again:
3310 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
3311 * resources and return so that the caller can try again. */
3312 ovsdb_idl_txn_abort(txn);
3313 ovsdb_idl_txn_destroy(txn);
3314 the_idl_txn = NULL;
3315
3316 ovsdb_symbol_table_destroy(symtab);
3317 for (c = commands; c < &commands[n_commands]; c++) {
3318 ds_destroy(&c->output);
3319 table_destroy(c->table);
3320 free(c->table);
3321 }
3322 free(error);
3323 return false;
3324 }
3325
3326 /* Frees the current transaction and the underlying IDL and then calls
3327 * exit(status).
3328 *
3329 * Freeing the transaction and the IDL is not strictly necessary, but it makes
3330 * for a clean memory leak report from valgrind in the normal case. That makes
3331 * it easier to notice real memory leaks. */
3332 static void
3333 nbctl_exit(int status)
3334 {
3335 if (the_idl_txn) {
3336 ovsdb_idl_txn_abort(the_idl_txn);
3337 ovsdb_idl_txn_destroy(the_idl_txn);
3338 }
3339 ovsdb_idl_destroy(the_idl);
3340 exit(status);
3341 }
3342
3343 static const struct ctl_command_syntax nbctl_commands[] = {
3344 { "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW },
3345 { "sync", 0, 0, "", nbctl_pre_sync, nbctl_sync, NULL, "", RO },
3346 { "show", 0, 1, "[SWITCH]", NULL, nbctl_show, NULL, "", RO },
3347
3348 /* logical switch commands. */
3349 { "ls-add", 0, 1, "[SWITCH]", NULL, nbctl_ls_add, NULL,
3350 "--may-exist,--add-duplicate", RW },
3351 { "ls-del", 1, 1, "SWITCH", NULL, nbctl_ls_del, NULL, "--if-exists", RW },
3352 { "ls-list", 0, 0, "", NULL, nbctl_ls_list, NULL, "", RO },
3353
3354 /* acl commands. */
3355 { "acl-add", 5, 5, "SWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
3356 nbctl_acl_add, NULL, "--log,--may-exist", RW },
3357 { "acl-del", 1, 4, "SWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
3358 nbctl_acl_del, NULL, "", RW },
3359 { "acl-list", 1, 1, "SWITCH", NULL, nbctl_acl_list, NULL, "", RO },
3360
3361 /* logical switch port commands. */
3362 { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add,
3363 NULL, "--may-exist", RW },
3364 { "lsp-del", 1, 1, "PORT", NULL, nbctl_lsp_del, NULL, "--if-exists", RW },
3365 { "lsp-list", 1, 1, "SWITCH", NULL, nbctl_lsp_list, NULL, "", RO },
3366 { "lsp-get-parent", 1, 1, "PORT", NULL, nbctl_lsp_get_parent, NULL,
3367 "", RO },
3368 { "lsp-get-tag", 1, 1, "PORT", NULL, nbctl_lsp_get_tag, NULL, "", RO },
3369 { "lsp-set-addresses", 1, INT_MAX, "PORT [ADDRESS]...", NULL,
3370 nbctl_lsp_set_addresses, NULL, "", RW },
3371 { "lsp-get-addresses", 1, 1, "PORT", NULL, nbctl_lsp_get_addresses, NULL,
3372 "", RO },
3373 { "lsp-set-port-security", 0, INT_MAX, "PORT [ADDRS]...", NULL,
3374 nbctl_lsp_set_port_security, NULL, "", RW },
3375 { "lsp-get-port-security", 1, 1, "PORT", NULL,
3376 nbctl_lsp_get_port_security, NULL, "", RO },
3377 { "lsp-get-up", 1, 1, "PORT", NULL, nbctl_lsp_get_up, NULL, "", RO },
3378 { "lsp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lsp_set_enabled,
3379 NULL, "", RW },
3380 { "lsp-get-enabled", 1, 1, "PORT", NULL, nbctl_lsp_get_enabled, NULL,
3381 "", RO },
3382 { "lsp-set-type", 2, 2, "PORT TYPE", NULL, nbctl_lsp_set_type, NULL,
3383 "", RW },
3384 { "lsp-get-type", 1, 1, "PORT", NULL, nbctl_lsp_get_type, NULL, "", RO },
3385 { "lsp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...", NULL,
3386 nbctl_lsp_set_options, NULL, "", RW },
3387 { "lsp-get-options", 1, 1, "PORT", NULL, nbctl_lsp_get_options, NULL,
3388 "", RO },
3389 { "lsp-set-dhcpv4-options", 1, 2, "PORT [DHCP_OPT_UUID]", NULL,
3390 nbctl_lsp_set_dhcpv4_options, NULL, "", RW },
3391 { "lsp-get-dhcpv4-options", 1, 1, "PORT", NULL,
3392 nbctl_lsp_get_dhcpv4_options, NULL, "", RO },
3393
3394 /* logical router commands. */
3395 { "lr-add", 0, 1, "[ROUTER]", NULL, nbctl_lr_add, NULL,
3396 "--may-exist,--add-duplicate", RW },
3397 { "lr-del", 1, 1, "ROUTER", NULL, nbctl_lr_del, NULL, "--if-exists", RW },
3398 { "lr-list", 0, 0, "", NULL, nbctl_lr_list, NULL, "", RO },
3399
3400 /* logical router port commands. */
3401 { "lrp-add", 4, INT_MAX,
3402 "ROUTER PORT MAC NETWORK... [COLUMN[:KEY]=VALUE]...",
3403 NULL, nbctl_lrp_add, NULL, "--may-exist", RW },
3404 { "lrp-del", 1, 1, "PORT", NULL, nbctl_lrp_del, NULL, "--if-exists", RW },
3405 { "lrp-list", 1, 1, "ROUTER", NULL, nbctl_lrp_list, NULL, "", RO },
3406 { "lrp-set-enabled", 2, 2, "PORT STATE", NULL, nbctl_lrp_set_enabled,
3407 NULL, "", RW },
3408 { "lrp-get-enabled", 1, 1, "PORT", NULL, nbctl_lrp_get_enabled,
3409 NULL, "", RO },
3410
3411 /* logical router route commands. */
3412 { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL,
3413 nbctl_lr_route_add, NULL, "--may-exist,--policy=", RW },
3414 { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del,
3415 NULL, "--if-exists", RW },
3416 { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL,
3417 "", RO },
3418
3419 /* NAT commands. */
3420 { "lr-nat-add", 4, 6,
3421 "ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]", NULL,
3422 nbctl_lr_nat_add, NULL, "--may-exist", RW },
3423 { "lr-nat-del", 1, 3, "ROUTER [TYPE [IP]]", NULL,
3424 nbctl_lr_nat_del, NULL, "--if-exists", RW },
3425 { "lr-nat-list", 1, 1, "ROUTER", NULL, nbctl_lr_nat_list, NULL, "", RO },
3426
3427 /* load balancer commands. */
3428 { "lb-add", 3, 4, "LB VIP[:PORT] IP[:PORT]... [PROTOCOL]", NULL,
3429 nbctl_lb_add, NULL, "--may-exist,--add-duplicate", RW },
3430 { "lb-del", 1, 2, "LB [VIP]", NULL, nbctl_lb_del, NULL,
3431 "--if-exists", RW },
3432 { "lb-list", 0, 1, "[LB]", NULL, nbctl_lb_list, NULL, "", RO },
3433 { "lr-lb-add", 2, 2, "ROUTER LB", NULL, nbctl_lr_lb_add, NULL,
3434 "--may-exist", RW },
3435 { "lr-lb-del", 1, 2, "ROUTER [LB]", NULL, nbctl_lr_lb_del, NULL,
3436 "--if-exists", RW },
3437 { "lr-lb-list", 1, 1, "ROUTER", NULL, nbctl_lr_lb_list, NULL,
3438 "", RO },
3439 { "ls-lb-add", 2, 2, "SWITCH LB", NULL, nbctl_ls_lb_add, NULL,
3440 "--may-exist", RW },
3441 { "ls-lb-del", 1, 2, "SWITCH [LB]", NULL, nbctl_ls_lb_del, NULL,
3442 "--if-exists", RW },
3443 { "ls-lb-list", 1, 1, "SWITCH", NULL, nbctl_ls_lb_list, NULL,
3444 "", RO },
3445
3446 /* DHCP_Options commands */
3447 {"dhcp-options-create", 1, INT_MAX, "CIDR [EXTERNAL:IDS]", NULL,
3448 nbctl_dhcp_options_create, NULL, "", RW },
3449 {"dhcp-options-del", 1, 1, "DHCP_OPT_UUID", NULL,
3450 nbctl_dhcp_options_del, NULL, "", RW},
3451 {"dhcp-options-list", 0, 0, "", NULL, nbctl_dhcp_options_list, NULL, "", RO},
3452 {"dhcp-options-set-options", 1, INT_MAX, "DHCP_OPT_UUID KEY=VALUE [KEY=VALUE]...",
3453 NULL, nbctl_dhcp_options_set_options, NULL, "", RW },
3454 {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL,
3455 nbctl_dhcp_options_get_options, NULL, "", RO },
3456
3457 /* Connection commands. */
3458 {"get-connection", 0, 0, "", pre_connection, cmd_get_connection, NULL, "", RO},
3459 {"del-connection", 0, 0, "", pre_connection, cmd_del_connection, NULL, "", RW},
3460 {"set-connection", 1, INT_MAX, "TARGET...", pre_connection, cmd_set_connection,
3461 NULL, "", RW},
3462
3463 /* SSL commands. */
3464 {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
3465 {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
3466 {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl,
3467 cmd_set_ssl, NULL, "--bootstrap", RW},
3468
3469 {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
3470 };
3471
3472 /* Registers nbctl and common db commands. */
3473 static void
3474 nbctl_cmd_init(void)
3475 {
3476 ctl_init(nbrec_table_classes, tables, NULL, nbctl_exit);
3477 ctl_register_commands(nbctl_commands);
3478 }