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