ovn-nbctl: Give handler functions more specific names.
[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 ACL commands:\n\
67   acl-add LSWITCH DIRECTION PRIORITY MATCH ACTION [log]\n\
68                             add an ACL to LSWITCH\n\
69   acl-del LSWITCH [DIRECTION [PRIORITY MATCH]]\n\
70                             remove ACLs from LSWITCH\n\
71   acl-list LSWITCH          print ACLs for LSWITCH\n\
72 \n\
73 Logical port commands:\n\
74   lport-add LSWITCH LPORT   add logical port LPORT on LSWITCH\n\
75   lport-add LSWITCH LPORT PARENT TAG\n\
76                             add logical port LPORT on LSWITCH with PARENT\n\
77                             on TAG\n\
78   lport-del LPORT           delete LPORT from its attached switch\n\
79   lport-list LSWITCH        print the names of all logical ports on LSWITCH\n\
80   lport-get-parent LPORT    get the parent of LPORT if set\n\
81   lport-get-tag LPORT       get the LPORT's tag if set\n\
82   lport-set-external-id LPORT KEY [VALUE]\n\
83                             set or delete an external-id on LPORT\n\
84   lport-get-external-id LPORT [KEY]\n\
85                             list one or all external-ids on LPORT\n\
86   lport-set-macs LPORT [MAC]...\n\
87                             set MAC addresses for LPORT.\n\
88   lport-get-macs LPORT      get a list of MAC addresses on LPORT\n\
89   lport-set-port-security LPORT [ADDRS]...\n\
90                             set port security addresses for LPORT.\n\
91   lport-get-port-security LPORT    get LPORT's port security addresses\n\
92   lport-get-up LPORT        get state of LPORT ('up' or 'down')\n\
93   lport-set-enabled LPORT STATE\n\
94                             set administrative state LPORT\n\
95                             ('enabled' or 'disabled')\n\
96   lport-get-enabled LPORT   get administrative state LPORT\n\
97                             ('enabled' or 'disabled')\n\
98   lport-set-type LPORT TYPE Set the type for LPORT\n\
99   lport-get-type LPORT      Get the type for LPORT\n\
100   lport-set-options LPORT KEY=VALUE [KEY=VALUE]...\n\
101                             Set options related to the type of LPORT\n\
102   lport-get-options LPORT   Get the type specific options for LPORT\n\
103 \n\
104 Options:\n\
105   --db=DATABASE             connect to DATABASE\n\
106                             (default: %s)\n\
107   -h, --help                display this help message\n\
108   -o, --options             list available options\n\
109   -V, --version             display version information\n\
110 ", program_name, program_name, default_db());
111     vlog_usage();
112     stream_usage("database", true, true, false);
113 }
114 \f
115 static const struct nbrec_logical_switch *
116 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
117 {
118     const struct nbrec_logical_switch *lswitch = NULL;
119     bool is_uuid = false;
120     bool duplicate = false;
121     struct uuid lswitch_uuid;
122
123     if (uuid_from_string(&lswitch_uuid, id)) {
124         is_uuid = true;
125         lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
126                                                     &lswitch_uuid);
127     }
128
129     if (!lswitch) {
130         const struct nbrec_logical_switch *iter;
131
132         NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
133             if (strcmp(iter->name, id)) {
134                 continue;
135             }
136             if (lswitch) {
137                 VLOG_WARN("There is more than one logical switch named '%s'. "
138                         "Use a UUID.", id);
139                 lswitch = NULL;
140                 duplicate = true;
141                 break;
142             }
143             lswitch = iter;
144         }
145     }
146
147     if (!lswitch && !duplicate) {
148         VLOG_WARN("lswitch not found for %s: '%s'",
149                 is_uuid ? "UUID" : "name", id);
150     }
151
152     return lswitch;
153 }
154
155 static void
156 print_lswitch(const struct nbrec_logical_switch *lswitch)
157 {
158     printf("    lswitch "UUID_FMT" (%s)\n",
159            UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
160
161     for (size_t i = 0; i < lswitch->n_ports; i++) {
162         const struct nbrec_logical_port *lport = lswitch->ports[i];
163
164         printf("        lport %s\n", lport->name);
165         if (lport->parent_name && lport->n_tag) {
166             printf("            parent: %s, tag:%"PRIu64"\n",
167                    lport->parent_name, lport->tag[0]);
168         }
169         if (lport->n_macs) {
170             printf("            macs:");
171             for (size_t j = 0; j < lport->n_macs; j++) {
172                 printf(" %s", lport->macs[j]);
173             }
174             printf("\n");
175         }
176     }
177 }
178
179 static void
180 nbctl_show(struct ovs_cmdl_context *ctx)
181 {
182     struct nbctl_context *nb_ctx = ctx->pvt;
183     const struct nbrec_logical_switch *lswitch;
184
185     if (ctx->argc == 2) {
186         lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
187         if (lswitch) {
188             print_lswitch(lswitch);
189         }
190     } else {
191         NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
192             print_lswitch(lswitch);
193         }
194     }
195 }
196
197 static void
198 nbctl_lswitch_add(struct ovs_cmdl_context *ctx)
199 {
200     struct nbctl_context *nb_ctx = ctx->pvt;
201     struct nbrec_logical_switch *lswitch;
202
203     lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
204     if (ctx->argc == 2) {
205         nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
206     }
207 }
208
209 static void
210 nbctl_lswitch_del(struct ovs_cmdl_context *ctx)
211 {
212     struct nbctl_context *nb_ctx = ctx->pvt;
213     const char *id = ctx->argv[1];
214     const struct nbrec_logical_switch *lswitch;
215
216     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
217     if (!lswitch) {
218         return;
219     }
220
221     nbrec_logical_switch_delete(lswitch);
222 }
223
224 static void
225 nbctl_lswitch_list(struct ovs_cmdl_context *ctx)
226 {
227     struct nbctl_context *nb_ctx = ctx->pvt;
228     const struct nbrec_logical_switch *lswitch;
229     struct smap lswitches;
230
231     smap_init(&lswitches);
232     NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
233         smap_add_format(&lswitches, lswitch->name, UUID_FMT " (%s)",
234                         UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
235     }
236     const struct smap_node **nodes = smap_sort(&lswitches);
237     for (size_t i = 0; i < smap_count(&lswitches); i++) {
238         const struct smap_node *node = nodes[i];
239         printf("%s\n", node->value);
240     }
241     smap_destroy(&lswitches);
242     free(nodes);
243 }
244
245 static void
246 nbctl_lswitch_set_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     struct smap new_external_ids;
252
253     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
254     if (!lswitch) {
255         return;
256     }
257
258     smap_init(&new_external_ids);
259     smap_clone(&new_external_ids, &lswitch->external_ids);
260     if (ctx->argc == 4) {
261         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
262     } else {
263         smap_remove(&new_external_ids, ctx->argv[2]);
264     }
265     nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
266     smap_destroy(&new_external_ids);
267 }
268
269 static void
270 nbctl_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
271 {
272     struct nbctl_context *nb_ctx = ctx->pvt;
273     const char *id = ctx->argv[1];
274     const struct nbrec_logical_switch *lswitch;
275
276     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
277     if (!lswitch) {
278         return;
279     }
280
281     if (ctx->argc == 3) {
282         const char *key = ctx->argv[2];
283         const char *value;
284
285         /* List one external ID */
286
287         value = smap_get(&lswitch->external_ids, key);
288         if (value) {
289             printf("%s\n", value);
290         }
291     } else {
292         struct smap_node *node;
293
294         /* List all external IDs */
295
296         SMAP_FOR_EACH(node, &lswitch->external_ids) {
297             printf("%s=%s\n", node->key, node->value);
298         }
299     }
300 }
301 \f
302 static const struct nbrec_logical_port *
303 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
304 {
305     const struct nbrec_logical_port *lport = NULL;
306     bool is_uuid = false;
307     struct uuid lport_uuid;
308
309     if (uuid_from_string(&lport_uuid, id)) {
310         is_uuid = true;
311         lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
312     }
313
314     if (!lport) {
315         NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
316             if (!strcmp(lport->name, id)) {
317                 break;
318             }
319         }
320     }
321
322     if (!lport) {
323         VLOG_WARN("lport not found for %s: '%s'",
324                 is_uuid ? "UUID" : "name", id);
325     }
326
327     return lport;
328 }
329
330 static void
331 nbctl_lport_add(struct ovs_cmdl_context *ctx)
332 {
333     struct nbctl_context *nb_ctx = ctx->pvt;
334     struct nbrec_logical_port *lport;
335     const struct nbrec_logical_switch *lswitch;
336     int64_t tag;
337
338     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
339     if (!lswitch) {
340         return;
341     }
342
343     if (ctx->argc != 3 && ctx->argc != 5) {
344         /* If a parent_name is specified, a tag must be specified as well. */
345         VLOG_WARN("Invalid arguments to lport-add.");
346         return;
347     }
348
349     if (ctx->argc == 5) {
350         /* Validate tag. */
351         if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
352             VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
353             return;
354         }
355     }
356
357     /* Create the logical port. */
358     lport = nbrec_logical_port_insert(nb_ctx->txn);
359     nbrec_logical_port_set_name(lport, ctx->argv[2]);
360     if (ctx->argc == 5) {
361         nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
362         nbrec_logical_port_set_tag(lport, &tag, 1);
363     }
364
365     /* Insert the logical port into the logical switch. */
366     nbrec_logical_switch_verify_ports(lswitch);
367     struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
368                                                     (lswitch->n_ports + 1));
369     memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
370     new_ports[lswitch->n_ports] = lport;
371     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
372     free(new_ports);
373 }
374
375 /* Removes lport 'lswitch->ports[idx]'. */
376 static void
377 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
378 {
379     const struct nbrec_logical_port *lport = lswitch->ports[idx];
380
381     /* First remove 'lport' from the array of ports.  This is what will
382      * actually cause the logical port to be deleted when the transaction is
383      * sent to the database server (due to garbage collection). */
384     struct nbrec_logical_port **new_ports
385         = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
386     new_ports[idx] = new_ports[lswitch->n_ports - 1];
387     nbrec_logical_switch_verify_ports(lswitch);
388     nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
389     free(new_ports);
390
391     /* Delete 'lport' from the IDL.  This won't have a real effect on the
392      * database server (the IDL will suppress it in fact) but it means that it
393      * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
394     nbrec_logical_port_delete(lport);
395 }
396
397 static void
398 nbctl_lport_del(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     /* Find the switch that contains 'lport', then delete it. */
409     const struct nbrec_logical_switch *lswitch;
410     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) {
411         for (size_t i = 0; i < lswitch->n_ports; i++) {
412             if (lswitch->ports[i] == lport) {
413                 remove_lport(lswitch, i);
414                 return;
415             }
416         }
417     }
418
419     VLOG_WARN("logical port %s is not part of any logical switch",
420               ctx->argv[1]);
421 }
422
423 static void
424 nbctl_lport_list(struct ovs_cmdl_context *ctx)
425 {
426     struct nbctl_context *nb_ctx = ctx->pvt;
427     const char *id = ctx->argv[1];
428     const struct nbrec_logical_switch *lswitch;
429     struct smap lports;
430     size_t i;
431
432     lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
433     if (!lswitch) {
434         return;
435     }
436
437     smap_init(&lports);
438     for (i = 0; i < lswitch->n_ports; i++) {
439         const struct nbrec_logical_port *lport = lswitch->ports[i];
440         smap_add_format(&lports, lport->name, UUID_FMT " (%s)",
441                         UUID_ARGS(&lport->header_.uuid), lport->name);
442     }
443     const struct smap_node **nodes = smap_sort(&lports);
444     for (i = 0; i < smap_count(&lports); i++) {
445         const struct smap_node *node = nodes[i];
446         printf("%s\n", node->value);
447     }
448     smap_destroy(&lports);
449     free(nodes);
450 }
451
452 static void
453 nbctl_lport_get_parent(struct ovs_cmdl_context *ctx)
454 {
455     struct nbctl_context *nb_ctx = ctx->pvt;
456     const struct nbrec_logical_port *lport;
457
458     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
459     if (!lport) {
460         return;
461     }
462
463     if (lport->parent_name) {
464         printf("%s\n", lport->parent_name);
465     }
466 }
467
468 static void
469 nbctl_lport_get_tag(struct ovs_cmdl_context *ctx)
470 {
471     struct nbctl_context *nb_ctx = ctx->pvt;
472     const struct nbrec_logical_port *lport;
473
474     lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
475     if (!lport) {
476         return;
477     }
478
479     if (lport->n_tag > 0) {
480         printf("%"PRId64"\n", lport->tag[0]);
481     }
482 }
483
484 static void
485 nbctl_lport_set_external_id(struct ovs_cmdl_context *ctx)
486 {
487     struct nbctl_context *nb_ctx = ctx->pvt;
488     const char *id = ctx->argv[1];
489     const struct nbrec_logical_port *lport;
490     struct smap new_external_ids;
491
492     lport = lport_by_name_or_uuid(nb_ctx, id);
493     if (!lport) {
494         return;
495     }
496
497     smap_init(&new_external_ids);
498     smap_clone(&new_external_ids, &lport->external_ids);
499     if (ctx->argc == 4) {
500         smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
501     } else {
502         smap_remove(&new_external_ids, ctx->argv[2]);
503     }
504     nbrec_logical_port_set_external_ids(lport, &new_external_ids);
505     smap_destroy(&new_external_ids);
506 }
507
508 static void
509 nbctl_lport_get_external_id(struct ovs_cmdl_context *ctx)
510 {
511     struct nbctl_context *nb_ctx = ctx->pvt;
512     const char *id = ctx->argv[1];
513     const struct nbrec_logical_port *lport;
514
515     lport = lport_by_name_or_uuid(nb_ctx, id);
516     if (!lport) {
517         return;
518     }
519
520     if (ctx->argc == 3) {
521         const char *key = ctx->argv[2];
522         const char *value;
523
524         /* List one external ID */
525
526         value = smap_get(&lport->external_ids, key);
527         if (value) {
528             printf("%s\n", value);
529         }
530     } else {
531         struct smap_node *node;
532
533         /* List all external IDs */
534
535         SMAP_FOR_EACH(node, &lport->external_ids) {
536             printf("%s=%s\n", node->key, node->value);
537         }
538     }
539 }
540
541 static void
542 nbctl_lport_set_macs(struct ovs_cmdl_context *ctx)
543 {
544     struct nbctl_context *nb_ctx = ctx->pvt;
545     const char *id = ctx->argv[1];
546     const struct nbrec_logical_port *lport;
547
548     lport = lport_by_name_or_uuid(nb_ctx, id);
549     if (!lport) {
550         return;
551     }
552
553     nbrec_logical_port_set_macs(lport,
554             (const char **) ctx->argv + 2, ctx->argc - 2);
555 }
556
557 static void
558 nbctl_lport_get_macs(struct ovs_cmdl_context *ctx)
559 {
560     struct nbctl_context *nb_ctx = ctx->pvt;
561     const char *id = ctx->argv[1];
562     const struct nbrec_logical_port *lport;
563     struct svec macs;
564     const char *mac;
565     size_t i;
566
567     lport = lport_by_name_or_uuid(nb_ctx, id);
568     if (!lport) {
569         return;
570     }
571
572     svec_init(&macs);
573     for (i = 0; i < lport->n_macs; i++) {
574         svec_add(&macs, lport->macs[i]);
575     }
576     svec_sort(&macs);
577     SVEC_FOR_EACH(i, mac, &macs) {
578         printf("%s\n", mac);
579     }
580     svec_destroy(&macs);
581 }
582
583 static void
584 nbctl_lport_set_port_security(struct ovs_cmdl_context *ctx)
585 {
586     struct nbctl_context *nb_ctx = ctx->pvt;
587     const char *id = ctx->argv[1];
588     const struct nbrec_logical_port *lport;
589
590     lport = lport_by_name_or_uuid(nb_ctx, id);
591     if (!lport) {
592         return;
593     }
594
595     nbrec_logical_port_set_port_security(lport,
596             (const char **) ctx->argv + 2, ctx->argc - 2);
597 }
598
599 static void
600 nbctl_lport_get_port_security(struct ovs_cmdl_context *ctx)
601 {
602     struct nbctl_context *nb_ctx = ctx->pvt;
603     const char *id = ctx->argv[1];
604     const struct nbrec_logical_port *lport;
605     struct svec addrs;
606     const char *addr;
607     size_t i;
608
609     lport = lport_by_name_or_uuid(nb_ctx, id);
610     if (!lport) {
611         return;
612     }
613
614     svec_init(&addrs);
615     for (i = 0; i < lport->n_port_security; i++) {
616         svec_add(&addrs, lport->port_security[i]);
617     }
618     svec_sort(&addrs);
619     SVEC_FOR_EACH(i, addr, &addrs) {
620         printf("%s\n", addr);
621     }
622     svec_destroy(&addrs);
623 }
624
625 static void
626 nbctl_lport_get_up(struct ovs_cmdl_context *ctx)
627 {
628     struct nbctl_context *nb_ctx = ctx->pvt;
629     const char *id = ctx->argv[1];
630     const struct nbrec_logical_port *lport;
631
632     lport = lport_by_name_or_uuid(nb_ctx, id);
633     if (!lport) {
634         return;
635     }
636
637     printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
638 }
639
640 static void
641 nbctl_lport_set_enabled(struct ovs_cmdl_context *ctx)
642 {
643     struct nbctl_context *nb_ctx = ctx->pvt;
644     const char *id = ctx->argv[1];
645     const char *state = ctx->argv[2];
646     const struct nbrec_logical_port *lport;
647
648     lport = lport_by_name_or_uuid(nb_ctx, id);
649     if (!lport) {
650         return;
651     }
652
653     if (!strcasecmp(state, "enabled")) {
654         bool enabled = true;
655         nbrec_logical_port_set_enabled(lport, &enabled, 1);
656     } else if (!strcasecmp(state, "disabled")) {
657         bool enabled = false;
658         nbrec_logical_port_set_enabled(lport, &enabled, 1);
659     } else {
660         VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
661     }
662 }
663
664 static void
665 nbctl_lport_get_enabled(struct ovs_cmdl_context *ctx)
666 {
667     struct nbctl_context *nb_ctx = ctx->pvt;
668     const char *id = ctx->argv[1];
669     const struct nbrec_logical_port *lport;
670
671     lport = lport_by_name_or_uuid(nb_ctx, id);
672     if (!lport) {
673         return;
674     }
675
676     printf("%s\n",
677            (!lport->enabled || *lport->enabled) ? "enabled" : "disabled");
678 }
679
680 static void
681 nbctl_lport_set_type(struct ovs_cmdl_context *ctx)
682 {
683     struct nbctl_context *nb_ctx = ctx->pvt;
684     const char *id = ctx->argv[1];
685     const char *type = ctx->argv[2];
686     const struct nbrec_logical_port *lport;
687
688     lport = lport_by_name_or_uuid(nb_ctx, id);
689     if (!lport) {
690         return;
691     }
692
693     nbrec_logical_port_set_type(lport, type);
694 }
695
696 static void
697 nbctl_lport_get_type(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
703     lport = lport_by_name_or_uuid(nb_ctx, id);
704     if (!lport) {
705         return;
706     }
707
708     printf("%s\n", lport->type);
709 }
710
711 static void
712 nbctl_lport_set_options(struct ovs_cmdl_context *ctx)
713 {
714     struct nbctl_context *nb_ctx = ctx->pvt;
715     const char *id = ctx->argv[1];
716     const struct nbrec_logical_port *lport;
717     size_t i;
718     struct smap options = SMAP_INITIALIZER(&options);
719
720     lport = lport_by_name_or_uuid(nb_ctx, id);
721     if (!lport) {
722         return;
723     }
724
725     for (i = 2; i < ctx->argc; i++) {
726         char *key, *value;
727         value = xstrdup(ctx->argv[i]);
728         key = strsep(&value, "=");
729         if (value) {
730             smap_add(&options, key, value);
731         }
732         free(key);
733     }
734
735     nbrec_logical_port_set_options(lport, &options);
736
737     smap_destroy(&options);
738 }
739
740 static void
741 nbctl_lport_get_options(struct ovs_cmdl_context *ctx)
742 {
743     struct nbctl_context *nb_ctx = ctx->pvt;
744     const char *id = ctx->argv[1];
745     const struct nbrec_logical_port *lport;
746     struct smap_node *node;
747
748     lport = lport_by_name_or_uuid(nb_ctx, id);
749     if (!lport) {
750         return;
751     }
752
753     SMAP_FOR_EACH(node, &lport->options) {
754         printf("%s=%s\n", node->key, node->value);
755     }
756 }
757
758 enum {
759     DIR_FROM_LPORT,
760     DIR_TO_LPORT
761 };
762
763 static int
764 dir_encode(const char *dir)
765 {
766     if (!strcmp(dir, "from-lport")) {
767         return DIR_FROM_LPORT;
768     } else if (!strcmp(dir, "to-lport")) {
769         return DIR_TO_LPORT;
770     }
771
772     OVS_NOT_REACHED();
773 }
774
775 static int
776 acl_cmp(const void *acl1_, const void *acl2_)
777 {
778     const struct nbrec_acl *const *acl1p = acl1_;
779     const struct nbrec_acl *const *acl2p = acl2_;
780     const struct nbrec_acl *acl1 = *acl1p;
781     const struct nbrec_acl *acl2 = *acl2p;
782
783     int dir1 = dir_encode(acl1->direction);
784     int dir2 = dir_encode(acl2->direction);
785
786     if (dir1 != dir2) {
787         return dir1 < dir2 ? -1 : 1;
788     } else if (acl1->priority != acl2->priority) {
789         return acl1->priority > acl2->priority ? -1 : 1;
790     } else {
791         return strcmp(acl1->match, acl2->match);
792     }
793 }
794
795 static void
796 nbctl_acl_list(struct ovs_cmdl_context *ctx)
797 {
798     const struct nbrec_logical_switch *lswitch;
799     struct nbctl_context *nb_ctx = ctx->pvt;
800     const struct nbrec_acl **acls;
801     size_t i;
802
803     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
804     if (!lswitch) {
805         return;
806     }
807
808     acls = xmalloc(sizeof *acls * lswitch->n_acls);
809     for (i = 0; i < lswitch->n_acls; i++) {
810         acls[i] = lswitch->acls[i];
811     }
812
813     qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
814
815     for (i = 0; i < lswitch->n_acls; i++) {
816         const struct nbrec_acl *acl = acls[i];
817         printf("%10s %5"PRId64" (%s) %s%s\n", acl->direction, acl->priority,
818                 acl->match, acl->action, acl->log ? " log" : "");
819     }
820
821     free(acls);
822 }
823
824 static void
825 nbctl_acl_add(struct ovs_cmdl_context *ctx)
826 {
827     const struct nbrec_logical_switch *lswitch;
828     struct nbctl_context *nb_ctx = ctx->pvt;
829     const char *action = ctx->argv[5];
830     const char *direction;
831     int64_t priority;
832
833     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
834     if (!lswitch) {
835         return;
836     }
837
838     /* Validate direction.  Only require the first letter. */
839     if (ctx->argv[2][0] == 't') {
840         direction = "to-lport";
841     } else if (ctx->argv[2][0] == 'f') {
842         direction = "from-lport";
843     } else {
844         VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
845         return;
846     }
847
848     /* Validate priority. */
849     if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
850         || priority > 65535) {
851         VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
852         return;
853     }
854
855     /* Validate action. */
856     if (strcmp(action, "allow") && strcmp(action, "allow-related")
857         && strcmp(action, "drop") && strcmp(action, "reject")) {
858         VLOG_WARN("Invalid action '%s'", action);
859         return;
860     }
861
862     /* Create the acl. */
863     struct nbrec_acl *acl = nbrec_acl_insert(nb_ctx->txn);
864     nbrec_acl_set_priority(acl, priority);
865     nbrec_acl_set_direction(acl, direction);
866     nbrec_acl_set_match(acl, ctx->argv[4]);
867     nbrec_acl_set_action(acl, action);
868     if (ctx->argc == 7 && ctx->argv[6][0] == 'l') {
869         nbrec_acl_set_log(acl, true);
870     }
871
872     /* Insert the acl into the logical switch. */
873     nbrec_logical_switch_verify_acls(lswitch);
874     struct nbrec_acl **new_acls = xmalloc(sizeof *new_acls *
875                                           (lswitch->n_acls + 1));
876     memcpy(new_acls, lswitch->acls, sizeof *new_acls * lswitch->n_acls);
877     new_acls[lswitch->n_acls] = acl;
878     nbrec_logical_switch_set_acls(lswitch, new_acls, lswitch->n_acls + 1);
879     free(new_acls);
880 }
881
882 static void
883 nbctl_acl_del(struct ovs_cmdl_context *ctx)
884 {
885     const struct nbrec_logical_switch *lswitch;
886     struct nbctl_context *nb_ctx = ctx->pvt;
887     const char *direction;
888     int64_t priority = 0;
889
890     lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
891     if (!lswitch) {
892         return;
893     }
894
895     if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
896         VLOG_WARN("Invalid number of arguments");
897         return;
898     }
899
900     if (ctx->argc == 2) {
901         /* If direction, priority, and match are not specified, delete
902          * all ACLs. */
903         nbrec_logical_switch_verify_acls(lswitch);
904         nbrec_logical_switch_set_acls(lswitch, NULL, 0);
905         return;
906     }
907
908     /* Validate direction.  Only require first letter. */
909     if (ctx->argv[2][0] == 't') {
910         direction = "to-lport";
911     } else if (ctx->argv[2][0] == 'f') {
912         direction = "from-lport";
913     } else {
914         VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
915         return;
916     }
917
918     /* If priority and match are not specified, delete all ACLs with the
919      * specified direction. */
920     if (ctx->argc == 3) {
921         struct nbrec_acl **new_acls
922             = xmalloc(sizeof *new_acls * lswitch->n_acls);
923
924         int n_acls = 0;
925         for (size_t i = 0; i < lswitch->n_acls; i++) {
926             if (strcmp(direction, lswitch->acls[i]->direction)) {
927                 new_acls[n_acls++] = lswitch->acls[i];
928             }
929         }
930
931         nbrec_logical_switch_verify_acls(lswitch);
932         nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
933         free(new_acls);
934         return;
935     }
936
937     /* Validate priority. */
938     if (!ovs_scan(ctx->argv[3], "%"SCNd64, &priority) || priority < 1
939         || priority > 65535) {
940         VLOG_WARN("Invalid priority '%s'", ctx->argv[3]);
941         return;
942     }
943
944     /* Remove the matching rule. */
945     for (size_t i = 0; i < lswitch->n_acls; i++) {
946         struct nbrec_acl *acl = lswitch->acls[i];
947
948         if (priority == acl->priority && !strcmp(ctx->argv[4], acl->match) &&
949              !strcmp(direction, acl->direction)) {
950             struct nbrec_acl **new_acls
951                 = xmemdup(lswitch->acls, sizeof *new_acls * lswitch->n_acls);
952             new_acls[i] = lswitch->acls[lswitch->n_acls - 1];
953             nbrec_logical_switch_verify_acls(lswitch);
954             nbrec_logical_switch_set_acls(lswitch, new_acls,
955                                           lswitch->n_acls - 1);
956             free(new_acls);
957             return;
958         }
959     }
960 }
961 \f
962 static void
963 parse_options(int argc, char *argv[])
964 {
965     enum {
966         VLOG_OPTION_ENUMS,
967     };
968     static const struct option long_options[] = {
969         {"db", required_argument, NULL, 'd'},
970         {"help", no_argument, NULL, 'h'},
971         {"options", no_argument, NULL, 'o'},
972         {"version", no_argument, NULL, 'V'},
973         VLOG_LONG_OPTIONS,
974         STREAM_SSL_LONG_OPTIONS,
975         {NULL, 0, NULL, 0},
976     };
977     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
978
979     for (;;) {
980         int c;
981
982         c = getopt_long(argc, argv, short_options, long_options, NULL);
983         if (c == -1) {
984             break;
985         }
986
987         switch (c) {
988         VLOG_OPTION_HANDLERS;
989         STREAM_SSL_OPTION_HANDLERS;
990
991         case 'd':
992             db = optarg;
993             break;
994
995         case 'h':
996             usage();
997             exit(EXIT_SUCCESS);
998
999         case 'o':
1000             ovs_cmdl_print_options(long_options);
1001             exit(EXIT_SUCCESS);
1002
1003         case 'V':
1004             ovs_print_version(0, 0);
1005             exit(EXIT_SUCCESS);
1006
1007         default:
1008             break;
1009         }
1010     }
1011
1012     if (!db) {
1013         db = default_db();
1014     }
1015
1016     free(short_options);
1017 }
1018
1019 static const struct ovs_cmdl_command all_commands[] = {
1020     {
1021         .name = "show",
1022         .usage = "[LSWITCH]",
1023         .min_args = 0,
1024         .max_args = 1,
1025         .handler = nbctl_show,
1026     },
1027     {
1028         .name = "lswitch-add",
1029         .usage = "[LSWITCH]",
1030         .min_args = 0,
1031         .max_args = 1,
1032         .handler = nbctl_lswitch_add,
1033     },
1034     {
1035         .name = "lswitch-del",
1036         .usage = "LSWITCH",
1037         .min_args = 1,
1038         .max_args = 1,
1039         .handler = nbctl_lswitch_del,
1040     },
1041     {
1042         .name = "lswitch-list",
1043         .usage = "",
1044         .min_args = 0,
1045         .max_args = 0,
1046         .handler = nbctl_lswitch_list,
1047     },
1048     {
1049         .name = "lswitch-set-external-id",
1050         .usage = "LSWITCH KEY [VALUE]",
1051         .min_args = 2,
1052         .max_args = 3,
1053         .handler = nbctl_lswitch_set_external_id,
1054     },
1055     {
1056         .name = "lswitch-get-external-id",
1057         .usage = "LSWITCH [KEY]",
1058         .min_args = 1,
1059         .max_args = 2,
1060         .handler = nbctl_lswitch_get_external_id,
1061     },
1062     {
1063         .name = "acl-add",
1064         .usage = "LSWITCH DIRECTION PRIORITY MATCH ACTION [log]",
1065         .min_args = 5,
1066         .max_args = 6,
1067         .handler = nbctl_acl_add,
1068     },
1069     {
1070         .name = "acl-del",
1071         .usage = "LSWITCH [DIRECTION [PRIORITY MATCH]]",
1072         .min_args = 1,
1073         .max_args = 4,
1074         .handler = nbctl_acl_del,
1075     },
1076     {
1077         .name = "acl-list",
1078         .usage = "LSWITCH",
1079         .min_args = 1,
1080         .max_args = 1,
1081         .handler = nbctl_acl_list,
1082     },
1083     {
1084         .name = "lport-add",
1085         .usage = "LSWITCH LPORT [PARENT] [TAG]",
1086         .min_args = 2,
1087         .max_args = 4,
1088         .handler = nbctl_lport_add,
1089     },
1090     {
1091         .name = "lport-del",
1092         .usage = "LPORT",
1093         .min_args = 1,
1094         .max_args = 1,
1095         .handler = nbctl_lport_del,
1096     },
1097     {
1098         .name = "lport-list",
1099         .usage = "LSWITCH",
1100         .min_args = 1,
1101         .max_args = 1,
1102         .handler = nbctl_lport_list,
1103     },
1104     {
1105         .name = "lport-get-parent",
1106         .usage = "LPORT",
1107         .min_args = 1,
1108         .max_args = 1,
1109         .handler = nbctl_lport_get_parent,
1110     },
1111     {
1112         .name = "lport-get-tag",
1113         .usage = "LPORT",
1114         .min_args = 1,
1115         .max_args = 1,
1116         .handler = nbctl_lport_get_tag,
1117     },
1118     {
1119         .name = "lport-set-external-id",
1120         .usage = "LPORT KEY [VALUE]",
1121         .min_args = 2,
1122         .max_args = 3,
1123         .handler = nbctl_lport_set_external_id,
1124     },
1125     {
1126         .name = "lport-get-external-id",
1127         .usage = "LPORT [KEY]",
1128         .min_args = 1,
1129         .max_args = 2,
1130         .handler = nbctl_lport_get_external_id,
1131     },
1132     {
1133         .name = "lport-set-macs",
1134         .usage = "LPORT [MAC]...",
1135         .min_args = 1,
1136         /* Accept however many arguments the system will allow. */
1137         .max_args = INT_MAX,
1138         .handler = nbctl_lport_set_macs,
1139     },
1140     {
1141         .name = "lport-get-macs",
1142         .usage = "LPORT",
1143         .min_args = 1,
1144         .max_args = 1,
1145         .handler = nbctl_lport_get_macs,
1146     },
1147     {
1148         .name = "lport-set-port-security",
1149         .usage = "LPORT [ADDRS]...",
1150         .min_args = 0,
1151         /* Accept however many arguments the system will allow. */
1152         .max_args = INT_MAX,
1153         .handler = nbctl_lport_set_port_security,
1154     },
1155     {
1156         .name = "lport-get-port-security",
1157         .usage = "LPORT",
1158         .min_args = 1,
1159         .max_args = 1,
1160         .handler = nbctl_lport_get_port_security,
1161     },
1162     {
1163         .name = "lport-get-up",
1164         .usage = "LPORT",
1165         .min_args = 1,
1166         .max_args = 1,
1167         .handler = nbctl_lport_get_up,
1168     },
1169     {
1170         .name = "lport-set-enabled",
1171         .usage = "LPORT STATE",
1172         .min_args = 2,
1173         .max_args = 2,
1174         .handler = nbctl_lport_set_enabled,
1175     },
1176     {
1177         .name = "lport-get-enabled",
1178         .usage = "LPORT",
1179         .min_args = 1,
1180         .max_args = 1,
1181         .handler = nbctl_lport_get_enabled,
1182     },
1183     {
1184         .name = "lport-set-type",
1185         .usage = "LPORT TYPE",
1186         .min_args = 2,
1187         .max_args = 2,
1188         .handler = nbctl_lport_set_type,
1189     },
1190     {
1191         .name = "lport-get-type",
1192         .usage = "LPORT",
1193         .min_args = 1,
1194         .max_args = 1,
1195         .handler = nbctl_lport_get_type,
1196     },
1197     {
1198         .name = "lport-set-options",
1199         .usage = "LPORT KEY=VALUE [KEY=VALUE]...",
1200         .min_args = 1,
1201         .max_args = INT_MAX,
1202         .handler = nbctl_lport_set_options
1203     },
1204     {
1205         .name = "lport-get-options",
1206         .usage = "LPORT",
1207         .min_args = 1,
1208         .max_args = 1,
1209         .handler = nbctl_lport_get_options,
1210     },
1211
1212     {
1213         /* sentinel */
1214         .name = NULL,
1215     },
1216 };
1217
1218 static const struct ovs_cmdl_command *
1219 get_all_commands(void)
1220 {
1221     return all_commands;
1222 }
1223
1224 static const char *
1225 default_db(void)
1226 {
1227     static char *def;
1228     if (!def) {
1229         def = getenv("OVN_NB_DB");
1230         if (!def) {
1231             def = xasprintf("unix:%s/db.sock", ovs_rundir());
1232         }
1233     }
1234     return def;
1235 }
1236
1237 int
1238 main(int argc, char *argv[])
1239 {
1240     extern struct vlog_module VLM_reconnect;
1241     struct ovs_cmdl_context ctx;
1242     struct nbctl_context nb_ctx = { .idl = NULL, };
1243     enum ovsdb_idl_txn_status txn_status;
1244     unsigned int seqno;
1245     int res = 0;
1246     char *args;
1247
1248     fatal_ignore_sigpipe();
1249     set_program_name(argv[0]);
1250     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
1251     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
1252     parse_options(argc, argv);
1253     nbrec_init();
1254
1255     args = process_escape_args(argv);
1256
1257     nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
1258     ctx.pvt = &nb_ctx;
1259     ctx.argc = argc - optind;
1260     ctx.argv = argv + optind;
1261
1262     seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
1263     for (;;) {
1264         ovsdb_idl_run(nb_ctx.idl);
1265
1266         if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
1267             int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
1268             VLOG_ERR("%s: database connection failed (%s)",
1269                     db, ovs_retval_to_string(retval));
1270             res = 1;
1271             break;
1272         }
1273
1274         if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
1275             nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
1276             ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
1277             ovs_cmdl_run_command(&ctx, get_all_commands());
1278             txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
1279             if (txn_status == TXN_TRY_AGAIN) {
1280                 ovsdb_idl_txn_destroy(nb_ctx.txn);
1281                 nb_ctx.txn = NULL;
1282                 continue;
1283             } else {
1284                 break;
1285             }
1286         }
1287
1288         if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
1289             ovsdb_idl_wait(nb_ctx.idl);
1290             poll_block();
1291         }
1292     }
1293
1294     if (nb_ctx.txn) {
1295         ovsdb_idl_txn_destroy(nb_ctx.txn);
1296     }
1297     ovsdb_idl_destroy(nb_ctx.idl);
1298     free(args);
1299
1300     exit(res);
1301 }