]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/ovn-nbctl.c
ovn-controller: Avoid overlooking changes that occur during commit.
[mirror_ovs.git] / ovn / ovn-nbctl.c
CommitLineData
a416ff28
RB
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>
bf5fa52a 18#include <inttypes.h>
a416ff28
RB
19#include <stdlib.h>
20#include <stdio.h>
21
22#include "command-line.h"
23#include "dirs.h"
24#include "fatal-signal.h"
e3df8838 25#include "ovn/lib/ovn-nb-idl.h"
a416ff28 26#include "poll-loop.h"
afc9da0b 27#include "process.h"
a416ff28
RB
28#include "stream.h"
29#include "stream-ssl.h"
30#include "util.h"
31#include "openvswitch/vlog.h"
32
33VLOG_DEFINE_THIS_MODULE(ovn_nbctl);
34
35struct nbctl_context {
36 struct ovsdb_idl *idl;
37 struct ovsdb_idl_txn *txn;
38};
39
40static const char *db;
41
42static const char *default_db(void);
43
44static void
45usage(void)
46{
47 printf("\
48%s: OVN northbound DB management utility\n\
49usage: %s [OPTIONS] COMMAND [ARG...]\n\
50\n\
907a0edf
JP
51General commands:\n\
52 show print overview of database contents\n\
6cfe8161 53 show LSWITCH print overview of database contents for LSWITCH\n\
907a0edf 54\n\
a367622a
JP
55Logical 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\
a416ff28 63\n\
a367622a
JP
64Logical port commands:\n\
65 lport-add LSWITCH LPORT add logical port LPORT on LSWITCH\n\
bf5fa52a
RB
66 lport-add LSWITCH LPORT PARENT TAG\n\
67 add logical port LPORT on LSWITCH with PARENT\n\
68 on TAG\n\
a367622a
JP
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\
bf5fa52a
RB
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\
a367622a
JP
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\
2de82d90
BP
77 lport-set-macs LPORT [MAC]...\n\
78 set MAC addresses for LPORT.\n\
a367622a 79 lport-get-macs LPORT get a list of MAC addresses on LPORT\n\
92207865
BP
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\
a367622a 83 lport-get-up LPORT get state of LPORT ('up' or 'down')\n\
e9e8bcdf
RB
84 lport-set-enabled LPORT STATE\n\
85 set administrative state LPORT\n\
86 ('enabled' or 'disabled')\n\
87 lport-get-enabled LPORT get administrative state LPORT\n\
88 ('enabled' or 'disabled')\n\
a416ff28
RB
89\n\
90Options:\n\
91 --db=DATABASE connect to DATABASE\n\
92 (default: %s)\n\
93 -h, --help display this help message\n\
94 -o, --options list available options\n\
95 -V, --version display version information\n\
96", program_name, program_name, default_db());
97 vlog_usage();
98 stream_usage("database", true, true, false);
99}
100\f
101static const struct nbrec_logical_switch *
102lswitch_by_name_or_uuid(struct nbctl_context *nb_ctx, const char *id)
103{
104 const struct nbrec_logical_switch *lswitch = NULL;
105 bool is_uuid = false;
106 bool duplicate = false;
107 struct uuid lswitch_uuid;
108
109 if (uuid_from_string(&lswitch_uuid, id)) {
110 is_uuid = true;
111 lswitch = nbrec_logical_switch_get_for_uuid(nb_ctx->idl,
112 &lswitch_uuid);
c1f4da63
RB
113 }
114
115 if (!lswitch) {
a416ff28
RB
116 const struct nbrec_logical_switch *iter;
117
118 NBREC_LOGICAL_SWITCH_FOR_EACH(iter, nb_ctx->idl) {
119 if (strcmp(iter->name, id)) {
120 continue;
121 }
122 if (lswitch) {
123 VLOG_WARN("There is more than one logical switch named '%s'. "
124 "Use a UUID.", id);
125 lswitch = NULL;
126 duplicate = true;
127 break;
128 }
129 lswitch = iter;
130 }
131 }
132
133 if (!lswitch && !duplicate) {
134 VLOG_WARN("lswitch not found for %s: '%s'",
135 is_uuid ? "UUID" : "name", id);
136 }
137
138 return lswitch;
139}
140
907a0edf 141static void
445a266a 142print_lswitch(const struct nbrec_logical_switch *lswitch)
907a0edf 143{
907a0edf
JP
144 printf(" lswitch "UUID_FMT" (%s)\n",
145 UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
146
445a266a
BP
147 for (size_t i = 0; i < lswitch->n_ports; i++) {
148 const struct nbrec_logical_port *lport = lswitch->ports[i];
907a0edf 149
445a266a
BP
150 printf(" lport %s\n", lport->name);
151 if (lport->parent_name && lport->n_tag) {
152 printf(" parent: %s, tag:%"PRIu64"\n",
153 lport->parent_name, lport->tag[0]);
154 }
155 if (lport->n_macs) {
156 printf(" macs:");
157 for (size_t j = 0; j < lport->n_macs; j++) {
158 printf(" %s", lport->macs[j]);
907a0edf 159 }
445a266a 160 printf("\n");
907a0edf
JP
161 }
162 }
163}
164
165static void
166do_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) {
445a266a 174 print_lswitch(lswitch);
907a0edf
JP
175 }
176 } else {
177 NBREC_LOGICAL_SWITCH_FOR_EACH(lswitch, nb_ctx->idl) {
445a266a 178 print_lswitch(lswitch);
907a0edf
JP
179 }
180 }
181}
182
a416ff28
RB
183static void
184do_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
195static void
196do_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
210static void
211do_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
222static void
223do_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
246static void
247do_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);
ee98038f 265 if (value) {
a416ff28 266 printf("%s\n", value);
a416ff28
RB
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
279static const struct nbrec_logical_port *
280lport_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);
c1f4da63
RB
289 }
290
291 if (!lport) {
a416ff28
RB
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
307static void
308do_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;
bf5fa52a 313 int64_t tag;
a416ff28 314
c8453791 315 lswitch = lswitch_by_name_or_uuid(nb_ctx, ctx->argv[1]);
a416ff28
RB
316 if (!lswitch) {
317 return;
318 }
319
bf5fa52a 320 if (ctx->argc != 3 && ctx->argc != 5) {
445a266a 321 /* If a parent_name is specified, a tag must be specified as well. */
bf5fa52a
RB
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
445a266a 334 /* Create the logical port. */
a416ff28 335 lport = nbrec_logical_port_insert(nb_ctx->txn);
c8453791 336 nbrec_logical_port_set_name(lport, ctx->argv[2]);
bf5fa52a
RB
337 if (ctx->argc == 5) {
338 nbrec_logical_port_set_parent_name(lport, ctx->argv[3]);
339 nbrec_logical_port_set_tag(lport, &tag, 1);
340 }
445a266a
BP
341
342 /* Insert the logical port into the logical switch. */
343 nbrec_logical_switch_verify_ports(lswitch);
344 struct nbrec_logical_port **new_ports = xmalloc(sizeof *new_ports *
345 (lswitch->n_ports + 1));
346 memcpy(new_ports, lswitch->ports, sizeof *new_ports * lswitch->n_ports);
347 new_ports[lswitch->n_ports] = lport;
348 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports + 1);
349 free(new_ports);
350}
351
352/* Removes lport 'lswitch->ports[idx]'. */
353static void
354remove_lport(const struct nbrec_logical_switch *lswitch, size_t idx)
355{
356 const struct nbrec_logical_port *lport = lswitch->ports[idx];
357
358 /* First remove 'lport' from the array of ports. This is what will
359 * actually cause the logical port to be deleted when the transaction is
360 * sent to the database server (due to garbage collection). */
361 struct nbrec_logical_port **new_ports
362 = xmemdup(lswitch->ports, sizeof *new_ports * lswitch->n_ports);
363 new_ports[idx] = new_ports[lswitch->n_ports - 1];
364 nbrec_logical_switch_verify_ports(lswitch);
365 nbrec_logical_switch_set_ports(lswitch, new_ports, lswitch->n_ports - 1);
366 free(new_ports);
367
368 /* Delete 'lport' from the IDL. This won't have a real effect on the
369 * database server (the IDL will suppress it in fact) but it means that it
370 * won't show up when we iterate with NBREC_LOGICAL_PORT_FOR_EACH later. */
371 nbrec_logical_port_delete(lport);
a416ff28
RB
372}
373
374static void
375do_lport_del(struct ovs_cmdl_context *ctx)
376{
377 struct nbctl_context *nb_ctx = ctx->pvt;
378 const struct nbrec_logical_port *lport;
379
380 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
381 if (!lport) {
382 return;
383 }
384
445a266a
BP
385 /* Find the switch that contains 'lport', then delete it. */
386 const struct nbrec_logical_switch *lswitch;
387 NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, nb_ctx->idl) {
388 for (size_t i = 0; i < lswitch->n_ports; i++) {
389 if (lswitch->ports[i] == lport) {
390 remove_lport(lswitch, i);
391 return;
392 }
393 }
a416ff28 394 }
a416ff28 395
445a266a
BP
396 VLOG_WARN("logical port %s is not part of any logical switch",
397 ctx->argv[1]);
398}
a416ff28
RB
399
400static void
401do_lport_list(struct ovs_cmdl_context *ctx)
402{
403 struct nbctl_context *nb_ctx = ctx->pvt;
404 const char *id = ctx->argv[1];
445a266a 405 const struct nbrec_logical_switch *lswitch;
a416ff28 406
445a266a
BP
407 lswitch = lswitch_by_name_or_uuid(nb_ctx, id);
408 if (!lswitch) {
409 return;
a416ff28
RB
410 }
411
445a266a
BP
412 for (size_t i = 0; i < lswitch->n_ports; i++) {
413 const struct nbrec_logical_port *lport = lswitch->ports[i];
a416ff28
RB
414 printf(UUID_FMT " (%s)\n",
415 UUID_ARGS(&lport->header_.uuid), lport->name);
416 }
417}
418
bf5fa52a
RB
419static void
420do_lport_get_parent(struct ovs_cmdl_context *ctx)
421{
422 struct nbctl_context *nb_ctx = ctx->pvt;
423 const struct nbrec_logical_port *lport;
424
425 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
426 if (!lport) {
427 return;
428 }
429
430 if (lport->parent_name) {
431 printf("%s\n", lport->parent_name);
432 }
433}
434
435static void
436do_lport_get_tag(struct ovs_cmdl_context *ctx)
437{
438 struct nbctl_context *nb_ctx = ctx->pvt;
439 const struct nbrec_logical_port *lport;
440
441 lport = lport_by_name_or_uuid(nb_ctx, ctx->argv[1]);
442 if (!lport) {
443 return;
444 }
445
446 if (lport->n_tag > 0) {
447 printf("%"PRId64"\n", lport->tag[0]);
448 }
449}
450
a416ff28
RB
451static void
452do_lport_set_external_id(struct ovs_cmdl_context *ctx)
453{
454 struct nbctl_context *nb_ctx = ctx->pvt;
455 const char *id = ctx->argv[1];
456 const struct nbrec_logical_port *lport;
457 struct smap new_external_ids;
458
459 lport = lport_by_name_or_uuid(nb_ctx, id);
460 if (!lport) {
461 return;
462 }
463
464 smap_init(&new_external_ids);
465 smap_clone(&new_external_ids, &lport->external_ids);
466 if (ctx->argc == 4) {
467 smap_replace(&new_external_ids, ctx->argv[2], ctx->argv[3]);
468 } else {
469 smap_remove(&new_external_ids, ctx->argv[2]);
470 }
471 nbrec_logical_port_set_external_ids(lport, &new_external_ids);
472 smap_destroy(&new_external_ids);
473}
474
475static void
476do_lport_get_external_id(struct ovs_cmdl_context *ctx)
477{
478 struct nbctl_context *nb_ctx = ctx->pvt;
479 const char *id = ctx->argv[1];
480 const struct nbrec_logical_port *lport;
481
482 lport = lport_by_name_or_uuid(nb_ctx, id);
483 if (!lport) {
484 return;
485 }
486
487 if (ctx->argc == 3) {
488 const char *key = ctx->argv[2];
489 const char *value;
490
491 /* List one external ID */
492
493 value = smap_get(&lport->external_ids, key);
ee98038f 494 if (value) {
a416ff28 495 printf("%s\n", value);
a416ff28
RB
496 }
497 } else {
498 struct smap_node *node;
499
500 /* List all external IDs */
501
502 SMAP_FOR_EACH(node, &lport->external_ids) {
503 printf("%s=%s\n", node->key, node->value);
504 }
505 }
506}
507
508static void
509do_lport_set_macs(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 nbrec_logical_port_set_macs(lport,
521 (const char **) ctx->argv + 2, ctx->argc - 2);
522}
523
524static void
525do_lport_get_macs(struct ovs_cmdl_context *ctx)
526{
527 struct nbctl_context *nb_ctx = ctx->pvt;
528 const char *id = ctx->argv[1];
529 const struct nbrec_logical_port *lport;
530 size_t i;
531
532 lport = lport_by_name_or_uuid(nb_ctx, id);
533 if (!lport) {
534 return;
535 }
536
537 for (i = 0; i < lport->n_macs; i++) {
538 printf("%s\n", lport->macs[i]);
539 }
540}
65fb6826 541
92207865
BP
542static void
543do_lport_set_port_security(struct ovs_cmdl_context *ctx)
544{
545 struct nbctl_context *nb_ctx = ctx->pvt;
546 const char *id = ctx->argv[1];
547 const struct nbrec_logical_port *lport;
548
549 lport = lport_by_name_or_uuid(nb_ctx, id);
550 if (!lport) {
551 return;
552 }
553
554 nbrec_logical_port_set_port_security(lport,
555 (const char **) ctx->argv + 2, ctx->argc - 2);
556}
557
558static void
559do_lport_get_port_security(struct ovs_cmdl_context *ctx)
560{
561 struct nbctl_context *nb_ctx = ctx->pvt;
562 const char *id = ctx->argv[1];
563 const struct nbrec_logical_port *lport;
564 size_t i;
565
566 lport = lport_by_name_or_uuid(nb_ctx, id);
567 if (!lport) {
568 return;
569 }
570
571 for (i = 0; i < lport->n_port_security; i++) {
572 printf("%s\n", lport->port_security[i]);
573 }
574}
575
65fb6826
RB
576static void
577do_lport_get_up(struct ovs_cmdl_context *ctx)
578{
579 struct nbctl_context *nb_ctx = ctx->pvt;
580 const char *id = ctx->argv[1];
581 const struct nbrec_logical_port *lport;
582
583 lport = lport_by_name_or_uuid(nb_ctx, id);
584 if (!lport) {
585 return;
586 }
587
588 printf("%s\n", (lport->up && *lport->up) ? "up" : "down");
589}
e9e8bcdf
RB
590
591static void
592do_lport_set_enabled(struct ovs_cmdl_context *ctx)
593{
594 struct nbctl_context *nb_ctx = ctx->pvt;
595 const char *id = ctx->argv[1];
596 const char *state = ctx->argv[2];
597 const struct nbrec_logical_port *lport;
598
599 lport = lport_by_name_or_uuid(nb_ctx, id);
600 if (!lport) {
601 return;
602 }
603
604 if (!strcasecmp(state, "enabled")) {
605 bool enabled = true;
606 nbrec_logical_port_set_enabled(lport, &enabled, 1);
607 } else if (!strcasecmp(state, "disabled")) {
608 bool enabled = false;
609 nbrec_logical_port_set_enabled(lport, &enabled, 1);
610 } else {
611 VLOG_ERR("Invalid state '%s' provided to lport-set-enabled", state);
612 }
613}
614
615static void
616do_lport_get_enabled(struct ovs_cmdl_context *ctx)
617{
618 struct nbctl_context *nb_ctx = ctx->pvt;
619 const char *id = ctx->argv[1];
620 const struct nbrec_logical_port *lport;
621
622 lport = lport_by_name_or_uuid(nb_ctx, id);
623 if (!lport) {
624 return;
625 }
626
627 printf("%s\n",
628 (!lport->enabled || *lport->enabled) ? "enabled" : "disabled");
629}
a416ff28
RB
630\f
631static void
632parse_options(int argc, char *argv[])
633{
634 enum {
635 VLOG_OPTION_ENUMS,
636 };
637 static const struct option long_options[] = {
a7ac550b 638 {"db", required_argument, NULL, 'd'},
a416ff28
RB
639 {"help", no_argument, NULL, 'h'},
640 {"options", no_argument, NULL, 'o'},
641 {"version", no_argument, NULL, 'V'},
642 VLOG_LONG_OPTIONS,
643 STREAM_SSL_LONG_OPTIONS,
644 {NULL, 0, NULL, 0},
645 };
646 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
647
648 for (;;) {
649 int c;
650
651 c = getopt_long(argc, argv, short_options, long_options, NULL);
652 if (c == -1) {
653 break;
654 }
655
656 switch (c) {
657 VLOG_OPTION_HANDLERS;
658 STREAM_SSL_OPTION_HANDLERS;
659
660 case 'd':
661 db = optarg;
662 break;
663
664 case 'h':
665 usage();
666 exit(EXIT_SUCCESS);
667
668 case 'o':
669 ovs_cmdl_print_options(long_options);
670 exit(EXIT_SUCCESS);
671
672 case 'V':
673 ovs_print_version(0, 0);
674 exit(EXIT_SUCCESS);
675
676 default:
677 break;
678 }
679 }
680
681 if (!db) {
682 db = default_db();
683 }
684
685 free(short_options);
686}
687
688static const struct ovs_cmdl_command all_commands[] = {
907a0edf
JP
689 {
690 .name = "show",
691 .usage = "[LSWITCH]",
692 .min_args = 0,
693 .max_args = 1,
694 .handler = do_show,
695 },
a416ff28
RB
696 {
697 .name = "lswitch-add",
a367622a 698 .usage = "[LSWITCH]",
a416ff28
RB
699 .min_args = 0,
700 .max_args = 1,
701 .handler = do_lswitch_add,
702 },
703 {
704 .name = "lswitch-del",
a367622a 705 .usage = "LSWITCH",
a416ff28
RB
706 .min_args = 1,
707 .max_args = 1,
708 .handler = do_lswitch_del,
709 },
710 {
711 .name = "lswitch-list",
712 .usage = "",
713 .min_args = 0,
714 .max_args = 0,
715 .handler = do_lswitch_list,
716 },
717 {
718 .name = "lswitch-set-external-id",
a367622a 719 .usage = "LSWITCH KEY [VALUE]",
a416ff28
RB
720 .min_args = 2,
721 .max_args = 3,
722 .handler = do_lswitch_set_external_id,
723 },
724 {
725 .name = "lswitch-get-external-id",
a367622a 726 .usage = "LSWITCH [KEY]",
a416ff28
RB
727 .min_args = 1,
728 .max_args = 2,
729 .handler = do_lswitch_get_external_id,
730 },
731 {
732 .name = "lport-add",
bf5fa52a 733 .usage = "LSWITCH LPORT [PARENT] [TAG]",
a416ff28 734 .min_args = 2,
bf5fa52a 735 .max_args = 4,
a416ff28
RB
736 .handler = do_lport_add,
737 },
738 {
739 .name = "lport-del",
a367622a 740 .usage = "LPORT",
a416ff28
RB
741 .min_args = 1,
742 .max_args = 1,
743 .handler = do_lport_del,
744 },
745 {
746 .name = "lport-list",
a367622a 747 .usage = "LSWITCH",
a416ff28
RB
748 .min_args = 1,
749 .max_args = 1,
750 .handler = do_lport_list,
751 },
bf5fa52a
RB
752 {
753 .name = "lport-get-parent",
754 .usage = "LPORT",
755 .min_args = 1,
756 .max_args = 1,
757 .handler = do_lport_get_parent,
758 },
759 {
760 .name = "lport-get-tag",
761 .usage = "LPORT",
762 .min_args = 1,
763 .max_args = 1,
764 .handler = do_lport_get_tag,
765 },
a416ff28
RB
766 {
767 .name = "lport-set-external-id",
a367622a 768 .usage = "LPORT KEY [VALUE]",
a416ff28
RB
769 .min_args = 2,
770 .max_args = 3,
771 .handler = do_lport_set_external_id,
772 },
773 {
774 .name = "lport-get-external-id",
a367622a 775 .usage = "LPORT [KEY]",
a416ff28
RB
776 .min_args = 1,
777 .max_args = 2,
778 .handler = do_lport_get_external_id,
779 },
780 {
781 .name = "lport-set-macs",
2de82d90 782 .usage = "LPORT [MAC]...",
a416ff28
RB
783 .min_args = 1,
784 /* Accept however many arguments the system will allow. */
785 .max_args = INT_MAX,
786 .handler = do_lport_set_macs,
787 },
788 {
789 .name = "lport-get-macs",
a367622a 790 .usage = "LPORT",
a416ff28
RB
791 .min_args = 1,
792 .max_args = 1,
793 .handler = do_lport_get_macs,
794 },
92207865
BP
795 {
796 .name = "lport-set-port-security",
797 .usage = "LPORT [ADDRS]...",
798 .min_args = 0,
799 /* Accept however many arguments the system will allow. */
800 .max_args = INT_MAX,
801 .handler = do_lport_set_port_security,
802 },
803 {
804 .name = "lport-get-port-security",
805 .usage = "LPORT",
806 .min_args = 1,
807 .max_args = 1,
808 .handler = do_lport_get_port_security,
809 },
65fb6826
RB
810 {
811 .name = "lport-get-up",
a367622a 812 .usage = "LPORT",
65fb6826
RB
813 .min_args = 1,
814 .max_args = 1,
815 .handler = do_lport_get_up,
816 },
e9e8bcdf
RB
817 {
818 .name = "lport-set-enabled",
819 .usage = "LPORT STATE",
820 .min_args = 2,
821 .max_args = 2,
822 .handler = do_lport_set_enabled,
823 },
824 {
825 .name = "lport-get-enabled",
826 .usage = "LPORT",
827 .min_args = 1,
828 .max_args = 1,
829 .handler = do_lport_get_enabled,
830 },
a416ff28
RB
831
832 {
833 /* sentinel */
834 .name = NULL,
835 },
836};
837
838static const struct ovs_cmdl_command *
839get_all_commands(void)
840{
841 return all_commands;
842}
843
844static const char *
845default_db(void)
846{
847 static char *def;
848 if (!def) {
d75ef07f
BP
849 def = getenv("OVN_NB_DB");
850 if (!def) {
851 def = xasprintf("unix:%s/db.sock", ovs_rundir());
852 }
a416ff28
RB
853 }
854 return def;
855}
856
857int
858main(int argc, char *argv[])
859{
860 extern struct vlog_module VLM_reconnect;
861 struct ovs_cmdl_context ctx;
862 struct nbctl_context nb_ctx = { .idl = NULL, };
863 enum ovsdb_idl_txn_status txn_status;
864 unsigned int seqno;
62ce36b2 865 int res = 0;
afc9da0b 866 char *args;
a416ff28
RB
867
868 fatal_ignore_sigpipe();
869 set_program_name(argv[0]);
870 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
871 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
872 parse_options(argc, argv);
873 nbrec_init();
874
afc9da0b
JP
875 args = process_escape_args(argv);
876
a416ff28
RB
877 nb_ctx.idl = ovsdb_idl_create(db, &nbrec_idl_class, true, false);
878 ctx.pvt = &nb_ctx;
879 ctx.argc = argc - optind;
880 ctx.argv = argv + optind;
881
882 seqno = ovsdb_idl_get_seqno(nb_ctx.idl);
883 for (;;) {
884 ovsdb_idl_run(nb_ctx.idl);
885
886 if (!ovsdb_idl_is_alive(nb_ctx.idl)) {
887 int retval = ovsdb_idl_get_last_error(nb_ctx.idl);
888 VLOG_ERR("%s: database connection failed (%s)",
889 db, ovs_retval_to_string(retval));
62ce36b2
RB
890 res = 1;
891 break;
a416ff28
RB
892 }
893
894 if (seqno != ovsdb_idl_get_seqno(nb_ctx.idl)) {
895 nb_ctx.txn = ovsdb_idl_txn_create(nb_ctx.idl);
afc9da0b 896 ovsdb_idl_txn_add_comment(nb_ctx.txn, "ovn-nbctl: %s", args);
a416ff28
RB
897 ovs_cmdl_run_command(&ctx, get_all_commands());
898 txn_status = ovsdb_idl_txn_commit_block(nb_ctx.txn);
899 if (txn_status == TXN_TRY_AGAIN) {
6514cf48
RB
900 ovsdb_idl_txn_destroy(nb_ctx.txn);
901 nb_ctx.txn = NULL;
a416ff28
RB
902 continue;
903 } else {
904 break;
905 }
906 }
907
908 if (seqno == ovsdb_idl_get_seqno(nb_ctx.idl)) {
909 ovsdb_idl_wait(nb_ctx.idl);
910 poll_block();
911 }
912 }
913
914 if (nb_ctx.txn) {
915 ovsdb_idl_txn_destroy(nb_ctx.txn);
916 }
917 ovsdb_idl_destroy(nb_ctx.idl);
afc9da0b 918 free(args);
a416ff28 919
62ce36b2 920 exit(res);
a416ff28 921}