ovn-nb: Rename Port_Bindings 'macs' column to 'addresses'.
[cascardo/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 "json.h"
27 #include "ovn/lib/ovn-nb-idl.h"
28 #include "poll-loop.h"
29 #include "process.h"
30 #include "smap.h"
31 #include "stream.h"
32 #include "stream-ssl.h"
33 #include "svec.h"
34 #include "table.h"
35 #include "timeval.h"
36 #include "util.h"
37 #include "openvswitch/vlog.h"
38
39 VLOG_DEFINE_THIS_MODULE(nbctl);
40
41 /* --db: The database server to contact. */
42 static const char *db;
43
44 /* --oneline: Write each command's output as a single line? */
45 static bool oneline;
46
47 /* --dry-run: Do not commit any changes. */
48 static bool dry_run;
49
50 /* --timeout: Time to wait for a connection to 'db'. */
51 static int timeout;
52
53 /* Format for table output. */
54 static struct table_style table_style = TABLE_STYLE_DEFAULT;
55
56 /* The IDL we're using and the current transaction, if any.
57  * This is for use by nbctl_exit() only, to allow it to clean up.
58  * Other code should use its context arguments. */
59 static struct ovsdb_idl *the_idl;
60 static struct ovsdb_idl_txn *the_idl_txn;
61 OVS_NO_RETURN static void nbctl_exit(int status);
62
63 static void nbctl_cmd_init(void);
64 OVS_NO_RETURN static void usage(void);
65 static void parse_options(int argc, char *argv[], struct shash *local_options);
66 static const char *nbctl_default_db(void);
67 static void run_prerequisites(struct ctl_command[], size_t n_commands,
68                               struct ovsdb_idl *);
69 static void do_nbctl(const char *args, struct ctl_command *, size_t n,
70                      struct ovsdb_idl *);
71
72 int
73 main(int argc, char *argv[])
74 {
75     extern struct vlog_module VLM_reconnect;
76     struct ovsdb_idl *idl;
77     struct ctl_command *commands;
78     struct shash local_options;
79     unsigned int seqno;
80     size_t n_commands;
81     char *args;
82
83     set_program_name(argv[0]);
84     fatal_ignore_sigpipe();
85     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
86     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
87     nbrec_init();
88
89     nbctl_cmd_init();
90
91     /* Log our arguments.  This is often valuable for debugging systems. */
92     args = process_escape_args(argv);
93     VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG,
94          "Called as %s", args);
95
96     /* Parse command line. */
97     shash_init(&local_options);
98     parse_options(argc, argv, &local_options);
99     commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
100                                   &n_commands);
101
102     if (timeout) {
103         time_alarm(timeout);
104     }
105
106     /* Initialize IDL. */
107     idl = the_idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
108     run_prerequisites(commands, n_commands, idl);
109
110     /* Execute the commands.
111      *
112      * 'seqno' is the database sequence number for which we last tried to
113      * execute our transaction.  There's no point in trying to commit more than
114      * once for any given sequence number, because if the transaction fails
115      * it's because the database changed and we need to obtain an up-to-date
116      * view of the database before we try the transaction again. */
117     seqno = ovsdb_idl_get_seqno(idl);
118     for (;;) {
119         ovsdb_idl_run(idl);
120         if (!ovsdb_idl_is_alive(idl)) {
121             int retval = ovsdb_idl_get_last_error(idl);
122             ctl_fatal("%s: database connection failed (%s)",
123                         db, ovs_retval_to_string(retval));
124         }
125
126         if (seqno != ovsdb_idl_get_seqno(idl)) {
127             seqno = ovsdb_idl_get_seqno(idl);
128             do_nbctl(args, commands, n_commands, idl);
129         }
130
131         if (seqno == ovsdb_idl_get_seqno(idl)) {
132             ovsdb_idl_wait(idl);
133             poll_block();
134         }
135     }
136 }
137
138 static const char *
139 nbctl_default_db(void)
140 {
141     static char *def;
142     if (!def) {
143         def = getenv("OVN_NB_DB");
144         if (!def) {
145             def = ctl_default_db();
146         }
147     }
148     return def;
149 }
150
151 static void
152 parse_options(int argc, char *argv[], struct shash *local_options)
153 {
154     enum {
155         OPT_DB = UCHAR_MAX + 1,
156         OPT_NO_SYSLOG,
157         OPT_DRY_RUN,
158         OPT_ONELINE,
159         OPT_LOCAL,
160         OPT_COMMANDS,
161         OPT_OPTIONS,
162         VLOG_OPTION_ENUMS,
163         TABLE_OPTION_ENUMS
164     };
165     static const struct option global_long_options[] = {
166         {"db", required_argument, NULL, OPT_DB},
167         {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
168         {"dry-run", no_argument, NULL, OPT_DRY_RUN},
169         {"oneline", no_argument, NULL, OPT_ONELINE},
170         {"timeout", required_argument, NULL, 't'},
171         {"help", no_argument, NULL, 'h'},
172         {"commands", no_argument, NULL, OPT_COMMANDS},
173         {"options", no_argument, NULL, OPT_OPTIONS},
174         {"version", no_argument, NULL, 'V'},
175         VLOG_LONG_OPTIONS,
176         STREAM_SSL_LONG_OPTIONS,
177         TABLE_LONG_OPTIONS,
178         {NULL, 0, NULL, 0},
179     };
180     const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
181     char *tmp, *short_options;
182
183     struct option *options;
184     size_t allocated_options;
185     size_t n_options;
186     size_t i;
187
188     tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
189     short_options = xasprintf("+%s", tmp);
190     free(tmp);
191
192     /* We want to parse both global and command-specific options here, but
193      * getopt_long() isn't too convenient for the job.  We copy our global
194      * options into a dynamic array, then append all of the command-specific
195      * options. */
196     options = xmemdup(global_long_options, sizeof global_long_options);
197     allocated_options = ARRAY_SIZE(global_long_options);
198     n_options = n_global_long_options;
199     ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
200     table_style.format = TF_LIST;
201
202     for (;;) {
203         int idx;
204         int c;
205
206         c = getopt_long(argc, argv, short_options, options, &idx);
207         if (c == -1) {
208             break;
209         }
210
211         switch (c) {
212         case OPT_DB:
213             db = optarg;
214             break;
215
216         case OPT_ONELINE:
217             oneline = true;
218             break;
219
220         case OPT_NO_SYSLOG:
221             vlog_set_levels(&VLM_nbctl, VLF_SYSLOG, VLL_WARN);
222             break;
223
224         case OPT_DRY_RUN:
225             dry_run = true;
226             break;
227
228         case OPT_LOCAL:
229             if (shash_find(local_options, options[idx].name)) {
230                 ctl_fatal("'%s' option specified multiple times",
231                             options[idx].name);
232             }
233             shash_add_nocopy(local_options,
234                              xasprintf("--%s", options[idx].name),
235                              optarg ? xstrdup(optarg) : NULL);
236             break;
237
238         case 'h':
239             usage();
240             exit(EXIT_SUCCESS);
241
242         case OPT_COMMANDS:
243             ctl_print_commands();
244
245         case OPT_OPTIONS:
246             ctl_print_options(global_long_options);
247
248         case 'V':
249             ovs_print_version(0, 0);
250             printf("DB Schema %s\n", nbrec_get_db_version());
251             exit(EXIT_SUCCESS);
252
253         case 't':
254             timeout = strtoul(optarg, NULL, 10);
255             if (timeout < 0) {
256                 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
257             }
258             break;
259
260         VLOG_OPTION_HANDLERS
261         TABLE_OPTION_HANDLERS(&table_style)
262         STREAM_SSL_OPTION_HANDLERS
263
264         case '?':
265             exit(EXIT_FAILURE);
266
267         default:
268             abort();
269         }
270     }
271
272     if (!db) {
273         db = nbctl_default_db();
274     }
275
276     for (i = n_global_long_options; options[i].name; i++) {
277         free(CONST_CAST(char *, options[i].name));
278     }
279     free(options);
280 }
281
282 static void
283 usage(void)
284 {
285     printf("\
286 %s: OVN northbound DB management utility\n\
287 usage: %s [OPTIONS] COMMAND [ARG...]\n\
288 \n\
289 General commands:\n\
290   show                      print overview of database contents\n\
291   show LSWITCH              print overview of database contents for LSWITCH\n\
292 \n\
293 Logical switch commands:\n\
294   lswitch-add [LSWITCH]     create a logical switch named LSWITCH\n\
295   lswitch-del LSWITCH       delete LSWITCH and all its ports\n\
296   lswitch-list              print the names of all logical switches\n\
297 \n\
298 ACL commands:\n\
299   acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
300                             add an ACL to LSWITCH\n\
301   acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\
302                             remove ACLs from LSWITCH\n\
303   acl-list LSWITCH          print ACLs for LSWITCH\n\
304 \n\
305 Logical port commands:\n\
306   lport-add LSWITCH LPORT   add logical port LPORT on LSWITCH\n\
307   lport-add LSWITCH LPORT PARENT TAG\n\
308                             add logical port LPORT on LSWITCH with PARENT\n\
309                             on TAG\n\
310   lport-del LPORT           delete LPORT from its attached switch\n\
311   lport-list LSWITCH        print the names of all logical ports on LSWITCH\n\
312   lport-get-parent LPORT    get the parent of LPORT if set\n\
313   lport-get-tag LPORT       get the LPORT's tag if set\n\
314   lport-set-addresses LPORT [ADDRESS]...\n\
315                             set addresses for LPORT.\n\
316   lport-get-addresses LPORT      get a list of MAC addresses on LPORT\n\
317   lport-set-port-security LPORT [ADDRS]...\n\
318                             set port security addresses for LPORT.\n\
319   lport-get-port-security LPORT    get LPORT's port security addresses\n\
320   lport-get-up LPORT        get state of LPORT ('up' or 'down')\n\
321   lport-set-enabled LPORT STATE\n\
322                             set administrative state LPORT\n\
323                             ('enabled' or 'disabled')\n\
324   lport-get-enabled LPORT   get administrative state LPORT\n\
325                             ('enabled' or 'disabled')\n\
326   lport-set-type LPORT TYPE Set the type for LPORT\n\
327   lport-get-type LPORT      Get the type for LPORT\n\
328   lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
329                             Set options related to the type of LPORT\n\
330   lport-get-options LPORT   Get the type specific options for LPORT\n\
331 \n\
332 Options:\n\
333   --db=DATABASE               connect to DATABASE\n\
334                               (default: %s)\n\
335   -t, --timeout=SECS          wait at most SECS seconds\n\
336   --dry-run                   do not commit changes to database\n\
337   --oneline                   print exactly one line of output per command\n",
338            program_name, program_name, nbctl_default_db());
339     vlog_usage();
340     printf("\
341   --no-syslog             equivalent to --verbose=nbctl:syslog:warn\n");
342     printf("\n\
343 Other options:\n\
344   -h, --help                  display this help message\n\
345   -V, --version               display version information\n");
346     exit(EXIT_SUCCESS);
347 }
348 \f
349 static const struct nbrec_logical_switch *
350 lswitch_by_name_or_uuid(struct ctl_context *ctx, const char *id)
351 {
352     const struct nbrec_logical_switch *lswitch = NULL;
353     bool is_uuid = false;
354     bool duplicate = false;
355     struct uuid lswitch_uuid;
356
357     if (uuid_from_string(&lswitch_uuid, id)) {
358         is_uuid = true;
359         lswitch = nbrec_logical_switch_get_for_uuid(ctx->idl,
360                                                     &lswitch_uuid);
361     }
362
363     if (!lswitch) {
364         const struct nbrec_logical_switch *iter;
365
366         NBREC_LOGICAL_SWITCH_FOR_EACH(iter, ctx->idl) {
367             if (strcmp(iter->name, id)) {
368                 continue;
369             }
370             if (lswitch) {
371                 VLOG_WARN("There is more than one logical switch named '%s'. "
372                         "Use a UUID.", id);
373                 lswitch = NULL;
374                 duplicate = true;
375                 break;
376             }
377             lswitch = iter;
378         }
379     }
380
381     if (!lswitch && !duplicate) {
382         VLOG_WARN("lswitch not found for %s: '%s'",
383                 is_uuid ? "UUID" : "name", id);
384     }
385
386     return lswitch;
387 }
388
389 static void
390 print_lswitch(const struct nbrec_logical_switch *lswitch, struct ds *s)
391 {
392     ds_put_format(s, "    lswitch "UUID_FMT" (%s)\n",
393                   UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
394
395     for (size_t i = 0; i < lswitch->n_ports; i++) {
396         const struct nbrec_logical_port *lport = lswitch->ports[i];
397
398         ds_put_format(s, "        lport %s\n", lport->name);
399         if (lport->parent_name) {
400             ds_put_format(s, "            parent: %s\n", lport->parent_name);
401         }
402         if (lport->n_tag) {
403             ds_put_format(s, "            tag: %"PRIu64"\n", lport->tag[0]);
404         }
405         if (lport->n_addresses) {
406             ds_put_cstr(s, "            addresses:");
407             for (size_t j = 0; j < lport->n_addresses; j++) {
408                 ds_put_format(s, " %s", lport->addresses[j]);
409             }
410             ds_put_char(s, '\n');
411         }
412     }
413 }
414
415 static void
416 nbctl_show(struct ctl_context *ctx)
417 {
418     const struct nbrec_logical_switch *lswitch;
419
420     if (ctx->argc == 2) {
421         lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
422         if (lswitch) {
423             print_lswitch(lswitch, &ctx->output);
424         }
425     } else {
426         NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
427             print_lswitch(lswitch, &ctx->output);
428         }
429     }
430 }
431
432 static void
433 nbctl_lswitch_add(struct ctl_context *ctx)
434 {
435     struct nbrec_logical_switch *lswitch;
436
437     lswitch = nbrec_logical_switch_insert(ctx->txn);
438     if (ctx->argc == 2) {
439         nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
440     }
441 }
442
443 static void
444 nbctl_lswitch_del(struct ctl_context *ctx)
445 {
446     const char *id = ctx->argv[1];
447     const struct nbrec_logical_switch *lswitch;
448
449     lswitch = lswitch_by_name_or_uuid(ctx, id);
450     if (!lswitch) {
451         return;
452     }
453
454     nbrec_logical_switch_delete(lswitch);
455 }
456
457 static void
458 nbctl_lswitch_list(struct ctl_context *ctx)
459 {
460     const struct nbrec_logical_switch *lswitch;
461     struct smap lswitches;
462
463     smap_init(&lswitches);
464     NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, ctx->idl) {
465         smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
466                         UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
467     }
468     const struct smap_node **nodes = smap_sort(&lswitches);
469     for (size_t i = 0; i < smap_count(&lswitches); i++) {
470         const struct smap_node *node = nodes[i];
471         ds_put_format(&ctx->output, "%s\n", node->value);
472     }
473     smap_destroy(&lswitches);
474     free(nodes);
475 }
476 \f
477 static const struct nbrec_logical_port *
478 lport_by_name_or_uuid(struct ctl_context *ctx, const char *id)
479 {
480     const struct nbrec_logical_port *lport = NULL;
481     bool is_uuid = false;
482     struct uuid lport_uuid;
483
484     if (uuid_from_string(&lport_uuid, id)) {
485         is_uuid = true;
486         lport = nbrec_logical_port_get_for_uuid(ctx->idl, &lport_uuid);
487     }
488
489     if (!lport) {
490         NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->idl) {
491             if (!strcmp(lport->name, id)) {
492                 break;
493             }
494         }
495     }
496
497     if (!lport) {
498         VLOG_WARN("lport not found for %s: '%s'",
499                 is_uuid ? "UUID" : "name", id);
500     }
501
502     return lport;
503 }
504
505 static void
506 nbctl_lport_add(struct ctl_context *ctx)
507 {
508     struct nbrec_logical_port *lport;
509     const struct nbrec_logical_switch *lswitch;
510     int64_t tag;
511
512     lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
513     if (!lswitch) {
514         return;
515     }
516
517     if (ctx->argc != 3 && ctx->argc != 5) {
518         /* If a parent_name is specified, a tag must be specified as well. */
519         VLOG_WARN("Invalid arguments to lport-add.");
520         return;
521     }
522
523     if (ctx->argc == 5) {
524         /* Validate tag. */
525         if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
526             VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
527             return;
528         }
529     }
530
531     /* Create the logical port. */
532     lport = nbrec_logical_port_insert(ctx->txn);
533     nbrec_logical_port_set_name(lport, ctx->argv[2]);
534     if (ctx->argc == 5) {
535         nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
536         nbrec_logical_port_set_tag(lport, &tag, 1);
537     }
538
539     /* Insert the logical port into the logical switch. */
540     nbrec_logical_switch_verify_ports(lswitch);
541     struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
542                                                     (lswitch->n_ports + 1));
543     memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
544     new_ports[lswitch->n_ports] = lport;
545     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
546     free(new_ports);
547 }
548
549 /* Removes lport 'lswitch->ports[idx]'. */
550 static void
551 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
552 {
553     const struct nbrec_logical_port *lport = lswitch->ports[idx];
554
555     /* First remove 'lport' from the array of ports.  This is what will
556      * actually cause the logical port to be deleted when the transaction is
557      * sent to the database server (due to garbage collection). */
558     struct nbrec_logical_port **new_ports
559         = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
560     new_ports[idx] = new_ports[lswitch->n_ports - 1];
561     nbrec_logical_switch_verify_ports(lswitch);
562     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
563     free(new_ports);
564
565     /* Delete 'lport' from the IDL.  This won't have a real effect on the
566      * database server (the IDL will suppress it in fact) but it means that it
567      * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
568     nbrec_logical_port_delete(lport);
569 }
570
571 static void
572 nbctl_lport_del(struct ctl_context *ctx)
573 {
574     const struct nbrec_logical_port *lport;
575
576     lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
577     if (!lport) {
578         return;
579     }
580
581     /* Find the switch that contains 'lport', then delete it. */
582     const struct nbrec_logical_switch *lswitch;
583     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->idl) {
584         for (size_t i = 0; i < lswitch->n_ports; i++) {
585             if (lswitch->ports[i] == lport) {
586                 remove_lport(lswitch, i);
587                 return;
588             }
589         }
590     }
591
592     VLOG_WARN("logical port %s is not part of any logical switch",
593               ctx->argv[1]);
594 }
595
596 static void
597 nbctl_lport_list(struct ctl_context *ctx)
598 {
599     const char *id = ctx->argv[1];
600     const struct nbrec_logical_switch *lswitch;
601     struct smap lports;
602     size_t i;
603
604     lswitch = lswitch_by_name_or_uuid(ctx, id);
605     if (!lswitch) {
606         return;
607     }
608
609     smap_init(&lports);
610     for (i = 0; i < lswitch->n_ports; i++) {
611         const struct nbrec_logical_port *lport = lswitch->ports[i];
612         smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
613                         UUID_ARGS(&lport->header_.uuid), lport->name);
614     }
615     const struct smap_node **nodes = smap_sort(&lports);
616     for (i = 0; i < smap_count(&lports); i++) {
617         const struct smap_node *node = nodes[i];
618         ds_put_format(&ctx->output, "%s\n", node->value);
619     }
620     smap_destroy(&lports);
621     free(nodes);
622 }
623
624 static void
625 nbctl_lport_get_parent(struct ctl_context *ctx)
626 {
627     const struct nbrec_logical_port *lport;
628
629     lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
630     if (!lport) {
631         return;
632     }
633
634     if (lport->parent_name) {
635         ds_put_format(&ctx->output, "%s\n", lport->parent_name);
636     }
637 }
638
639 static void
640 nbctl_lport_get_tag(struct ctl_context *ctx)
641 {
642     const struct nbrec_logical_port *lport;
643
644     lport = lport_by_name_or_uuid(ctx, ctx->argv[1]);
645     if (!lport) {
646         return;
647     }
648
649     if (lport->n_tag > 0) {
650         ds_put_format(&ctx->output, "%"PRId64"\n", lport->tag[0]);
651     }
652 }
653
654 static void
655 nbctl_lport_set_addresses(struct ctl_context *ctx)
656 {
657     const char *id = ctx->argv[1];
658     const struct nbrec_logical_port *lport;
659
660     lport = lport_by_name_or_uuid(ctx, id);
661     if (!lport) {
662         return;
663     }
664
665     nbrec_logical_port_set_addresses(lport,
666             (const char **) ctx->argv + 2, ctx->argc - 2);
667 }
668
669 static void
670 nbctl_lport_get_addresses(struct ctl_context *ctx)
671 {
672     const char *id = ctx->argv[1];
673     const struct nbrec_logical_port *lport;
674     struct svec addresses;
675     const char *mac;
676     size_t i;
677
678     lport = lport_by_name_or_uuid(ctx, id);
679     if (!lport) {
680         return;
681     }
682
683     svec_init(&addresses);
684     for (i = 0; i < lport->n_addresses; i++) {
685         svec_add(&addresses, lport->addresses[i]);
686     }
687     svec_sort(&addresses);
688     SVEC_FOR_EACH(i, mac, &addresses) {
689         ds_put_format(&ctx->output, "%s\n", mac);
690     }
691     svec_destroy(&addresses);
692 }
693
694 static void
695 nbctl_lport_set_port_security(struct ctl_context *ctx)
696 {
697     const char *id = ctx->argv[1];
698     const struct nbrec_logical_port *lport;
699
700     lport = lport_by_name_or_uuid(ctx, id);
701     if (!lport) {
702         return;
703     }
704
705     nbrec_logical_port_set_port_security(lport,
706             (const char **) ctx->argv + 2, ctx->argc - 2);
707 }
708
709 static void
710 nbctl_lport_get_port_security(struct ctl_context *ctx)
711 {
712     const char *id = ctx->argv[1];
713     const struct nbrec_logical_port *lport;
714     struct svec addrs;
715     const char *addr;
716     size_t i;
717
718     lport = lport_by_name_or_uuid(ctx, id);
719     if (!lport) {
720         return;
721     }
722
723     svec_init(&addrs);
724     for (i = 0; i < lport->n_port_security; i++) {
725         svec_add(&addrs, lport->port_security[i]);
726     }
727     svec_sort(&addrs);
728     SVEC_FOR_EACH(i, addr, &addrs) {
729         ds_put_format(&ctx->output, "%s\n", addr);
730     }
731     svec_destroy(&addrs);
732 }
733
734 static void
735 nbctl_lport_get_up(struct ctl_context *ctx)
736 {
737     const char *id = ctx->argv[1];
738     const struct nbrec_logical_port *lport;
739
740     lport = lport_by_name_or_uuid(ctx, id);
741     if (!lport) {
742         return;
743     }
744
745     ds_put_format(&ctx->output,
746                   "%s\n", (lport->up && *lport->up) ? "up" : "down");
747 }
748
749 static void
750 nbctl_lport_set_enabled(struct ctl_context *ctx)
751 {
752     const char *id = ctx->argv[1];
753     const char *state = ctx->argv[2];
754     const struct nbrec_logical_port *lport;
755
756     lport = lport_by_name_or_uuid(ctx, id);
757     if (!lport) {
758         return;
759     }
760
761     if (!strcasecmp(state, "enabled")) {
762         bool enabled = true;
763         nbrec_logical_port_set_enabled(lport, &enabled, 1);
764     } else if (!strcasecmp(state, "disabled")) {
765         bool enabled = false;
766         nbrec_logical_port_set_enabled(lport, &enabled, 1);
767     } else {
768         VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
769     }
770 }
771
772 static void
773 nbctl_lport_get_enabled(struct ctl_context *ctx)
774 {
775     const char *id = ctx->argv[1];
776     const struct nbrec_logical_port *lport;
777
778     lport = lport_by_name_or_uuid(ctx, id);
779     if (!lport) {
780         return;
781     }
782
783     ds_put_format(&ctx->output, "%s\n",
784                   !lport->enabled || *lport->enabled ? "enabled" : "disabled");
785 }
786
787 static void
788 nbctl_lport_set_type(struct ctl_context *ctx)
789 {
790     const char *id = ctx->argv[1];
791     const char *type = ctx->argv[2];
792     const struct nbrec_logical_port *lport;
793
794     lport = lport_by_name_or_uuid(ctx, id);
795     if (!lport) {
796         return;
797     }
798
799     nbrec_logical_port_set_type(lport, type);
800 }
801
802 static void
803 nbctl_lport_get_type(struct ctl_context *ctx)
804 {
805     const char *id = ctx->argv[1];
806     const struct nbrec_logical_port *lport;
807
808     lport = lport_by_name_or_uuid(ctx, id);
809     if (!lport) {
810         return;
811     }
812
813     ds_put_format(&ctx->output, "%s\n", lport->type);
814 }
815
816 static void
817 nbctl_lport_set_options(struct ctl_context *ctx)
818 {
819     const char *id = ctx->argv[1];
820     const struct nbrec_logical_port *lport;
821     size_t i;
822     struct smap options = SMAP_INITIALIZER(&options);
823
824     lport = lport_by_name_or_uuid(ctx, id);
825     if (!lport) {
826         return;
827     }
828
829     for (i = 2; i < ctx->argc; i++) {
830         char *key, *value;
831         value = xstrdup(ctx->argv[i]);
832         key = strsep(&value, "=");
833         if (value) {
834             smap_add(&options, key, value);
835         }
836         free(key);
837     }
838
839     nbrec_logical_port_set_options(lport, &options);
840
841     smap_destroy(&options);
842 }
843
844 static void
845 nbctl_lport_get_options(struct ctl_context *ctx)
846 {
847     const char *id = ctx->argv[1];
848     const struct nbrec_logical_port *lport;
849     struct smap_node *node;
850
851     lport = lport_by_name_or_uuid(ctx, id);
852     if (!lport) {
853         return;
854     }
855
856     SMAP_FOR_EACH(node, &lport->options) {
857         ds_put_format(&ctx->output, "%s=%s\n", node->key, node->value);
858     }
859 }
860
861 enum {
862     DIR_FROM_LPORT,
863     DIR_TO_LPORT
864 };
865
866 static int
867 dir_encode(const char *dir)
868 {
869     if (!strcmp(dir, "from-lport")) {
870         return DIR_FROM_LPORT;
871     } else if (!strcmp(dir, "to-lport")) {
872         return DIR_TO_LPORT;
873     }
874
875     OVS_NOT_REACHED();
876 }
877
878 static int
879 acl_cmp(const void *acl1_, const void *acl2_)
880 {
881     const struct nbrec_acl *const *acl1p = acl1_;
882     const struct nbrec_acl *const *acl2p = acl2_;
883     const struct nbrec_acl *acl1 = *acl1p;
884     const struct nbrec_acl *acl2 = *acl2p;
885
886     int dir1 = dir_encode(acl1->direction);
887     int dir2 = dir_encode(acl2->direction);
888
889     if (dir1 != dir2) {
890         return dir1 < dir2 ? -1 : 1;
891     } else if (acl1->priority != acl2->priority) {
892         return acl1->priority > acl2->priority ? -1 : 1;
893     } else {
894         return strcmp(acl1->match, acl2->match);
895     }
896 }
897
898 static void
899 nbctl_acl_list(struct ctl_context *ctx)
900 {
901     const struct nbrec_logical_switch *lswitch;
902     const struct nbrec_acl **acls;
903     size_t i;
904
905     lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
906     if (!lswitch) {
907         return;
908     }
909
910     acls = xmalloc(sizeof *acls * lswitch->n_acls);
911     for (i = 0; i < lswitch->n_acls; i++) {
912         acls[i] = lswitch->acls[i];
913     }
914
915     qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
916
917     for (i = 0; i < lswitch->n_acls; i++) {
918         const struct nbrec_acl *acl = acls[i];
919         printf("%10s %5"PRId64" (%s) %s%s\n", acl->direction, acl->priority,
920                 acl->match, acl->action, acl->log ? " log" : "");
921     }
922
923     free(acls);
924 }
925
926 static void
927 nbctl_acl_add(struct ctl_context *ctx)
928 {
929     const struct nbrec_logical_switch *lswitch;
930     const char *action = ctx->argv[5];
931     const char *direction;
932     int64_t priority;
933
934     lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
935     if (!lswitch) {
936         return;
937     }
938
939     /* Validate direction.  Only require the first letter. */
940     if (ctx->argv[2][0] == 't') {
941         direction = "to-lport";
942     } else if (ctx->argv[2][0] == 'f') {
943         direction = "from-lport";
944     } else {
945         VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
946         return;
947     }
948
949     /* Validate priority. */
950     if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
951         || priority > 65535) {
952         VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
953         return;
954     }
955
956     /* Validate action. */
957     if (strcmp(action, "allow") && strcmp(action, "allow-related")
958         && strcmp(action, "drop") && strcmp(action, "reject")) {
959         VLOG_WARN("Invalid action '%s'", action);
960         return;
961     }
962
963     /* Create the acl. */
964     struct nbrec_acl *acl = nbrec_acl_insert(ctx->txn);
965     nbrec_acl_set_priority(acl, priority);
966     nbrec_acl_set_direction(acl, direction);
967     nbrec_acl_set_match(acl, ctx->argv[4]);
968     nbrec_acl_set_action(acl, action);
969     if (shash_find(&ctx->options, "--log") != NULL) {
970         nbrec_acl_set_log(acl, true);
971     }
972
973     /* Insert the acl into the logical switch. */
974     nbrec_logical_switch_verify_acls(lswitch);
975     struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls *
976                                           (lswitch->n_acls + 1));
977     memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls);
978     new_acls[lswitch->n_acls] = acl;
979     nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1);
980     free(new_acls);
981 }
982
983 static void
984 nbctl_acl_del(struct ctl_context *ctx)
985 {
986     const struct nbrec_logical_switch *lswitch;
987     const char *direction;
988     int64_t priority = 0;
989
990     lswitch = lswitch_by_name_or_uuid(ctx, ctx->argv[1]);
991     if (!lswitch) {
992         return;
993     }
994
995     if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
996         VLOG_WARN("Invalid number of arguments");
997         return;
998     }
999
1000     if (ctx->argc == 2) {
1001         /* If direction, priority, and match are not specified, delete
1002          * all ACLs. */
1003         nbrec_logical_switch_verify_acls(lswitch);
1004         nbrec_logical_switch_set_acls(lswitch, NULL, 0);
1005         return;
1006     }
1007
1008     /* Validate direction.  Only require first letter. */
1009     if (ctx->argv[2][0] == 't') {
1010         direction = "to-lport";
1011     } else if (ctx->argv[2][0] == 'f') {
1012         direction = "from-lport";
1013     } else {
1014         VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
1015         return;
1016     }
1017
1018     /* If priority and match are not specified, delete all ACLs with the
1019      * specified direction. */
1020     if (ctx->argc == 3) {
1021         struct nbrec_acl **new_acls
1022             = xmalloc(sizeof *new_acls * lswitch->n_acls);
1023
1024         int n_acls = 0;
1025         for (size_t i = 0; i < lswitch->n_acls; i++) {
1026             if (strcmp(direction, lswitch->acls[i]->direction)) {
1027                 new_acls[n_acls++] = lswitch->acls[i];
1028             }
1029         }
1030
1031         nbrec_logical_switch_verify_acls(lswitch);
1032         nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
1033         free(new_acls);
1034         return;
1035     }
1036
1037     /* Validate priority. */
1038     if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
1039         || priority > 65535) {
1040         VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
1041         return;
1042     }
1043
1044     /* Remove the matching rule. */
1045     for (size_t i = 0; i < lswitch->n_acls; i++) {
1046         struct nbrec_acl *acl = lswitch->acls[i];
1047
1048         if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
1049              !strcmp(direction, acl->direction)) {
1050             struct nbrec_acl **new_acls
1051                 = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls);
1052             new_acls[i] = lswitch->acls[lswitch->n_acls - 1];
1053             nbrec_logical_switch_verify_acls(lswitch);
1054             nbrec_logical_switch_set_acls(lswitch, new_acls,
1055                                           lswitch->n_acls - 1);
1056             free(new_acls);
1057             return;
1058         }
1059     }
1060 }
1061 \f
1062 static const struct ctl_table_class tables[] = {
1063     {&nbrec_table_logical_switch,
1064      {{&nbrec_table_logical_switch, &nbrec_logical_switch_col_name, NULL},
1065       {NULL, NULL, NULL}}},
1066
1067     {&nbrec_table_logical_port,
1068      {{&nbrec_table_logical_port, &nbrec_logical_port_col_name, NULL},
1069       {NULL, NULL, NULL}}},
1070
1071     {&nbrec_table_acl,
1072      {{NULL, NULL, NULL},
1073       {NULL, NULL, NULL}}},
1074
1075     {&nbrec_table_logical_router,
1076      {{&nbrec_table_logical_router, &nbrec_logical_router_col_name, NULL},
1077       {NULL, NULL, NULL}}},
1078
1079     {&nbrec_table_logical_router_port,
1080      {{&nbrec_table_logical_router_port, &nbrec_logical_router_port_col_name,
1081        NULL},
1082       {NULL, NULL, NULL}}},
1083
1084     {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
1085 };
1086 \f
1087 static void
1088 run_prerequisites(struct ctl_command *commands, size_t n_commands,
1089                   struct ovsdb_idl *idl)
1090 {
1091     struct ctl_command *c;
1092
1093     for (c = commands; c < &commands[n_commands]; c++) {
1094         if (c->syntax->prerequisites) {
1095             struct ctl_context ctx;
1096
1097             ds_init(&c->output);
1098             c->table = NULL;
1099
1100             ctl_context_init(&ctx, c, idl, NULL, NULL, NULL);
1101             (c->syntax->prerequisites)(&ctx);
1102             ctl_context_done(&ctx, c);
1103
1104             ovs_assert(!c->output.string);
1105             ovs_assert(!c->table);
1106         }
1107     }
1108 }
1109
1110 static void
1111 do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands,
1112          struct ovsdb_idl *idl)
1113 {
1114     struct ovsdb_idl_txn *txn;
1115     enum ovsdb_idl_txn_status status;
1116     struct ovsdb_symbol_table *symtab;
1117     struct ctl_context ctx;
1118     struct ctl_command *c;
1119     struct shash_node *node;
1120     char *error = NULL;
1121
1122     txn = the_idl_txn = ovsdb_idl_txn_create(idl);
1123     if (dry_run) {
1124         ovsdb_idl_txn_set_dry_run(txn);
1125     }
1126
1127     ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args);
1128
1129     symtab = ovsdb_symbol_table_create();
1130     for (c = commands; c < &commands[n_commands]; c++) {
1131         ds_init(&c->output);
1132         c->table = NULL;
1133     }
1134     ctl_context_init(&ctx, NULL, idl, txn, symtab, NULL);
1135     for (c = commands; c < &commands[n_commands]; c++) {
1136         ctl_context_init_command(&ctx, c);
1137         if (c->syntax->run) {
1138             (c->syntax->run)(&ctx);
1139         }
1140         ctl_context_done_command(&ctx, c);
1141
1142         if (ctx.try_again) {
1143             ctl_context_done(&ctx, NULL);
1144             goto try_again;
1145         }
1146     }
1147     ctl_context_done(&ctx, NULL);
1148
1149     SHASH_FOR_EACH (node, &symtab->sh) {
1150         struct ovsdb_symbol *symbol = node->data;
1151         if (!symbol->created) {
1152             ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
1153                       "with \"-- --id=%s create ...\")",
1154                       node->name, node->name);
1155         }
1156         if (!symbol->strong_ref) {
1157             if (!symbol->weak_ref) {
1158                 VLOG_WARN("row id \"%s\" was created but no reference to it "
1159                           "was inserted, so it will not actually appear in "
1160                           "the database", node->name);
1161             } else {
1162                 VLOG_WARN("row id \"%s\" was created but only a weak "
1163                           "reference to it was inserted, so it will not "
1164                           "actually appear in the database", node->name);
1165             }
1166         }
1167     }
1168
1169     status = ovsdb_idl_txn_commit_block(txn);
1170     if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
1171         for (c = commands; c < &commands[n_commands]; c++) {
1172             if (c->syntax->postprocess) {
1173                 ctl_context_init(&ctx, c, idl, txn, symtab, NULL);
1174                 (c->syntax->postprocess)(&ctx);
1175                 ctl_context_done(&ctx, c);
1176             }
1177         }
1178     }
1179     error = xstrdup(ovsdb_idl_txn_get_error(txn));
1180
1181     switch (status) {
1182     case TXN_UNCOMMITTED:
1183     case TXN_INCOMPLETE:
1184         OVS_NOT_REACHED();
1185
1186     case TXN_ABORTED:
1187         /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1188         ctl_fatal("transaction aborted");
1189
1190     case TXN_UNCHANGED:
1191     case TXN_SUCCESS:
1192         break;
1193
1194     case TXN_TRY_AGAIN:
1195         goto try_again;
1196
1197     case TXN_ERROR:
1198         ctl_fatal("transaction error: %s", error);
1199
1200     case TXN_NOT_LOCKED:
1201         /* Should not happen--we never call ovsdb_idl_set_lock(). */
1202         ctl_fatal("database not locked");
1203
1204     default:
1205         OVS_NOT_REACHED();
1206     }
1207     free(error);
1208
1209     ovsdb_symbol_table_destroy(symtab);
1210
1211     for (c = commands; c < &commands[n_commands]; c++) {
1212         struct ds *ds = &c->output;
1213
1214         if (c->table) {
1215             table_print(c->table, &table_style);
1216         } else if (oneline) {
1217             size_t j;
1218
1219             ds_chomp(ds, '\n');
1220             for (j = 0; j < ds->length; j++) {
1221                 int ch = ds->string[j];
1222                 switch (ch) {
1223                 case '\n':
1224                     fputs("\\n", stdout);
1225                     break;
1226
1227                 case '\\':
1228                     fputs("\\\\", stdout);
1229                     break;
1230
1231                 default:
1232                     putchar(ch);
1233                 }
1234             }
1235             putchar('\n');
1236         } else {
1237             fputs(ds_cstr(ds), stdout);
1238         }
1239         ds_destroy(&c->output);
1240         table_destroy(c->table);
1241         free(c->table);
1242
1243         shash_destroy_free_data(&c->options);
1244     }
1245     free(commands);
1246     ovsdb_idl_txn_destroy(txn);
1247     ovsdb_idl_destroy(idl);
1248
1249     exit(EXIT_SUCCESS);
1250
1251 try_again:
1252     /* Our transaction needs to be rerun, or a prerequisite was not met.  Free
1253      * resources and return so that the caller can try again. */
1254     if (txn) {
1255         ovsdb_idl_txn_abort(txn);
1256         ovsdb_idl_txn_destroy(txn);
1257         the_idl_txn = NULL;
1258     }
1259     ovsdb_symbol_table_destroy(symtab);
1260     for (c = commands; c < &commands[n_commands]; c++) {
1261         ds_destroy(&c->output);
1262         table_destroy(c->table);
1263         free(c->table);
1264     }
1265     free(error);
1266 }
1267
1268 /* Frees the current transaction and the underlying IDL and then calls
1269  * exit(status).
1270  *
1271  * Freeing the transaction and the IDL is not strictly necessary, but it makes
1272  * for a clean memory leak report from valgrind in the normal case.  That makes
1273  * it easier to notice real memory leaks. */
1274 static void
1275 nbctl_exit(int status)
1276 {
1277     if (the_idl_txn) {
1278         ovsdb_idl_txn_abort(the_idl_txn);
1279         ovsdb_idl_txn_destroy(the_idl_txn);
1280     }
1281     ovsdb_idl_destroy(the_idl);
1282     exit(status);
1283 }
1284
1285 static const struct ctl_command_syntax nbctl_commands[] = {
1286     { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO },
1287
1288     /* lswitch commands. */
1289     { "lswitch-add", 0, 1, "[LSWITCH]", NULL, nbctl_lswitch_add,
1290       NULL, "", RW },
1291     { "lswitch-del", 1, 1, "LSWITCH", NULL, nbctl_lswitch_del,
1292       NULL, "", RW },
1293     { "lswitch-list", 0, 0, "", NULL, nbctl_lswitch_list, NULL, "", RO },
1294
1295     /* acl commands. */
1296     { "acl-add", 5, 5, "LSWITCH DIRECTION PRIORITY MATCH ACTION", NULL,
1297       nbctl_acl_add, NULL, "--log", RW },
1298     { "acl-del", 1, 4, "LSWITCH [DIRECTION [PRIORITY MATCH]]", NULL,
1299       nbctl_acl_del, NULL, "", RW },
1300     { "acl-list", 1, 1, "LSWITCH", NULL, nbctl_acl_list, NULL, "", RO },
1301
1302     /* lport commands. */
1303     { "lport-add", 2, 4, "LSWITCH LPORT [PARENT] [TAG]", NULL, nbctl_lport_add,
1304       NULL, "", RW },
1305     { "lport-del", 1, 1, "LPORT", NULL, nbctl_lport_del, NULL, "", RO },
1306     { "lport-list", 1, 1, "LSWITCH", NULL, nbctl_lport_list, NULL, "", RO },
1307     { "lport-get-parent", 1, 1, "LPORT", NULL, nbctl_lport_get_parent, NULL,
1308       "", RO },
1309     { "lport-get-tag", 1, 1, "LPORT", NULL, nbctl_lport_get_tag, NULL, "",
1310       RO },
1311     { "lport-set-addresses", 1, INT_MAX, "LPORT [ADDRESS]...", NULL,
1312       nbctl_lport_set_addresses, NULL, "", RW },
1313     { "lport-get-addresses", 1, 1, "LPORT", NULL,
1314       nbctl_lport_get_addresses, NULL,
1315       "", RO },
1316     { "lport-set-port-security", 0, INT_MAX, "LPORT [ADDRS]...", NULL,
1317       nbctl_lport_set_port_security, NULL, "", RW },
1318     { "lport-get-port-security", 1, 1, "LPORT", NULL,
1319       nbctl_lport_get_port_security, NULL, "", RO },
1320     { "lport-get-up", 1, 1, "LPORT", NULL, nbctl_lport_get_up, NULL, "", RO },
1321     { "lport-set-enabled", 2, 2, "LPORT STATE", NULL, nbctl_lport_set_enabled,
1322       NULL, "", RW },
1323     { "lport-get-enabled", 1, 1, "LPORT", NULL, nbctl_lport_get_enabled, NULL,
1324       "", RO },
1325     { "lport-set-type", 2, 2, "LPORT TYPE", NULL, nbctl_lport_set_type, NULL,
1326       "", RW },
1327     { "lport-get-type", 1, 1, "LPORT", NULL, nbctl_lport_get_type, NULL, "",
1328       RO },
1329     { "lport-set-options", 1, INT_MAX, "LPORT KEY=VALUE [KEY=VALUE]...", NULL,
1330       nbctl_lport_set_options, NULL, "", RW },
1331     { "lport-get-options", 1, 1, "LPORT", NULL, nbctl_lport_get_options, NULL,
1332       "", RO },
1333
1334     {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
1335 };
1336
1337 /* Registers nbctl and common db commands. */
1338 static void
1339 nbctl_cmd_init(void)
1340 {
1341     ctl_init(tables, NULL, nbctl_exit);
1342     ctl_register_commands(nbctl_commands);
1343 }