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