ovn-nbctl: Sort output of most commands.
[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 "dirs.h"
24 #include "fatal-signal.h"
25 #include "ovn/lib/ovn-nb-idl.h"
26 #include "poll-loop.h"
27 #include "process.h"
28 #include "smap.h"
29 #include "stream.h"
30 #include "stream-ssl.h"
31 #include "svec.h"
32 #include "util.h"
33 #include "openvswitch/vlog.h"
34
35 VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
36
37 struct nbctl_context {
38     struct ovsdb_idl *idl;
39     struct ovsdb_idl_txn *txn;
40 };
41
42 static const char *db;
43
44 static const char *default_db(void);
45
46 static void
47 usage(void)
48 {
49     printf("\
50 %s: OVN northbound DB management utility\n\
51 usage: %s [OPTIONS] COMMAND [ARG...]\n\
52 \n\
53 General commands:\n\
54   show                      print overview of database contents\n\
55   show LSWITCH              print overview of database contents for LSWITCH\n\
56 \n\
57 Logical switch commands:\n\
58   lswitch-add [LSWITCH]     create a logical switch named LSWITCH\n\
59   lswitch-del LSWITCH       delete LSWITCH and all its ports\n\
60   lswitch-list              print the names of all logical switches\n\
61   lswitch-set-external-id LSWITCH KEY [VALUE]\n\
62                             set or delete an external-id on LSWITCH\n\
63   lswitch-get-external-id LSWITCH [KEY]\n\
64                             list one or all external-ids on LSWITCH\n\
65 \n\
66 Logical port commands:\n\
67   lport-add LSWITCH LPORT   add logical port LPORT on LSWITCH\n\
68   lport-add LSWITCH LPORT PARENT TAG\n\
69                             add logical port LPORT on LSWITCH with PARENT\n\
70                             on TAG\n\
71   lport-del LPORT           delete LPORT from its attached switch\n\
72   lport-list LSWITCH        print the names of all logical ports on LSWITCH\n\
73   lport-get-parent LPORT    get the parent of LPORT if set\n\
74   lport-get-tag LPORT       get the LPORT's tag if set\n\
75   lport-set-external-id LPORT KEY [VALUE]\n\
76                             set or delete an external-id on LPORT\n\
77   lport-get-external-id LPORT [KEY]\n\
78                             list one or all external-ids on LPORT\n\
79   lport-set-macs LPORT [MAC]...\n\
80                             set MAC addresses for LPORT.\n\
81   lport-get-macs LPORT      get a list of MAC addresses on LPORT\n\
82   lport-set-port-security LPORT [ADDRS]...\n\
83                             set port security addresses for LPORT.\n\
84   lport-get-port-security LPORT    get LPORT's port security addresses\n\
85   lport-get-up LPORT        get state of LPORT ('up' or 'down')\n\
86   lport-set-enabled LPORT STATE\n\
87                             set administrative state LPORT\n\
88                             ('enabled' or 'disabled')\n\
89   lport-get-enabled LPORT   get administrative state LPORT\n\
90                             ('enabled' or 'disabled')\n\
91   lport-set-type LPORT TYPE Set the type for LPORT\n\
92   lport-get-type LPORT      Get the type for LPORT\n\
93   lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
94                             Set options related to the type of LPORT\n\
95   lport-get-options LPORT   Get the type specific options for LPORT\n\
96 \n\
97 Options:\n\
98   --db=DATABASE             connect to DATABASE\n\
99                             (default: %s)\n\
100   -h, --help                display this help message\n\
101   -o, --options             list available options\n\
102   -V, --version             display version information\n\
103 ", program_name, program_name, default_db());
104     vlog_usage();
105     stream_usage("database", true, true, false);
106 }
107 \f
108 static const struct nbrec_logical_switch *
109 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
110 {
111     const struct nbrec_logical_switch *lswitch = NULL;
112     bool is_uuid = false;
113     bool duplicate = false;
114     struct uuid lswitch_uuid;
115
116     if (uuid_from_string(&lswitch_uuid, id)) {
117         is_uuid = true;
118         lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
119                                                     &lswitch_uuid);
120     }
121
122     if (!lswitch) {
123         const struct nbrec_logical_switch *iter;
124
125         NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
126             if (strcmp(iter->name, id)) {
127                 continue;
128             }
129             if (lswitch) {
130                 VLOG_WARN("There is more than one logical switch named '%s'. "
131                         "Use a UUID.", id);
132                 lswitch = NULL;
133                 duplicate = true;
134                 break;
135             }
136             lswitch = iter;
137         }
138     }
139
140     if (!lswitch && !duplicate) {
141         VLOG_WARN("lswitch not found for %s: '%s'",
142                 is_uuid ? "UUID" : "name", id);
143     }
144
145     return lswitch;
146 }
147
148 static void
149 print_lswitch(const struct nbrec_logical_switch *lswitch)
150 {
151     printf("    lswitch "UUID_FMT" (%s)\n",
152            UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
153
154     for (size_t i = 0; i < lswitch->n_ports; i++) {
155         const struct nbrec_logical_port *lport = lswitch->ports[i];
156
157         printf("        lport %s\n", lport->name);
158         if (lport->parent_name && lport->n_tag) {
159             printf("            parent: %s, tag:%"PRIu64"\n",
160                    lport->parent_name, lport->tag[0]);
161         }
162         if (lport->n_macs) {
163             printf("            macs:");
164             for (size_t j = 0; j < lport->n_macs; j++) {
165                 printf(" %s", lport->macs[j]);
166             }
167             printf("\n");
168         }
169     }
170 }
171
172 static void
173 do_show(struct ovs_cmdl_context *ctx)
174 {
175     struct nbctl_context *nb_ctx = ctx->pvt;
176     const struct nbrec_logical_switch *lswitch;
177
178     if (ctx->argc == 2) {
179         lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
180         if (lswitch) {
181             print_lswitch(lswitch);
182         }
183     } else {
184         NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
185             print_lswitch(lswitch);
186         }
187     }
188 }
189
190 static void
191 do_lswitch_add(struct ovs_cmdl_context *ctx)
192 {
193     struct nbctl_context *nb_ctx = ctx->pvt;
194     struct nbrec_logical_switch *lswitch;
195
196     lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
197     if (ctx->argc == 2) {
198         nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
199     }
200 }
201
202 static void
203 do_lswitch_del(struct ovs_cmdl_context *ctx)
204 {
205     struct nbctl_context *nb_ctx = ctx->pvt;
206     const char *id = ctx->argv[1];
207     const struct nbrec_logical_switch *lswitch;
208
209     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
210     if (!lswitch) {
211         return;
212     }
213
214     nbrec_logical_switch_delete(lswitch);
215 }
216
217 static void
218 do_lswitch_list(struct ovs_cmdl_context *ctx)
219 {
220     struct nbctl_context *nb_ctx = ctx->pvt;
221     const struct nbrec_logical_switch *lswitch;
222     struct smap lswitches;
223
224     smap_init(&lswitches);
225     NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
226         smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
227                         UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
228     }
229     const struct smap_node **nodes = smap_sort(&lswitches);
230     for (size_t i = 0; i < smap_count(&lswitches); i++) {
231         const struct smap_node *node = nodes[i];
232         printf("%s\n", node->value);
233     }
234     smap_destroy(&lswitches);
235     free(nodes);
236 }
237
238 static void
239 do_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
240 {
241     struct nbctl_context *nb_ctx = ctx->pvt;
242     const char *id = ctx->argv[1];
243     const struct nbrec_logical_switch *lswitch;
244     struct smap new_external_ids;
245
246     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
247     if (!lswitch) {
248         return;
249     }
250
251     smap_init(&new_external_ids);
252     smap_clone(&new_external_ids, &lswitch->external_ids);
253     if (ctx->argc == 4) {
254         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
255     } else {
256         smap_remove(&new_external_ids, ctx->argv[2]);
257     }
258     nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
259     smap_destroy(&new_external_ids);
260 }
261
262 static void
263 do_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
264 {
265     struct nbctl_context *nb_ctx = ctx->pvt;
266     const char *id = ctx->argv[1];
267     const struct nbrec_logical_switch *lswitch;
268
269     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
270     if (!lswitch) {
271         return;
272     }
273
274     if (ctx->argc == 3) {
275         const char *key = ctx->argv[2];
276         const char *value;
277
278         /* List one external ID */
279
280         value = smap_get(&lswitch->external_ids, key);
281         if (value) {
282             printf("%s\n", value);
283         }
284     } else {
285         struct smap_node *node;
286
287         /* List all external IDs */
288
289         SMAP_FOR_EACH(node, &lswitch->external_ids) {
290             printf("%s=%s\n", node->key, node->value);
291         }
292     }
293 }
294 \f
295 static const struct nbrec_logical_port *
296 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
297 {
298     const struct nbrec_logical_port *lport = NULL;
299     bool is_uuid = false;
300     struct uuid lport_uuid;
301
302     if (uuid_from_string(&lport_uuid, id)) {
303         is_uuid = true;
304         lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
305     }
306
307     if (!lport) {
308         NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
309             if (!strcmp(lport->name, id)) {
310                 break;
311             }
312         }
313     }
314
315     if (!lport) {
316         VLOG_WARN("lport not found for %s: '%s'",
317                 is_uuid ? "UUID" : "name", id);
318     }
319
320     return lport;
321 }
322
323 static void
324 do_lport_add(struct ovs_cmdl_context *ctx)
325 {
326     struct nbctl_context *nb_ctx = ctx->pvt;
327     struct nbrec_logical_port *lport;
328     const struct nbrec_logical_switch *lswitch;
329     int64_t tag;
330
331     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
332     if (!lswitch) {
333         return;
334     }
335
336     if (ctx->argc != 3 && ctx->argc != 5) {
337         /* If a parent_name is specified, a tag must be specified as well. */
338         VLOG_WARN("Invalid arguments to lport-add.");
339         return;
340     }
341
342     if (ctx->argc == 5) {
343         /* Validate tag. */
344         if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
345             VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
346             return;
347         }
348     }
349
350     /* Create the logical port. */
351     lport = nbrec_logical_port_insert(nb_ctx->txn);
352     nbrec_logical_port_set_name(lport, ctx->argv[2]);
353     if (ctx->argc == 5) {
354         nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
355         nbrec_logical_port_set_tag(lport, &tag, 1);
356     }
357
358     /* Insert the logical port into the logical switch. */
359     nbrec_logical_switch_verify_ports(lswitch);
360     struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
361                                                     (lswitch->n_ports + 1));
362     memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
363     new_ports[lswitch->n_ports] = lport;
364     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
365     free(new_ports);
366 }
367
368 /* Removes lport 'lswitch->ports[idx]'. */
369 static void
370 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
371 {
372     const struct nbrec_logical_port *lport = lswitch->ports[idx];
373
374     /* First remove 'lport' from the array of ports.  This is what will
375      * actually cause the logical port to be deleted when the transaction is
376      * sent to the database server (due to garbage collection). */
377     struct nbrec_logical_port **new_ports
378         = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
379     new_ports[idx] = new_ports[lswitch->n_ports - 1];
380     nbrec_logical_switch_verify_ports(lswitch);
381     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
382     free(new_ports);
383
384     /* Delete 'lport' from the IDL.  This won't have a real effect on the
385      * database server (the IDL will suppress it in fact) but it means that it
386      * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
387     nbrec_logical_port_delete(lport);
388 }
389
390 static void
391 do_lport_del(struct ovs_cmdl_context *ctx)
392 {
393     struct nbctl_context *nb_ctx = ctx->pvt;
394     const struct nbrec_logical_port *lport;
395
396     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
397     if (!lport) {
398         return;
399     }
400
401     /* Find the switch that contains 'lport', then delete it. */
402     const struct nbrec_logical_switch *lswitch;
403     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) {
404         for (size_t i = 0; i < lswitch->n_ports; i++) {
405             if (lswitch->ports[i] == lport) {
406                 remove_lport(lswitch, i);
407                 return;
408             }
409         }
410     }
411
412     VLOG_WARN("logical port %s is not part of any logical switch",
413               ctx->argv[1]);
414 }
415
416 static void
417 do_lport_list(struct ovs_cmdl_context *ctx)
418 {
419     struct nbctl_context *nb_ctx = ctx->pvt;
420     const char *id = ctx->argv[1];
421     const struct nbrec_logical_switch *lswitch;
422     struct smap lports;
423     size_t i;
424
425     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
426     if (!lswitch) {
427         return;
428     }
429
430     smap_init(&lports);
431     for (i = 0; i < lswitch->n_ports; i++) {
432         const struct nbrec_logical_port *lport = lswitch->ports[i];
433         smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
434                         UUID_ARGS(&lport->header_.uuid), lport->name);
435     }
436     const struct smap_node **nodes = smap_sort(&lports);
437     for (i = 0; i < smap_count(&lports); i++) {
438         const struct smap_node *node = nodes[i];
439         printf("%s\n", node->value);
440     }
441     smap_destroy(&lports);
442     free(nodes);
443 }
444
445 static void
446 do_lport_get_parent(struct ovs_cmdl_context *ctx)
447 {
448     struct nbctl_context *nb_ctx = ctx->pvt;
449     const struct nbrec_logical_port *lport;
450
451     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
452     if (!lport) {
453         return;
454     }
455
456     if (lport->parent_name) {
457         printf("%s\n", lport->parent_name);
458     }
459 }
460
461 static void
462 do_lport_get_tag(struct ovs_cmdl_context *ctx)
463 {
464     struct nbctl_context *nb_ctx = ctx->pvt;
465     const struct nbrec_logical_port *lport;
466
467     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
468     if (!lport) {
469         return;
470     }
471
472     if (lport->n_tag > 0) {
473         printf("%"PRId64"\n", lport->tag[0]);
474     }
475 }
476
477 static void
478 do_lport_set_external_id(struct ovs_cmdl_context *ctx)
479 {
480     struct nbctl_context *nb_ctx = ctx->pvt;
481     const char *id = ctx->argv[1];
482     const struct nbrec_logical_port *lport;
483     struct smap new_external_ids;
484
485     lport = lport_by_name_or_uuid(nb_ctx, id);
486     if (!lport) {
487         return;
488     }
489
490     smap_init(&new_external_ids);
491     smap_clone(&new_external_ids, &lport->external_ids);
492     if (ctx->argc == 4) {
493         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
494     } else {
495         smap_remove(&new_external_ids, ctx->argv[2]);
496     }
497     nbrec_logical_port_set_external_ids(lport, &new_external_ids);
498     smap_destroy(&new_external_ids);
499 }
500
501 static void
502 do_lport_get_external_id(struct ovs_cmdl_context *ctx)
503 {
504     struct nbctl_context *nb_ctx = ctx->pvt;
505     const char *id = ctx->argv[1];
506     const struct nbrec_logical_port *lport;
507
508     lport = lport_by_name_or_uuid(nb_ctx, id);
509     if (!lport) {
510         return;
511     }
512
513     if (ctx->argc == 3) {
514         const char *key = ctx->argv[2];
515         const char *value;
516
517         /* List one external ID */
518
519         value = smap_get(&lport->external_ids, key);
520         if (value) {
521             printf("%s\n", value);
522         }
523     } else {
524         struct smap_node *node;
525
526         /* List all external IDs */
527
528         SMAP_FOR_EACH(node, &lport->external_ids) {
529             printf("%s=%s\n", node->key, node->value);
530         }
531     }
532 }
533
534 static void
535 do_lport_set_macs(struct ovs_cmdl_context *ctx)
536 {
537     struct nbctl_context *nb_ctx = ctx->pvt;
538     const char *id = ctx->argv[1];
539     const struct nbrec_logical_port *lport;
540
541     lport = lport_by_name_or_uuid(nb_ctx, id);
542     if (!lport) {
543         return;
544     }
545
546     nbrec_logical_port_set_macs(lport,
547             (const char **) ctx->argv + 2, ctx->argc - 2);
548 }
549
550 static void
551 do_lport_get_macs(struct ovs_cmdl_context *ctx)
552 {
553     struct nbctl_context *nb_ctx = ctx->pvt;
554     const char *id = ctx->argv[1];
555     const struct nbrec_logical_port *lport;
556     struct svec macs;
557     const char *mac;
558     size_t i;
559
560     lport = lport_by_name_or_uuid(nb_ctx, id);
561     if (!lport) {
562         return;
563     }
564
565     svec_init(&macs);
566     for (i = 0; i < lport->n_macs; i++) {
567         svec_add(&macs, lport->macs[i]);
568     }
569     svec_sort(&macs);
570     SVEC_FOR_EACH(i, mac, &macs) {
571         printf("%s\n", mac);
572     }
573     svec_destroy(&macs);
574 }
575
576 static void
577 do_lport_set_port_security(struct ovs_cmdl_context *ctx)
578 {
579     struct nbctl_context *nb_ctx = ctx->pvt;
580     const char *id = ctx->argv[1];
581     const struct nbrec_logical_port *lport;
582
583     lport = lport_by_name_or_uuid(nb_ctx, id);
584     if (!lport) {
585         return;
586     }
587
588     nbrec_logical_port_set_port_security(lport,
589             (const char **) ctx->argv + 2, ctx->argc - 2);
590 }
591
592 static void
593 do_lport_get_port_security(struct ovs_cmdl_context *ctx)
594 {
595     struct nbctl_context *nb_ctx = ctx->pvt;
596     const char *id = ctx->argv[1];
597     const struct nbrec_logical_port *lport;
598     struct svec addrs;
599     const char *addr;
600     size_t i;
601
602     lport = lport_by_name_or_uuid(nb_ctx, id);
603     if (!lport) {
604         return;
605     }
606
607     svec_init(&addrs);
608     for (i = 0; i < lport->n_port_security; i++) {
609         svec_add(&addrs, lport->port_security[i]);
610     }
611     svec_sort(&addrs);
612     SVEC_FOR_EACH(i, addr, &addrs) {
613         printf("%s\n", addr);
614     }
615     svec_destroy(&addrs);
616 }
617
618 static void
619 do_lport_get_up(struct ovs_cmdl_context *ctx)
620 {
621     struct nbctl_context *nb_ctx = ctx->pvt;
622     const char *id = ctx->argv[1];
623     const struct nbrec_logical_port *lport;
624
625     lport = lport_by_name_or_uuid(nb_ctx, id);
626     if (!lport) {
627         return;
628     }
629
630     printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
631 }
632
633 static void
634 do_lport_set_enabled(struct ovs_cmdl_context *ctx)
635 {
636     struct nbctl_context *nb_ctx = ctx->pvt;
637     const char *id = ctx->argv[1];
638     const char *state = ctx->argv[2];
639     const struct nbrec_logical_port *lport;
640
641     lport = lport_by_name_or_uuid(nb_ctx, id);
642     if (!lport) {
643         return;
644     }
645
646     if (!strcasecmp(state, "enabled")) {
647         bool enabled = true;
648         nbrec_logical_port_set_enabled(lport, &enabled, 1);
649     } else if (!strcasecmp(state, "disabled")) {
650         bool enabled = false;
651         nbrec_logical_port_set_enabled(lport, &enabled, 1);
652     } else {
653         VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
654     }
655 }
656
657 static void
658 do_lport_get_enabled(struct ovs_cmdl_context *ctx)
659 {
660     struct nbctl_context *nb_ctx = ctx->pvt;
661     const char *id = ctx->argv[1];
662     const struct nbrec_logical_port *lport;
663
664     lport = lport_by_name_or_uuid(nb_ctx, id);
665     if (!lport) {
666         return;
667     }
668
669     printf("%s\n",
670            (!lport->enabled || *lport->enabled) ? "enabled" : "disabled");
671 }
672
673 static void
674 do_lport_set_type(struct ovs_cmdl_context *ctx)
675 {
676     struct nbctl_context *nb_ctx = ctx->pvt;
677     const char *id = ctx->argv[1];
678     const char *type = ctx->argv[2];
679     const struct nbrec_logical_port *lport;
680
681     lport = lport_by_name_or_uuid(nb_ctx, id);
682     if (!lport) {
683         return;
684     }
685
686     nbrec_logical_port_set_type(lport, type);
687 }
688
689 static void
690 do_lport_get_type(struct ovs_cmdl_context *ctx)
691 {
692     struct nbctl_context *nb_ctx = ctx->pvt;
693     const char *id = ctx->argv[1];
694     const struct nbrec_logical_port *lport;
695
696     lport = lport_by_name_or_uuid(nb_ctx, id);
697     if (!lport) {
698         return;
699     }
700
701     printf("%s\n", lport->type);
702 }
703
704 static void
705 do_lport_set_options(struct ovs_cmdl_context *ctx)
706 {
707     struct nbctl_context *nb_ctx = ctx->pvt;
708     const char *id = ctx->argv[1];
709     const struct nbrec_logical_port *lport;
710     size_t i;
711     struct smap options = SMAP_INITIALIZER(&options);
712
713     lport = lport_by_name_or_uuid(nb_ctx, id);
714     if (!lport) {
715         return;
716     }
717
718     for (i = 2; i < ctx->argc; i++) {
719         char *key, *value;
720         value = xstrdup(ctx->argv[i]);
721         key = strsep(&value, "=");
722         if (value) {
723             smap_add(&options, key, value);
724         }
725         free(key);
726     }
727
728     nbrec_logical_port_set_options(lport, &options);
729
730     smap_destroy(&options);
731 }
732
733 static void
734 do_lport_get_options(struct ovs_cmdl_context *ctx)
735 {
736     struct nbctl_context *nb_ctx = ctx->pvt;
737     const char *id = ctx->argv[1];
738     const struct nbrec_logical_port *lport;
739     struct smap_node *node;
740
741     lport = lport_by_name_or_uuid(nb_ctx, id);
742     if (!lport) {
743         return;
744     }
745
746     SMAP_FOR_EACH(node, &lport->options) {
747         printf("%s=%s\n", node->key, node->value);
748     }
749 }
750 \f
751 static void
752 parse_options(int argc, char *argv[])
753 {
754     enum {
755         VLOG_OPTION_ENUMS,
756     };
757     static const struct option long_options[] = {
758         {"db", required_argument, NULL, 'd'},
759         {"help", no_argument, NULL, 'h'},
760         {"options", no_argument, NULL, 'o'},
761         {"version", no_argument, NULL, 'V'},
762         VLOG_LONG_OPTIONS,
763         STREAM_SSL_LONG_OPTIONS,
764         {NULL, 0, NULL, 0},
765     };
766     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
767
768     for (;;) {
769         int c;
770
771         c = getopt_long(argc, argv, short_options, long_options, NULL);
772         if (c == -1) {
773             break;
774         }
775
776         switch (c) {
777         VLOG_OPTION_HANDLERS;
778         STREAM_SSL_OPTION_HANDLERS;
779
780         case 'd':
781             db = optarg;
782             break;
783
784         case 'h':
785             usage();
786             exit(EXIT_SUCCESS);
787
788         case 'o':
789             ovs_cmdl_print_options(long_options);
790             exit(EXIT_SUCCESS);
791
792         case 'V':
793             ovs_print_version(0, 0);
794             exit(EXIT_SUCCESS);
795
796         default:
797             break;
798         }
799     }
800
801     if (!db) {
802         db = default_db();
803     }
804
805     free(short_options);
806 }
807
808 static const struct ovs_cmdl_command all_commands[] = {
809     {
810         .name = "show",
811         .usage = "[LSWITCH]",
812         .min_args = 0,
813         .max_args = 1,
814         .handler = do_show,
815     },
816     {
817         .name = "lswitch-add",
818         .usage = "[LSWITCH]",
819         .min_args = 0,
820         .max_args = 1,
821         .handler = do_lswitch_add,
822     },
823     {
824         .name = "lswitch-del",
825         .usage = "LSWITCH",
826         .min_args = 1,
827         .max_args = 1,
828         .handler = do_lswitch_del,
829     },
830     {
831         .name = "lswitch-list",
832         .usage = "",
833         .min_args = 0,
834         .max_args = 0,
835         .handler = do_lswitch_list,
836     },
837     {
838         .name = "lswitch-set-external-id",
839         .usage = "LSWITCH KEY [VALUE]",
840         .min_args = 2,
841         .max_args = 3,
842         .handler = do_lswitch_set_external_id,
843     },
844     {
845         .name = "lswitch-get-external-id",
846         .usage = "LSWITCH [KEY]",
847         .min_args = 1,
848         .max_args = 2,
849         .handler = do_lswitch_get_external_id,
850     },
851     {
852         .name = "lport-add",
853         .usage = "LSWITCH LPORT [PARENT] [TAG]",
854         .min_args = 2,
855         .max_args = 4,
856         .handler = do_lport_add,
857     },
858     {
859         .name = "lport-del",
860         .usage = "LPORT",
861         .min_args = 1,
862         .max_args = 1,
863         .handler = do_lport_del,
864     },
865     {
866         .name = "lport-list",
867         .usage = "LSWITCH",
868         .min_args = 1,
869         .max_args = 1,
870         .handler = do_lport_list,
871     },
872     {
873         .name = "lport-get-parent",
874         .usage = "LPORT",
875         .min_args = 1,
876         .max_args = 1,
877         .handler = do_lport_get_parent,
878     },
879     {
880         .name = "lport-get-tag",
881         .usage = "LPORT",
882         .min_args = 1,
883         .max_args = 1,
884         .handler = do_lport_get_tag,
885     },
886     {
887         .name = "lport-set-external-id",
888         .usage = "LPORT KEY [VALUE]",
889         .min_args = 2,
890         .max_args = 3,
891         .handler = do_lport_set_external_id,
892     },
893     {
894         .name = "lport-get-external-id",
895         .usage = "LPORT [KEY]",
896         .min_args = 1,
897         .max_args = 2,
898         .handler = do_lport_get_external_id,
899     },
900     {
901         .name = "lport-set-macs",
902         .usage = "LPORT [MAC]...",
903         .min_args = 1,
904         /* Accept however many arguments the system will allow. */
905         .max_args = INT_MAX,
906         .handler = do_lport_set_macs,
907     },
908     {
909         .name = "lport-get-macs",
910         .usage = "LPORT",
911         .min_args = 1,
912         .max_args = 1,
913         .handler = do_lport_get_macs,
914     },
915     {
916         .name = "lport-set-port-security",
917         .usage = "LPORT [ADDRS]...",
918         .min_args = 0,
919         /* Accept however many arguments the system will allow. */
920         .max_args = INT_MAX,
921         .handler = do_lport_set_port_security,
922     },
923     {
924         .name = "lport-get-port-security",
925         .usage = "LPORT",
926         .min_args = 1,
927         .max_args = 1,
928         .handler = do_lport_get_port_security,
929     },
930     {
931         .name = "lport-get-up",
932         .usage = "LPORT",
933         .min_args = 1,
934         .max_args = 1,
935         .handler = do_lport_get_up,
936     },
937     {
938         .name = "lport-set-enabled",
939         .usage = "LPORT STATE",
940         .min_args = 2,
941         .max_args = 2,
942         .handler = do_lport_set_enabled,
943     },
944     {
945         .name = "lport-get-enabled",
946         .usage = "LPORT",
947         .min_args = 1,
948         .max_args = 1,
949         .handler = do_lport_get_enabled,
950     },
951     {
952         .name = "lport-set-type",
953         .usage = "LPORT TYPE",
954         .min_args = 2,
955         .max_args = 2,
956         .handler = do_lport_set_type,
957     },
958     {
959         .name = "lport-get-type",
960         .usage = "LPORT",
961         .min_args = 1,
962         .max_args = 1,
963         .handler = do_lport_get_type,
964     },
965     {
966         .name = "lport-set-options",
967         .usage = "LPORT KEY=VALUE [KEY=VALUE]...",
968         .min_args = 1,
969         .max_args = INT_MAX,
970         .handler = do_lport_set_options
971     },
972     {
973         .name = "lport-get-options",
974         .usage = "LPORT",
975         .min_args = 1,
976         .max_args = 1,
977         .handler = do_lport_get_options,
978     },
979
980     {
981         /* sentinel */
982         .name = NULL,
983     },
984 };
985
986 static const struct ovs_cmdl_command *
987 get_all_commands(void)
988 {
989     return all_commands;
990 }
991
992 static const char *
993 default_db(void)
994 {
995     static char *def;
996     if (!def) {
997         def = getenv("OVN_NB_DB");
998         if (!def) {
999             def = xasprintf("unix:%s/db.sock", ovs_rundir());
1000         }
1001     }
1002     return def;
1003 }
1004
1005 int
1006 main(int argc, char *argv[])
1007 {
1008     extern struct vlog_module VLM_reconnect;
1009     struct ovs_cmdl_context ctx;
1010     struct nbctl_context nb_ctx = { .idl = NULL, };
1011     enum ovsdb_idl_txn_status txn_status;
1012     unsigned int seqno;
1013     int res = 0;
1014     char *args;
1015
1016     fatal_ignore_sigpipe();
1017     set_program_name(argv[0]);
1018     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
1019     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
1020     parse_options(argc, argv);
1021     nbrec_init();
1022
1023     args = process_escape_args(argv);
1024
1025     nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
1026     ctx.pvt = &nb_ctx;
1027     ctx.argc = argc - optind;
1028     ctx.argv = argv + optind;
1029
1030     seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
1031     for (;;) {
1032         ovsdb_idl_run(nb_ctx.idl);
1033
1034         if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
1035             int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
1036             VLOG_ERR("%s: database connection failed (%s)",
1037                     db, ovs_retval_to_string(retval));
1038             res = 1;
1039             break;
1040         }
1041
1042         if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
1043             nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
1044             ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
1045             ovs_cmdl_run_command(&ctx, get_all_commands());
1046             txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
1047             if (txn_status == TXN_TRY_AGAIN) {
1048                 ovsdb_idl_txn_destroy(nb_ctx.txn);
1049                 nb_ctx.txn = NULL;
1050                 continue;
1051             } else {
1052                 break;
1053             }
1054         }
1055
1056         if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
1057             ovsdb_idl_wait(nb_ctx.idl);
1058             poll_block();
1059         }
1060     }
1061
1062     if (nb_ctx.txn) {
1063         ovsdb_idl_txn_destroy(nb_ctx.txn);
1064     }
1065     ovsdb_idl_destroy(nb_ctx.idl);
1066     free(args);
1067
1068     exit(res);
1069 }