ovn: Move all library files into ovn/lib, and merge libraries.
[cascardo/ovs.git] / ovn / 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 \n\
54 Logical switch commands:\n\
55   lswitch-add [LSWITCH]     create a logical switch named LSWITCH\n\
56   lswitch-del LSWITCH       delete LSWITCH and all its ports\n\
57   lswitch-list              print the names of all logical switches\n\
58   lswitch-set-external-id LSWITCH KEY [VALUE]\n\
59                             set or delete an external-id on LSWITCH\n\
60   lswitch-get-external-id LSWITCH [KEY]\n\
61                             list one or all external-ids on LSWITCH\n\
62 \n\
63 Logical port commands:\n\
64   lport-add LSWITCH LPORT   add logical port LPORT on LSWITCH\n\
65   lport-add LSWITCH LPORT PARENT TAG\n\
66                             add logical port LPORT on LSWITCH with PARENT\n\
67                             on TAG\n\
68   lport-del LPORT           delete LPORT from its attached switch\n\
69   lport-list LSWITCH        print the names of all logical ports on LSWITCH\n\
70   lport-get-parent LPORT    get the parent of LPORT if set\n\
71   lport-get-tag LPORT       get the LPORT's tag if set\n\
72   lport-set-external-id LPORT KEY [VALUE]\n\
73                             set or delete an external-id on LPORT\n\
74   lport-get-external-id LPORT [KEY]\n\
75                             list one or all external-ids on LPORT\n\
76   lport-set-macs LPORT [MAC]...\n\
77                             set MAC addresses for LPORT.\n\
78   lport-get-macs LPORT      get a list of MAC addresses on LPORT\n\
79   lport-set-port-security LPORT [ADDRS]...\n\
80                             set port security addresses for LPORT.\n\
81   lport-get-port-security LPORT    get LPORT's port security addresses\n\
82   lport-get-up LPORT        get state of LPORT ('up' or 'down')\n\
83 \n\
84 Options:\n\
85   --db=DATABASE             connect to DATABASE\n\
86                             (default: %s)\n\
87   -h, --help                display this help message\n\
88   -o, --options             list available options\n\
89   -V, --version             display version information\n\
90 ", program_name, program_name, default_db());
91     vlog_usage();
92     stream_usage("database", true, true, false);
93 }
94 \f
95 static const struct nbrec_logical_switch *
96 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
97 {
98     const struct nbrec_logical_switch *lswitch = NULL;
99     bool is_uuid = false;
100     bool duplicate = false;
101     struct uuid lswitch_uuid;
102
103     if (uuid_from_string(&lswitch_uuid, id)) {
104         is_uuid = true;
105         lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
106                                                     &lswitch_uuid);
107     }
108
109     if (!lswitch) {
110         const struct nbrec_logical_switch *iter;
111
112         NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
113             if (strcmp(iter->name, id)) {
114                 continue;
115             }
116             if (lswitch) {
117                 VLOG_WARN("There is more than one logical switch named '%s'. "
118                         "Use a UUID.", id);
119                 lswitch = NULL;
120                 duplicate = true;
121                 break;
122             }
123             lswitch = iter;
124         }
125     }
126
127     if (!lswitch && !duplicate) {
128         VLOG_WARN("lswitch not found for %s: '%s'",
129                 is_uuid ? "UUID" : "name", id);
130     }
131
132     return lswitch;
133 }
134
135 static void
136 print_lswitch(const struct nbctl_context *nb_ctx,
137               const struct nbrec_logical_switch *lswitch)
138 {
139     const struct nbrec_logical_port *lport;
140
141     printf("    lswitch "UUID_FMT" (%s)\n",
142            UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
143
144     NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
145         int i;
146
147         if (lport->lswitch == lswitch) {
148             printf("        lport %s\n", lport->name);
149             if (lport->parent_name && lport->n_tag) {
150                 printf("            parent: %s, tag:%"PRIu64"\n",
151                        lport->parent_name, lport->tag[0]);
152             }
153             if (lport->n_macs) {
154                 printf("            macs:");
155                 for (i=0; i < lport->n_macs; i++) {
156                     printf(" %s", lport->macs[i]);
157                 }
158                 printf("\n");
159             }
160         }
161     }
162 }
163
164 static void
165 do_show(struct ovs_cmdl_context *ctx)
166 {
167     struct nbctl_context *nb_ctx = ctx->pvt;
168     const struct nbrec_logical_switch *lswitch;
169
170     if (ctx->argc == 2) {
171         lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
172         if (lswitch) {
173             print_lswitch(nb_ctx, lswitch);
174         }
175     } else {
176         NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
177             print_lswitch(nb_ctx, lswitch);
178         }
179     }
180 }
181
182 static void
183 do_lswitch_add(struct ovs_cmdl_context *ctx)
184 {
185     struct nbctl_context *nb_ctx = ctx->pvt;
186     struct nbrec_logical_switch *lswitch;
187
188     lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
189     if (ctx->argc == 2) {
190         nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
191     }
192 }
193
194 static void
195 do_lswitch_del(struct ovs_cmdl_context *ctx)
196 {
197     struct nbctl_context *nb_ctx = ctx->pvt;
198     const char *id = ctx->argv[1];
199     const struct nbrec_logical_switch *lswitch;
200
201     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
202     if (!lswitch) {
203         return;
204     }
205
206     nbrec_logical_switch_delete(lswitch);
207 }
208
209 static void
210 do_lswitch_list(struct ovs_cmdl_context *ctx)
211 {
212     struct nbctl_context *nb_ctx = ctx->pvt;
213     const struct nbrec_logical_switch *lswitch;
214
215     NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
216         printf(UUID_FMT " (%s)\n",
217                UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
218     }
219 }
220
221 static void
222 do_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
223 {
224     struct nbctl_context *nb_ctx = ctx->pvt;
225     const char *id = ctx->argv[1];
226     const struct nbrec_logical_switch *lswitch;
227     struct smap new_external_ids;
228
229     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
230     if (!lswitch) {
231         return;
232     }
233
234     smap_init(&new_external_ids);
235     smap_clone(&new_external_ids, &lswitch->external_ids);
236     if (ctx->argc == 4) {
237         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
238     } else {
239         smap_remove(&new_external_ids, ctx->argv[2]);
240     }
241     nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
242     smap_destroy(&new_external_ids);
243 }
244
245 static void
246 do_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
247 {
248     struct nbctl_context *nb_ctx = ctx->pvt;
249     const char *id = ctx->argv[1];
250     const struct nbrec_logical_switch *lswitch;
251
252     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
253     if (!lswitch) {
254         return;
255     }
256
257     if (ctx->argc == 3) {
258         const char *key = ctx->argv[2];
259         const char *value;
260
261         /* List one external ID */
262
263         value = smap_get(&lswitch->external_ids, key);
264         if (value) {
265             printf("%s\n", value);
266         }
267     } else {
268         struct smap_node *node;
269
270         /* List all external IDs */
271
272         SMAP_FOR_EACH(node, &lswitch->external_ids) {
273             printf("%s=%s\n", node->key, node->value);
274         }
275     }
276 }
277 \f
278 static const struct nbrec_logical_port *
279 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
280 {
281     const struct nbrec_logical_port *lport = NULL;
282     bool is_uuid = false;
283     struct uuid lport_uuid;
284
285     if (uuid_from_string(&lport_uuid, id)) {
286         is_uuid = true;
287         lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
288     }
289
290     if (!lport) {
291         NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
292             if (!strcmp(lport->name, id)) {
293                 break;
294             }
295         }
296     }
297
298     if (!lport) {
299         VLOG_WARN("lport not found for %s: '%s'",
300                 is_uuid ? "UUID" : "name", id);
301     }
302
303     return lport;
304 }
305
306 static void
307 do_lport_add(struct ovs_cmdl_context *ctx)
308 {
309     struct nbctl_context *nb_ctx = ctx->pvt;
310     struct nbrec_logical_port *lport;
311     const struct nbrec_logical_switch *lswitch;
312     int64_t tag;
313
314     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
315     if (!lswitch) {
316         return;
317     }
318
319     if (ctx->argc != 3 && ctx->argc != 5) {
320         /* If a parent_name is specififed, a tag must be specified as well. */
321         VLOG_WARN("Invalid arguments to lport-add.");
322         return;
323     }
324
325     if (ctx->argc == 5) {
326         /* Validate tag. */
327         if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
328             VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
329             return;
330         }
331     }
332
333     /* Finally, create the transaction. */
334     lport = nbrec_logical_port_insert(nb_ctx->txn);
335     nbrec_logical_port_set_name(lport, ctx->argv[2]);
336     nbrec_logical_port_set_lswitch(lport, lswitch);
337     if (ctx->argc == 5) {
338         nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
339         nbrec_logical_port_set_tag(lport, &tag, 1);
340     }
341 }
342
343 static void
344 do_lport_del(struct ovs_cmdl_context *ctx)
345 {
346     struct nbctl_context *nb_ctx = ctx->pvt;
347     const struct nbrec_logical_port *lport;
348
349     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
350     if (!lport) {
351         return;
352     }
353
354     nbrec_logical_port_delete(lport);
355 }
356
357 static bool
358 is_lswitch(const struct nbrec_logical_switch *lswitch,
359         struct uuid *lswitch_uuid, const char *name)
360 {
361     if (lswitch_uuid) {
362         return uuid_equals(lswitch_uuid, &lswitch->header_.uuid);
363     } else {
364         return !strcmp(lswitch->name, name);
365     }
366 }
367
368
369 static void
370 do_lport_list(struct ovs_cmdl_context *ctx)
371 {
372     struct nbctl_context *nb_ctx = ctx->pvt;
373     const char *id = ctx->argv[1];
374     const struct nbrec_logical_port *lport;
375     bool is_uuid = false;
376     struct uuid lswitch_uuid;
377
378     if (uuid_from_string(&lswitch_uuid, id)) {
379         is_uuid = true;
380     }
381
382     NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
383         bool match;
384         if (is_uuid) {
385             match = is_lswitch(lport->lswitch, &lswitch_uuid, NULL);
386         } else {
387             match = is_lswitch(lport->lswitch, NULL, id);
388         }
389         if (!match) {
390             continue;
391         }
392         printf(UUID_FMT " (%s)\n",
393                UUID_ARGS(&lport->header_.uuid), lport->name);
394     }
395 }
396
397 static void
398 do_lport_get_parent(struct ovs_cmdl_context *ctx)
399 {
400     struct nbctl_context *nb_ctx = ctx->pvt;
401     const struct nbrec_logical_port *lport;
402
403     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
404     if (!lport) {
405         return;
406     }
407
408     if (lport->parent_name) {
409         printf("%s\n", lport->parent_name);
410     }
411 }
412
413 static void
414 do_lport_get_tag(struct ovs_cmdl_context *ctx)
415 {
416     struct nbctl_context *nb_ctx = ctx->pvt;
417     const struct nbrec_logical_port *lport;
418
419     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
420     if (!lport) {
421         return;
422     }
423
424     if (lport->n_tag > 0) {
425         printf("%"PRId64"\n", lport->tag[0]);
426     }
427 }
428
429 static void
430 do_lport_set_external_id(struct ovs_cmdl_context *ctx)
431 {
432     struct nbctl_context *nb_ctx = ctx->pvt;
433     const char *id = ctx->argv[1];
434     const struct nbrec_logical_port *lport;
435     struct smap new_external_ids;
436
437     lport = lport_by_name_or_uuid(nb_ctx, id);
438     if (!lport) {
439         return;
440     }
441
442     smap_init(&new_external_ids);
443     smap_clone(&new_external_ids, &lport->external_ids);
444     if (ctx->argc == 4) {
445         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
446     } else {
447         smap_remove(&new_external_ids, ctx->argv[2]);
448     }
449     nbrec_logical_port_set_external_ids(lport, &new_external_ids);
450     smap_destroy(&new_external_ids);
451 }
452
453 static void
454 do_lport_get_external_id(struct ovs_cmdl_context *ctx)
455 {
456     struct nbctl_context *nb_ctx = ctx->pvt;
457     const char *id = ctx->argv[1];
458     const struct nbrec_logical_port *lport;
459
460     lport = lport_by_name_or_uuid(nb_ctx, id);
461     if (!lport) {
462         return;
463     }
464
465     if (ctx->argc == 3) {
466         const char *key = ctx->argv[2];
467         const char *value;
468
469         /* List one external ID */
470
471         value = smap_get(&lport->external_ids, key);
472         if (value) {
473             printf("%s\n", value);
474         }
475     } else {
476         struct smap_node *node;
477
478         /* List all external IDs */
479
480         SMAP_FOR_EACH(node, &lport->external_ids) {
481             printf("%s=%s\n", node->key, node->value);
482         }
483     }
484 }
485
486 static void
487 do_lport_set_macs(struct ovs_cmdl_context *ctx)
488 {
489     struct nbctl_context *nb_ctx = ctx->pvt;
490     const char *id = ctx->argv[1];
491     const struct nbrec_logical_port *lport;
492
493     lport = lport_by_name_or_uuid(nb_ctx, id);
494     if (!lport) {
495         return;
496     }
497
498     nbrec_logical_port_set_macs(lport,
499             (const char **) ctx->argv + 2, ctx->argc - 2);
500 }
501
502 static void
503 do_lport_get_macs(struct ovs_cmdl_context *ctx)
504 {
505     struct nbctl_context *nb_ctx = ctx->pvt;
506     const char *id = ctx->argv[1];
507     const struct nbrec_logical_port *lport;
508     size_t i;
509
510     lport = lport_by_name_or_uuid(nb_ctx, id);
511     if (!lport) {
512         return;
513     }
514
515     for (i = 0; i < lport->n_macs; i++) {
516         printf("%s\n", lport->macs[i]);
517     }
518 }
519
520 static void
521 do_lport_set_port_security(struct ovs_cmdl_context *ctx)
522 {
523     struct nbctl_context *nb_ctx = ctx->pvt;
524     const char *id = ctx->argv[1];
525     const struct nbrec_logical_port *lport;
526
527     lport = lport_by_name_or_uuid(nb_ctx, id);
528     if (!lport) {
529         return;
530     }
531
532     nbrec_logical_port_set_port_security(lport,
533             (const char **) ctx->argv + 2, ctx->argc - 2);
534 }
535
536 static void
537 do_lport_get_port_security(struct ovs_cmdl_context *ctx)
538 {
539     struct nbctl_context *nb_ctx = ctx->pvt;
540     const char *id = ctx->argv[1];
541     const struct nbrec_logical_port *lport;
542     size_t i;
543
544     lport = lport_by_name_or_uuid(nb_ctx, id);
545     if (!lport) {
546         return;
547     }
548
549     for (i = 0; i < lport->n_port_security; i++) {
550         printf("%s\n", lport->port_security[i]);
551     }
552 }
553
554 static void
555 do_lport_get_up(struct ovs_cmdl_context *ctx)
556 {
557     struct nbctl_context *nb_ctx = ctx->pvt;
558     const char *id = ctx->argv[1];
559     const struct nbrec_logical_port *lport;
560
561     lport = lport_by_name_or_uuid(nb_ctx, id);
562     if (!lport) {
563         return;
564     }
565
566     printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
567 }
568 \f
569 static void
570 parse_options(int argc, char *argv[])
571 {
572     enum {
573         VLOG_OPTION_ENUMS,
574     };
575     static const struct option long_options[] = {
576         {"db", required_argument, NULL, 'd'},
577         {"help", no_argument, NULL, 'h'},
578         {"options", no_argument, NULL, 'o'},
579         {"version", no_argument, NULL, 'V'},
580         VLOG_LONG_OPTIONS,
581         STREAM_SSL_LONG_OPTIONS,
582         {NULL, 0, NULL, 0},
583     };
584     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
585
586     for (;;) {
587         int c;
588
589         c = getopt_long(argc, argv, short_options, long_options, NULL);
590         if (c == -1) {
591             break;
592         }
593
594         switch (c) {
595         VLOG_OPTION_HANDLERS;
596         STREAM_SSL_OPTION_HANDLERS;
597
598         case 'd':
599             db = optarg;
600             break;
601
602         case 'h':
603             usage();
604             exit(EXIT_SUCCESS);
605
606         case 'o':
607             ovs_cmdl_print_options(long_options);
608             exit(EXIT_SUCCESS);
609
610         case 'V':
611             ovs_print_version(0, 0);
612             exit(EXIT_SUCCESS);
613
614         default:
615             break;
616         }
617     }
618
619     if (!db) {
620         db = default_db();
621     }
622
623     free(short_options);
624 }
625
626 static const struct ovs_cmdl_command all_commands[] = {
627     {
628         .name = "show",
629         .usage = "[LSWITCH]",
630         .min_args = 0,
631         .max_args = 1,
632         .handler = do_show,
633     },
634     {
635         .name = "lswitch-add",
636         .usage = "[LSWITCH]",
637         .min_args = 0,
638         .max_args = 1,
639         .handler = do_lswitch_add,
640     },
641     {
642         .name = "lswitch-del",
643         .usage = "LSWITCH",
644         .min_args = 1,
645         .max_args = 1,
646         .handler = do_lswitch_del,
647     },
648     {
649         .name = "lswitch-list",
650         .usage = "",
651         .min_args = 0,
652         .max_args = 0,
653         .handler = do_lswitch_list,
654     },
655     {
656         .name = "lswitch-set-external-id",
657         .usage = "LSWITCH KEY [VALUE]",
658         .min_args = 2,
659         .max_args = 3,
660         .handler = do_lswitch_set_external_id,
661     },
662     {
663         .name = "lswitch-get-external-id",
664         .usage = "LSWITCH [KEY]",
665         .min_args = 1,
666         .max_args = 2,
667         .handler = do_lswitch_get_external_id,
668     },
669     {
670         .name = "lport-add",
671         .usage = "LSWITCH LPORT [PARENT] [TAG]",
672         .min_args = 2,
673         .max_args = 4,
674         .handler = do_lport_add,
675     },
676     {
677         .name = "lport-del",
678         .usage = "LPORT",
679         .min_args = 1,
680         .max_args = 1,
681         .handler = do_lport_del,
682     },
683     {
684         .name = "lport-list",
685         .usage = "LSWITCH",
686         .min_args = 1,
687         .max_args = 1,
688         .handler = do_lport_list,
689     },
690     {
691         .name = "lport-get-parent",
692         .usage = "LPORT",
693         .min_args = 1,
694         .max_args = 1,
695         .handler = do_lport_get_parent,
696     },
697     {
698         .name = "lport-get-tag",
699         .usage = "LPORT",
700         .min_args = 1,
701         .max_args = 1,
702         .handler = do_lport_get_tag,
703     },
704     {
705         .name = "lport-set-external-id",
706         .usage = "LPORT KEY [VALUE]",
707         .min_args = 2,
708         .max_args = 3,
709         .handler = do_lport_set_external_id,
710     },
711     {
712         .name = "lport-get-external-id",
713         .usage = "LPORT [KEY]",
714         .min_args = 1,
715         .max_args = 2,
716         .handler = do_lport_get_external_id,
717     },
718     {
719         .name = "lport-set-macs",
720         .usage = "LPORT [MAC]...",
721         .min_args = 1,
722         /* Accept however many arguments the system will allow. */
723         .max_args = INT_MAX,
724         .handler = do_lport_set_macs,
725     },
726     {
727         .name = "lport-get-macs",
728         .usage = "LPORT",
729         .min_args = 1,
730         .max_args = 1,
731         .handler = do_lport_get_macs,
732     },
733     {
734         .name = "lport-set-port-security",
735         .usage = "LPORT [ADDRS]...",
736         .min_args = 0,
737         /* Accept however many arguments the system will allow. */
738         .max_args = INT_MAX,
739         .handler = do_lport_set_port_security,
740     },
741     {
742         .name = "lport-get-port-security",
743         .usage = "LPORT",
744         .min_args = 1,
745         .max_args = 1,
746         .handler = do_lport_get_port_security,
747     },
748     {
749         .name = "lport-get-up",
750         .usage = "LPORT",
751         .min_args = 1,
752         .max_args = 1,
753         .handler = do_lport_get_up,
754     },
755
756     {
757         /* sentinel */
758         .name = NULL,
759     },
760 };
761
762 static const struct ovs_cmdl_command *
763 get_all_commands(void)
764 {
765     return all_commands;
766 }
767
768 static const char *
769 default_db(void)
770 {
771     static char *def;
772     if (!def) {
773         def = xasprintf("unix:%s/db.sock", ovs_rundir());
774     }
775     return def;
776 }
777
778 int
779 main(int argc, char *argv[])
780 {
781     extern struct vlog_module VLM_reconnect;
782     struct ovs_cmdl_context ctx;
783     struct nbctl_context nb_ctx = { .idl = NULL, };
784     enum ovsdb_idl_txn_status txn_status;
785     unsigned int seqno;
786     int res = 0;
787     char *args;
788
789     fatal_ignore_sigpipe();
790     set_program_name(argv[0]);
791     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
792     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
793     parse_options(argc, argv);
794     nbrec_init();
795
796     args = process_escape_args(argv);
797
798     nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
799     ctx.pvt = &nb_ctx;
800     ctx.argc = argc - optind;
801     ctx.argv = argv + optind;
802
803     seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
804     for (;;) {
805         ovsdb_idl_run(nb_ctx.idl);
806
807         if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
808             int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
809             VLOG_ERR("%s: database connection failed (%s)",
810                     db, ovs_retval_to_string(retval));
811             res = 1;
812             break;
813         }
814
815         if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
816             nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
817             ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
818             ovs_cmdl_run_command(&ctx, get_all_commands());
819             txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
820             if (txn_status == TXN_TRY_AGAIN) {
821                 ovsdb_idl_txn_destroy(nb_ctx.txn);
822                 nb_ctx.txn = NULL;
823                 continue;
824             } else {
825                 break;
826             }
827         }
828
829         if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
830             ovsdb_idl_wait(nb_ctx.idl);
831             poll_block();
832         }
833     }
834
835     if (nb_ctx.txn) {
836         ovsdb_idl_txn_destroy(nb_ctx.txn);
837     }
838     ovsdb_idl_destroy(nb_ctx.idl);
839     free(args);
840
841     exit(res);
842 }