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:
6 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include "command-line.h"
24 #include "fatal-signal.h"
25 #include "ovn/lib/ovn-nb-idl.h"
26 #include "poll-loop.h"
30 #include "stream-ssl.h"
33 #include "openvswitch/vlog.h"
35 VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
37 struct nbctl_context {
38 struct ovsdb_idl *idl;
39 struct ovsdb_idl_txn *txn;
42 static const char *db;
44 static const char *default_db(void);
50 %s: OVN northbound DB management utility\n\
51 usage: %s [OPTIONS] COMMAND [ARG...]\n\
54 show print overview of database contents\n\
55 show LSWITCH print overview of database contents for LSWITCH\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\
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\
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\
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\
105 --db=DATABASE connect to DATABASE\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());
112 stream_usage("database", true, true, false);
115 static const struct nbrec_logical_switch *
116 lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
118 const struct nbrec_logical_switch *lswitch = NULL;
119 bool is_uuid = false;
120 bool duplicate = false;
121 struct uuid lswitch_uuid;
123 if (uuid_from_string(&lswitch_uuid, id)) {
125 lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
130 const struct nbrec_logical_switch *iter;
132 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
133 if (strcmp(iter->name, id)) {
137 VLOG_WARN("There is more than one logical switch named '%s'. "
147 if (!lswitch && !duplicate) {
148 VLOG_WARN("lswitch not found for %s: '%s'",
149 is_uuid ? "UUID" : "name", id);
156 print_lswitch(const struct nbrec_logical_switch *lswitch)
158 printf(" lswitch "UUID_FMT" (%s)\n",
159 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
161 for (size_t i = 0; i < lswitch->n_ports; i++) {
162 const struct nbrec_logical_port *lport = lswitch->ports[i];
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]);
171 for (size_t j = 0; j < lport->n_macs; j++) {
172 printf(" %s", lport->macs[j]);
180 nbctl_show(struct ovs_cmdl_context *ctx)
182 struct nbctl_context *nb_ctx = ctx->pvt;
183 const struct nbrec_logical_switch *lswitch;
185 if (ctx->argc == 2) {
186 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
188 print_lswitch(lswitch);
191 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
192 print_lswitch(lswitch);
198 nbctl_lswitch_add(struct ovs_cmdl_context *ctx)
200 struct nbctl_context *nb_ctx = ctx->pvt;
201 struct nbrec_logical_switch *lswitch;
203 lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
204 if (ctx->argc == 2) {
205 nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
210 nbctl_lswitch_del(struct ovs_cmdl_context *ctx)
212 struct nbctl_context *nb_ctx = ctx->pvt;
213 const char *id = ctx->argv[1];
214 const struct nbrec_logical_switch *lswitch;
216 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
221 nbrec_logical_switch_delete(lswitch);
225 nbctl_lswitch_list(struct ovs_cmdl_context *ctx)
227 struct nbctl_context *nb_ctx = ctx->pvt;
228 const struct nbrec_logical_switch *lswitch;
229 struct smap lswitches;
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);
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);
241 smap_destroy(&lswitches);
246 nbctl_lswitch_set_external_id(struct ovs_cmdl_context *ctx)
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;
253 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
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]);
263 smap_remove(&new_external_ids, ctx->argv[2]);
265 nbrec_logical_switch_set_external_ids(lswitch, &new_external_ids);
266 smap_destroy(&new_external_ids);
270 nbctl_lswitch_get_external_id(struct ovs_cmdl_context *ctx)
272 struct nbctl_context *nb_ctx = ctx->pvt;
273 const char *id = ctx->argv[1];
274 const struct nbrec_logical_switch *lswitch;
276 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
281 if (ctx->argc == 3) {
282 const char *key = ctx->argv[2];
285 /* List one external ID */
287 value = smap_get(&lswitch->external_ids, key);
289 printf("%s\n", value);
292 struct smap_node *node;
294 /* List all external IDs */
296 SMAP_FOR_EACH(node, &lswitch->external_ids) {
297 printf("%s=%s\n", node->key, node->value);
302 static const struct nbrec_logical_port *
303 lport_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
305 const struct nbrec_logical_port *lport = NULL;
306 bool is_uuid = false;
307 struct uuid lport_uuid;
309 if (uuid_from_string(&lport_uuid, id)) {
311 lport = nbrec_logical_port_get_for_uuid(nb_ctx->idl, &lport_uuid);
315 NBREC_LOGICAL_PORT_FOR_EACH(lport, nb_ctx->idl) {
316 if (!strcmp(lport->name, id)) {
323 VLOG_WARN("lport not found for %s: '%s'",
324 is_uuid ? "UUID" : "name", id);
331 nbctl_lport_add(struct ovs_cmdl_context *ctx)
333 struct nbctl_context *nb_ctx = ctx->pvt;
334 struct nbrec_logical_port *lport;
335 const struct nbrec_logical_switch *lswitch;
338 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
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.");
349 if (ctx->argc == 5) {
351 if (!ovs_scan(ctx->argv[4], "%"SCNd64, &tag) || tag < 0 || tag > 4095) {
352 VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
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);
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);
375 /* Removes lport 'lswitch->ports[idx]'. */
377 remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
379 const struct nbrec_logical_port *lport = lswitch->ports[idx];
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);
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);
398 nbctl_lport_del(struct ovs_cmdl_context *ctx)
400 struct nbctl_context *nb_ctx = ctx->pvt;
401 const struct nbrec_logical_port *lport;
403 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
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);
419 VLOG_WARN("logical port %s is not part of any logical switch",
424 nbctl_lport_list(struct ovs_cmdl_context *ctx)
426 struct nbctl_context *nb_ctx = ctx->pvt;
427 const char *id = ctx->argv[1];
428 const struct nbrec_logical_switch *lswitch;
432 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
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);
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);
448 smap_destroy(&lports);
453 nbctl_lport_get_parent(struct ovs_cmdl_context *ctx)
455 struct nbctl_context *nb_ctx = ctx->pvt;
456 const struct nbrec_logical_port *lport;
458 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
463 if (lport->parent_name) {
464 printf("%s\n", lport->parent_name);
469 nbctl_lport_get_tag(struct ovs_cmdl_context *ctx)
471 struct nbctl_context *nb_ctx = ctx->pvt;
472 const struct nbrec_logical_port *lport;
474 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
479 if (lport->n_tag > 0) {
480 printf("%"PRId64"\n", lport->tag[0]);
485 nbctl_lport_set_external_id(struct ovs_cmdl_context *ctx)
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;
492 lport = lport_by_name_or_uuid(nb_ctx, id);
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]);
502 smap_remove(&new_external_ids, ctx->argv[2]);
504 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
505 smap_destroy(&new_external_ids);
509 nbctl_lport_get_external_id(struct ovs_cmdl_context *ctx)
511 struct nbctl_context *nb_ctx = ctx->pvt;
512 const char *id = ctx->argv[1];
513 const struct nbrec_logical_port *lport;
515 lport = lport_by_name_or_uuid(nb_ctx, id);
520 if (ctx->argc == 3) {
521 const char *key = ctx->argv[2];
524 /* List one external ID */
526 value = smap_get(&lport->external_ids, key);
528 printf("%s\n", value);
531 struct smap_node *node;
533 /* List all external IDs */
535 SMAP_FOR_EACH(node, &lport->external_ids) {
536 printf("%s=%s\n", node->key, node->value);
542 nbctl_lport_set_macs(struct ovs_cmdl_context *ctx)
544 struct nbctl_context *nb_ctx = ctx->pvt;
545 const char *id = ctx->argv[1];
546 const struct nbrec_logical_port *lport;
548 lport = lport_by_name_or_uuid(nb_ctx, id);
553 nbrec_logical_port_set_macs(lport,
554 (const char **) ctx->argv + 2, ctx->argc - 2);
558 nbctl_lport_get_macs(struct ovs_cmdl_context *ctx)
560 struct nbctl_context *nb_ctx = ctx->pvt;
561 const char *id = ctx->argv[1];
562 const struct nbrec_logical_port *lport;
567 lport = lport_by_name_or_uuid(nb_ctx, id);
573 for (i = 0; i < lport->n_macs; i++) {
574 svec_add(&macs, lport->macs[i]);
577 SVEC_FOR_EACH(i, mac, &macs) {
584 nbctl_lport_set_port_security(struct ovs_cmdl_context *ctx)
586 struct nbctl_context *nb_ctx = ctx->pvt;
587 const char *id = ctx->argv[1];
588 const struct nbrec_logical_port *lport;
590 lport = lport_by_name_or_uuid(nb_ctx, id);
595 nbrec_logical_port_set_port_security(lport,
596 (const char **) ctx->argv + 2, ctx->argc - 2);
600 nbctl_lport_get_port_security(struct ovs_cmdl_context *ctx)
602 struct nbctl_context *nb_ctx = ctx->pvt;
603 const char *id = ctx->argv[1];
604 const struct nbrec_logical_port *lport;
609 lport = lport_by_name_or_uuid(nb_ctx, id);
615 for (i = 0; i < lport->n_port_security; i++) {
616 svec_add(&addrs, lport->port_security[i]);
619 SVEC_FOR_EACH(i, addr, &addrs) {
620 printf("%s\n", addr);
622 svec_destroy(&addrs);
626 nbctl_lport_get_up(struct ovs_cmdl_context *ctx)
628 struct nbctl_context *nb_ctx = ctx->pvt;
629 const char *id = ctx->argv[1];
630 const struct nbrec_logical_port *lport;
632 lport = lport_by_name_or_uuid(nb_ctx, id);
637 printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
641 nbctl_lport_set_enabled(struct ovs_cmdl_context *ctx)
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;
648 lport = lport_by_name_or_uuid(nb_ctx, id);
653 if (!strcasecmp(state, "enabled")) {
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);
660 VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
665 nbctl_lport_get_enabled(struct ovs_cmdl_context *ctx)
667 struct nbctl_context *nb_ctx = ctx->pvt;
668 const char *id = ctx->argv[1];
669 const struct nbrec_logical_port *lport;
671 lport = lport_by_name_or_uuid(nb_ctx, id);
677 (!lport->enabled || *lport->enabled) ? "enabled" : "disabled");
681 nbctl_lport_set_type(struct ovs_cmdl_context *ctx)
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;
688 lport = lport_by_name_or_uuid(nb_ctx, id);
693 nbrec_logical_port_set_type(lport, type);
697 nbctl_lport_get_type(struct ovs_cmdl_context *ctx)
699 struct nbctl_context *nb_ctx = ctx->pvt;
700 const char *id = ctx->argv[1];
701 const struct nbrec_logical_port *lport;
703 lport = lport_by_name_or_uuid(nb_ctx, id);
708 printf("%s\n", lport->type);
712 nbctl_lport_set_options(struct ovs_cmdl_context *ctx)
714 struct nbctl_context *nb_ctx = ctx->pvt;
715 const char *id = ctx->argv[1];
716 const struct nbrec_logical_port *lport;
718 struct smap options = SMAP_INITIALIZER(&options);
720 lport = lport_by_name_or_uuid(nb_ctx, id);
725 for (i = 2; i < ctx->argc; i++) {
727 value = xstrdup(ctx->argv[i]);
728 key = strsep(&value, "=");
730 smap_add(&options, key, value);
735 nbrec_logical_port_set_options(lport, &options);
737 smap_destroy(&options);
741 nbctl_lport_get_options(struct ovs_cmdl_context *ctx)
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;
748 lport = lport_by_name_or_uuid(nb_ctx, id);
753 SMAP_FOR_EACH(node, &lport->options) {
754 printf("%s=%s\n", node->key, node->value);
764 dir_encode(const char *dir)
766 if (!strcmp(dir, "from-lport")) {
767 return DIR_FROM_LPORT;
768 } else if (!strcmp(dir, "to-lport")) {
776 acl_cmp(const void *acl1_, const void *acl2_)
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;
783 int dir1 = dir_encode(acl1->direction);
784 int dir2 = dir_encode(acl2->direction);
787 return dir1 < dir2 ? -1 : 1;
788 } else if (acl1->priority != acl2->priority) {
789 return acl1->priority > acl2->priority ? -1 : 1;
791 return strcmp(acl1->match, acl2->match);
796 nbctl_acl_list(struct ovs_cmdl_context *ctx)
798 const struct nbrec_logical_switch *lswitch;
799 struct nbctl_context *nb_ctx = ctx->pvt;
800 const struct nbrec_acl **acls;
803 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
808 acls = xmalloc(sizeof *acls * lswitch->n_acls);
809 for (i = 0; i < lswitch->n_acls; i++) {
810 acls[i] = lswitch->acls[i];
813 qsort(acls, lswitch->n_acls, sizeof *acls, acl_cmp);
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" : "");
825 nbctl_acl_add(struct ovs_cmdl_context *ctx)
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;
833 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
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";
844 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
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]);
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);
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);
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);
883 nbctl_acl_del(struct ovs_cmdl_context *ctx)
885 const struct nbrec_logical_switch *lswitch;
886 struct nbctl_context *nb_ctx = ctx->pvt;
887 const char *direction;
888 int64_t priority = 0;
890 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
895 if (ctx->argc != 2 && ctx->argc != 3 && ctx->argc != 5) {
896 VLOG_WARN("Invalid number of arguments");
900 if (ctx->argc == 2) {
901 /* If direction, priority, and match are not specified, delete
903 nbrec_logical_switch_verify_acls(lswitch);
904 nbrec_logical_switch_set_acls(lswitch, NULL, 0);
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";
914 VLOG_WARN("Invalid direction '%s'", ctx->argv[2]);
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);
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];
931 nbrec_logical_switch_verify_acls(lswitch);
932 nbrec_logical_switch_set_acls(lswitch, new_acls, n_acls);
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]);
944 /* Remove the matching rule. */
945 for (size_t i = 0; i < lswitch->n_acls; i++) {
946 struct nbrec_acl *acl = lswitch->acls[i];
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);
963 parse_options(int argc, char *argv[])
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'},
974 STREAM_SSL_LONG_OPTIONS,
977 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
982 c = getopt_long(argc, argv, short_options, long_options, NULL);
988 VLOG_OPTION_HANDLERS;
989 STREAM_SSL_OPTION_HANDLERS;
1000 ovs_cmdl_print_options(long_options);
1004 ovs_print_version(0, 0);
1016 free(short_options);
1019 static const struct ovs_cmdl_command all_commands[] = {
1022 .usage = "[LSWITCH]",
1025 .handler = nbctl_show,
1028 .name = "lswitch-add",
1029 .usage = "[LSWITCH]",
1032 .handler = nbctl_lswitch_add,
1035 .name = "lswitch-del",
1039 .handler = nbctl_lswitch_del,
1042 .name = "lswitch-list",
1046 .handler = nbctl_lswitch_list,
1049 .name = "lswitch-set-external-id",
1050 .usage = "LSWITCH KEY [VALUE]",
1053 .handler = nbctl_lswitch_set_external_id,
1056 .name = "lswitch-get-external-id",
1057 .usage = "LSWITCH [KEY]",
1060 .handler = nbctl_lswitch_get_external_id,
1064 .usage = "LSWITCH DIRECTION PRIORITY MATCH ACTION [log]",
1067 .handler = nbctl_acl_add,
1071 .usage = "LSWITCH [DIRECTION [PRIORITY MATCH]]",
1074 .handler = nbctl_acl_del,
1081 .handler = nbctl_acl_list,
1084 .name = "lport-add",
1085 .usage = "LSWITCH LPORT [PARENT] [TAG]",
1088 .handler = nbctl_lport_add,
1091 .name = "lport-del",
1095 .handler = nbctl_lport_del,
1098 .name = "lport-list",
1102 .handler = nbctl_lport_list,
1105 .name = "lport-get-parent",
1109 .handler = nbctl_lport_get_parent,
1112 .name = "lport-get-tag",
1116 .handler = nbctl_lport_get_tag,
1119 .name = "lport-set-external-id",
1120 .usage = "LPORT KEY [VALUE]",
1123 .handler = nbctl_lport_set_external_id,
1126 .name = "lport-get-external-id",
1127 .usage = "LPORT [KEY]",
1130 .handler = nbctl_lport_get_external_id,
1133 .name = "lport-set-macs",
1134 .usage = "LPORT [MAC]...",
1136 /* Accept however many arguments the system will allow. */
1137 .max_args = INT_MAX,
1138 .handler = nbctl_lport_set_macs,
1141 .name = "lport-get-macs",
1145 .handler = nbctl_lport_get_macs,
1148 .name = "lport-set-port-security",
1149 .usage = "LPORT [ADDRS]...",
1151 /* Accept however many arguments the system will allow. */
1152 .max_args = INT_MAX,
1153 .handler = nbctl_lport_set_port_security,
1156 .name = "lport-get-port-security",
1160 .handler = nbctl_lport_get_port_security,
1163 .name = "lport-get-up",
1167 .handler = nbctl_lport_get_up,
1170 .name = "lport-set-enabled",
1171 .usage = "LPORT STATE",
1174 .handler = nbctl_lport_set_enabled,
1177 .name = "lport-get-enabled",
1181 .handler = nbctl_lport_get_enabled,
1184 .name = "lport-set-type",
1185 .usage = "LPORT TYPE",
1188 .handler = nbctl_lport_set_type,
1191 .name = "lport-get-type",
1195 .handler = nbctl_lport_get_type,
1198 .name = "lport-set-options",
1199 .usage = "LPORT KEY=VALUE [KEY=VALUE]...",
1201 .max_args = INT_MAX,
1202 .handler = nbctl_lport_set_options
1205 .name = "lport-get-options",
1209 .handler = nbctl_lport_get_options,
1218 static const struct ovs_cmdl_command *
1219 get_all_commands(void)
1221 return all_commands;
1229 def = getenv("OVN_NB_DB");
1231 def = xasprintf("unix:%s/db.sock", ovs_rundir());
1238 main(int argc, char *argv[])
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;
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);
1255 args = process_escape_args(argv);
1257 nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
1259 ctx.argc = argc - optind;
1260 ctx.argv = argv + optind;
1262 seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
1264 ovsdb_idl_run(nb_ctx.idl);
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));
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);
1288 if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
1289 ovsdb_idl_wait(nb_ctx.idl);
1295 ovsdb_idl_txn_destroy(nb_ctx.txn);
1297 ovsdb_idl_destroy(nb_ctx.idl);