]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/utilities/ovn-sbctl.c
tnl-ports: Handle STT ports.
[mirror_ovs.git] / ovn / utilities / ovn-sbctl.c
CommitLineData
fed00ab1 1/*
922fed06 2 * Copyright (c) 2015, 2016 Nicira, Inc.
fed00ab1
AW
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include <ctype.h>
20#include <errno.h>
21#include <float.h>
22#include <getopt.h>
23#include <inttypes.h>
24#include <signal.h>
25#include <stdarg.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "db-ctl-base.h"
60bdd011 31#include "dirs.h"
fed00ab1
AW
32
33#include "command-line.h"
34#include "compiler.h"
3e8a2ad1 35#include "openvswitch/dynamic-string.h"
fed00ab1
AW
36#include "fatal-signal.h"
37#include "json.h"
38#include "ovsdb-data.h"
39#include "ovsdb-idl.h"
40#include "poll-loop.h"
41#include "process.h"
42#include "sset.h"
43#include "shash.h"
dda825b8 44#include "stream-ssl.h"
66cf8908 45#include "stream.h"
fed00ab1
AW
46#include "table.h"
47#include "timeval.h"
48#include "util.h"
49#include "openvswitch/vlog.h"
50#include "ovn/lib/ovn-sb-idl.h"
51
52VLOG_DEFINE_THIS_MODULE(sbctl);
53
54struct sbctl_context;
55
56/* --db: The database server to contact. */
57static const char *db;
58
59/* --oneline: Write each command's output as a single line? */
60static bool oneline;
61
62/* --dry-run: Do not commit any changes. */
63static bool dry_run;
64
65/* --timeout: Time to wait for a connection to 'db'. */
66static int timeout;
67
68/* Format for table output. */
69static struct table_style table_style = TABLE_STYLE_DEFAULT;
70
71/* The IDL we're using and the current transaction, if any.
72 * This is for use by sbctl_exit() only, to allow it to clean up.
73 * Other code should use its context arguments. */
74static struct ovsdb_idl *the_idl;
75static struct ovsdb_idl_txn *the_idl_txn;
76OVS_NO_RETURN static void sbctl_exit(int status);
77
78static void sbctl_cmd_init(void);
79OVS_NO_RETURN static void usage(void);
80static void parse_options(int argc, char *argv[], struct shash *local_options);
cce9c163 81static const char *sbctl_default_db(void);
fed00ab1
AW
82static void run_prerequisites(struct ctl_command[], size_t n_commands,
83 struct ovsdb_idl *);
84static void do_sbctl(const char *args, struct ctl_command *, size_t n,
85 struct ovsdb_idl *);
86
87int
88main(int argc, char *argv[])
89{
fed00ab1
AW
90 struct ovsdb_idl *idl;
91 struct ctl_command *commands;
92 struct shash local_options;
93 unsigned int seqno;
94 size_t n_commands;
95 char *args;
96
97 set_program_name(argv[0]);
98 fatal_ignore_sigpipe();
99 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
45863ce5 100 vlog_set_levels_from_string_assert("reconnect:warn");
fed00ab1
AW
101 sbrec_init();
102
103 sbctl_cmd_init();
104
105 /* Log our arguments. This is often valuable for debugging systems. */
106 args = process_escape_args(argv);
107 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG, "Called as %s", args);
108
109 /* Parse command line. */
110 shash_init(&local_options);
111 parse_options(argc, argv, &local_options);
112 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
113 &n_commands);
114
115 if (timeout) {
116 time_alarm(timeout);
117 }
118
119 /* Initialize IDL. */
120 idl = the_idl = ovsdb_idl_create(db, &sbrec_idl_class, false, false);
121 run_prerequisites(commands, n_commands, idl);
122
123 /* Execute the commands.
124 *
125 * 'seqno' is the database sequence number for which we last tried to
126 * execute our transaction. There's no point in trying to commit more than
127 * once for any given sequence number, because if the transaction fails
128 * it's because the database changed and we need to obtain an up-to-date
129 * view of the database before we try the transaction again. */
130 seqno = ovsdb_idl_get_seqno(idl);
131 for (;;) {
132 ovsdb_idl_run(idl);
133 if (!ovsdb_idl_is_alive(idl)) {
134 int retval = ovsdb_idl_get_last_error(idl);
135 ctl_fatal("%s: database connection failed (%s)",
136 db, ovs_retval_to_string(retval));
137 }
138
139 if (seqno != ovsdb_idl_get_seqno(idl)) {
140 seqno = ovsdb_idl_get_seqno(idl);
141 do_sbctl(args, commands, n_commands, idl);
142 }
143
144 if (seqno == ovsdb_idl_get_seqno(idl)) {
145 ovsdb_idl_wait(idl);
146 poll_block();
147 }
148 }
149}
150
cce9c163
BP
151static const char *
152sbctl_default_db(void)
153{
154 static char *def;
155 if (!def) {
156 def = getenv("OVN_SB_DB");
157 if (!def) {
60bdd011 158 def = xasprintf("unix:%s/ovnsb_db.sock", ovs_rundir());
cce9c163
BP
159 }
160 }
161 return def;
162}
163
fed00ab1
AW
164static void
165parse_options(int argc, char *argv[], struct shash *local_options)
166{
167 enum {
168 OPT_DB = UCHAR_MAX + 1,
169 OPT_ONELINE,
170 OPT_NO_SYSLOG,
171 OPT_DRY_RUN,
172 OPT_PEER_CA_CERT,
173 OPT_LOCAL,
174 OPT_COMMANDS,
175 OPT_OPTIONS,
176 VLOG_OPTION_ENUMS,
177 TABLE_OPTION_ENUMS
178 };
179 static const struct option global_long_options[] = {
180 {"db", required_argument, NULL, OPT_DB},
181 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
182 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
183 {"oneline", no_argument, NULL, OPT_ONELINE},
184 {"timeout", required_argument, NULL, 't'},
185 {"help", no_argument, NULL, 'h'},
186 {"commands", no_argument, NULL, OPT_COMMANDS},
187 {"options", no_argument, NULL, OPT_OPTIONS},
188 {"version", no_argument, NULL, 'V'},
189 VLOG_LONG_OPTIONS,
dda825b8 190 STREAM_SSL_LONG_OPTIONS,
fed00ab1
AW
191 TABLE_LONG_OPTIONS,
192 {NULL, 0, NULL, 0},
193 };
194 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
195 char *tmp, *short_options;
196
197 struct option *options;
198 size_t allocated_options;
199 size_t n_options;
200 size_t i;
201
202 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
203 short_options = xasprintf("+%s", tmp);
204 free(tmp);
205
206 /* We want to parse both global and command-specific options here, but
207 * getopt_long() isn't too convenient for the job. We copy our global
208 * options into a dynamic array, then append all of the command-specific
209 * options. */
210 options = xmemdup(global_long_options, sizeof global_long_options);
211 allocated_options = ARRAY_SIZE(global_long_options);
212 n_options = n_global_long_options;
213 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
214 table_style.format = TF_LIST;
215
216 for (;;) {
217 int idx;
218 int c;
219
220 c = getopt_long(argc, argv, short_options, options, &idx);
221 if (c == -1) {
222 break;
223 }
224
225 switch (c) {
226 case OPT_DB:
227 db = optarg;
228 break;
229
230 case OPT_ONELINE:
231 oneline = true;
232 break;
233
234 case OPT_NO_SYSLOG:
922fed06 235 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
fed00ab1
AW
236 break;
237
238 case OPT_DRY_RUN:
239 dry_run = true;
240 break;
241
242 case OPT_LOCAL:
243 if (shash_find(local_options, options[idx].name)) {
244 ctl_fatal("'%s' option specified multiple times",
245 options[idx].name);
246 }
247 shash_add_nocopy(local_options,
248 xasprintf("--%s", options[idx].name),
249 optarg ? xstrdup(optarg) : NULL);
250 break;
251
252 case 'h':
253 usage();
254
255 case OPT_COMMANDS:
256 ctl_print_commands();
257
258 case OPT_OPTIONS:
259 ctl_print_options(global_long_options);
260
261 case 'V':
262 ovs_print_version(0, 0);
263 printf("DB Schema %s\n", sbrec_get_db_version());
264 exit(EXIT_SUCCESS);
265
266 case 't':
267 timeout = strtoul(optarg, NULL, 10);
268 if (timeout < 0) {
b31301bc 269 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
fed00ab1
AW
270 }
271 break;
272
273 VLOG_OPTION_HANDLERS
274 TABLE_OPTION_HANDLERS(&table_style)
dda825b8 275 STREAM_SSL_OPTION_HANDLERS
fed00ab1
AW
276
277 case '?':
278 exit(EXIT_FAILURE);
279
280 default:
281 abort();
282 }
283 }
284 free(short_options);
285
286 if (!db) {
cce9c163 287 db = sbctl_default_db();
fed00ab1
AW
288 }
289
290 for (i = n_global_long_options; options[i].name; i++) {
291 free(CONST_CAST(char *, options[i].name));
292 }
293 free(options);
294}
295
296static void
297usage(void)
298{
299 printf("\
66cf8908 300%s: OVN southbound DB management utility\n\
fed00ab1 301\n\
66cf8908 302For debugging and testing only, not for use in production.\n\
fed00ab1
AW
303\n\
304usage: %s [OPTIONS] COMMAND [ARG...]\n\
305\n\
66cf8908 306General commands:\n\
fed00ab1
AW
307 show print overview of database contents\n\
308\n\
309Chassis commands:\n\
310 chassis-add CHASSIS ENCAP-TYPE ENCAP-IP create a new chassis named\n\
3c653533
JP
311 CHASSIS with ENCAP-TYPE tunnels\n\
312 and ENCAP-IP\n\
313 chassis-del CHASSIS delete CHASSIS and all of its encaps\n\
fed00ab1
AW
314 and gateway_ports\n\
315\n\
316Port binding commands:\n\
317 lport-bind LPORT CHASSIS bind logical port LPORT to CHASSIS\n\
318 lport-unbind LPORT reset the port binding of logical port LPORT\n\
319\n\
dc70b67b
RB
320Logical flow commands:\n\
321 lflow-list [DATAPATH] List logical flows for all or a single datapath\n\
322 dump-flows [DATAPATH] Alias for lflow-list\n\
323\n\
fed00ab1
AW
324%s\
325\n\
326Options:\n\
327 --db=DATABASE connect to DATABASE\n\
328 (default: %s)\n\
66cf8908 329 -t, --timeout=SECS wait at most SECS seconds\n\
fed00ab1
AW
330 --dry-run do not commit changes to database\n\
331 --oneline print exactly one line of output per command\n",
9e7027fd 332 program_name, program_name, ctl_get_db_cmd_usage(), sbctl_default_db());
fed00ab1
AW
333 vlog_usage();
334 printf("\
335 --no-syslog equivalent to --verbose=sbctl:syslog:warn\n");
336 printf("\n\
337Other options:\n\
338 -h, --help display this help message\n\
339 -V, --version display version information\n");
66cf8908 340 stream_usage("database", true, true, false);
fed00ab1
AW
341 exit(EXIT_SUCCESS);
342}
343
344\f
345/* ovs-sbctl specific context. Inherits the 'struct ctl_context' as base. */
346struct sbctl_context {
347 struct ctl_context base;
348
349 /* A cache of the contents of the database.
350 *
351 * A command that needs to use any of this information must first call
352 * sbctl_context_populate_cache(). A command that changes anything that
353 * could invalidate the cache must either call
354 * sbctl_context_invalidate_cache() or manually update the cache to
355 * maintain its correctness. */
356 bool cache_valid;
357 /* Maps from chassis name to struct sbctl_chassis. */
358 struct shash chassis;
359 /* Maps from lport name to struct sbctl_port_binding. */
360 struct shash port_bindings;
361};
362
ec4eed45 363/* Casts 'base' into 'struct sbctl_context'. */
fed00ab1
AW
364static struct sbctl_context *
365sbctl_context_cast(struct ctl_context *base)
366{
367 return CONTAINER_OF(base, struct sbctl_context, base);
368}
369
370struct sbctl_chassis {
371 const struct sbrec_chassis *ch_cfg;
372};
373
374struct sbctl_port_binding {
375 const struct sbrec_port_binding *bd_cfg;
376};
377
378static void
379sbctl_context_invalidate_cache(struct ctl_context *ctx)
380{
381 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
382
383 if (!sbctl_ctx->cache_valid) {
384 return;
385 }
386 sbctl_ctx->cache_valid = false;
387 shash_destroy_free_data(&sbctl_ctx->chassis);
388 shash_destroy_free_data(&sbctl_ctx->port_bindings);
389}
390
391static void
392sbctl_context_populate_cache(struct ctl_context *ctx)
393{
394 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
395 const struct sbrec_chassis *chassis_rec;
396 const struct sbrec_port_binding *port_binding_rec;
397 struct sset chassis, port_bindings;
398
399 if (sbctl_ctx->cache_valid) {
400 /* Cache is already populated. */
401 return;
402 }
403 sbctl_ctx->cache_valid = true;
404 shash_init(&sbctl_ctx->chassis);
405 shash_init(&sbctl_ctx->port_bindings);
406 sset_init(&chassis);
407 SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->idl) {
408 struct sbctl_chassis *ch;
409
410 if (!sset_add(&chassis, chassis_rec->name)) {
411 VLOG_WARN("database contains duplicate chassis name (%s)",
412 chassis_rec->name);
413 continue;
414 }
415
416 ch = xmalloc(sizeof *ch);
417 ch->ch_cfg = chassis_rec;
418 shash_add(&sbctl_ctx->chassis, chassis_rec->name, ch);
419 }
420 sset_destroy(&chassis);
421
422 sset_init(&port_bindings);
423 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->idl) {
424 struct sbctl_port_binding *bd;
425
426 if (!sset_add(&port_bindings, port_binding_rec->logical_port)) {
427 VLOG_WARN("database contains duplicate port binding for logical "
428 "port (%s)",
429 port_binding_rec->logical_port);
430 continue;
431 }
432
433 bd = xmalloc(sizeof *bd);
434 bd->bd_cfg = port_binding_rec;
435 shash_add(&sbctl_ctx->port_bindings, port_binding_rec->logical_port,
436 bd);
437 }
438 sset_destroy(&port_bindings);
439}
440
441static void
442check_conflicts(struct sbctl_context *sbctl_ctx, const char *name,
443 char *msg)
444{
445 if (shash_find(&sbctl_ctx->chassis, name)) {
446 ctl_fatal("%s because a chassis named %s already exists",
447 msg, name);
448 }
449 free(msg);
450}
451
452static struct sbctl_chassis *
453find_chassis(struct sbctl_context *sbctl_ctx, const char *name,
454 bool must_exist)
455{
456 struct sbctl_chassis *sbctl_ch;
457
458 ovs_assert(sbctl_ctx->cache_valid);
459
460 sbctl_ch = shash_find_data(&sbctl_ctx->chassis, name);
461 if (must_exist && !sbctl_ch) {
462 ctl_fatal("no chassis named %s", name);
463 }
464
465 return sbctl_ch;
466}
467
468static struct sbctl_port_binding *
469find_port_binding(struct sbctl_context *sbctl_ctx, const char *name,
470 bool must_exist)
471{
472 struct sbctl_port_binding *bd;
473
474 ovs_assert(sbctl_ctx->cache_valid);
475
476 bd = shash_find_data(&sbctl_ctx->port_bindings, name);
477 if (must_exist && !bd) {
478 ctl_fatal("no port named %s", name);
479 }
480
481 return bd;
482}
483
484static void
485pre_get_info(struct ctl_context *ctx)
486{
487 ovsdb_idl_add_column(ctx->idl, &sbrec_chassis_col_name);
488 ovsdb_idl_add_column(ctx->idl, &sbrec_chassis_col_encaps);
489
490 ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_type);
491 ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_ip);
492
493 ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_logical_port);
494 ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_chassis);
dc70b67b
RB
495
496 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_logical_datapath);
497 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_pipeline);
498 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_actions);
499 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_priority);
500 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_table_id);
501 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_match);
ebbcddeb 502 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_external_ids);
fed00ab1
AW
503}
504
505static struct cmd_show_table cmd_show_tables[] = {
506 {&sbrec_table_chassis,
507 &sbrec_chassis_col_name,
2229f3ec
RB
508 {&sbrec_chassis_col_hostname,
509 &sbrec_chassis_col_encaps,
016e4684
AW
510 NULL},
511 {&sbrec_table_port_binding,
512 &sbrec_port_binding_col_logical_port,
513 &sbrec_port_binding_col_chassis}},
fed00ab1
AW
514
515 {&sbrec_table_encap,
516 &sbrec_encap_col_type,
517 {&sbrec_encap_col_ip,
518 &sbrec_encap_col_options,
016e4684
AW
519 NULL},
520 {NULL, NULL, NULL}},
fed00ab1 521
016e4684 522 {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}},
fed00ab1
AW
523};
524
525static void
526cmd_chassis_add(struct ctl_context *ctx)
527{
528 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
fed00ab1 529 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
3c653533 530 const char *ch_name, *encap_types, *encap_ip;
fed00ab1
AW
531
532 ch_name = ctx->argv[1];
3c653533 533 encap_types = ctx->argv[2];
fed00ab1
AW
534 encap_ip = ctx->argv[3];
535
536 sbctl_context_populate_cache(ctx);
537 if (may_exist) {
538 struct sbctl_chassis *sbctl_ch;
539
540 sbctl_ch = find_chassis(sbctl_ctx, ch_name, false);
541 if (sbctl_ch) {
542 return;
543 }
544 }
545 check_conflicts(sbctl_ctx, ch_name,
546 xasprintf("cannot create a chassis named %s", ch_name));
3c653533
JP
547
548 char *tokstr = xstrdup(encap_types);
549 char *token, *save_ptr = NULL;
550 struct sset encap_set = SSET_INITIALIZER(&encap_set);
551 for (token = strtok_r(tokstr, ",", &save_ptr); token != NULL;
552 token = strtok_r(NULL, ",", &save_ptr)) {
553 sset_add(&encap_set, token);
554 }
555 free(tokstr);
556
557 size_t n_encaps = sset_count(&encap_set);
558 struct sbrec_encap **encaps = xmalloc(n_encaps * sizeof *encaps);
559 const char *encap_type;
560 int i = 0;
561 SSET_FOR_EACH (encap_type, &encap_set){
562 encaps[i] = sbrec_encap_insert(ctx->txn);
563
564 sbrec_encap_set_type(encaps[i], encap_type);
565 sbrec_encap_set_ip(encaps[i], encap_ip);
566 i++;
567 }
568 sset_destroy(&encap_set);
569
570 struct sbrec_chassis *ch = sbrec_chassis_insert(ctx->txn);
fed00ab1 571 sbrec_chassis_set_name(ch, ch_name);
3c653533
JP
572 sbrec_chassis_set_encaps(ch, encaps, n_encaps);
573 free(encaps);
574
fed00ab1
AW
575 sbctl_context_invalidate_cache(ctx);
576}
577
578static void
579cmd_chassis_del(struct ctl_context *ctx)
580{
581 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
582 bool must_exist = !shash_find(&ctx->options, "--if-exists");
583 struct sbctl_chassis *sbctl_ch;
584
585 sbctl_context_populate_cache(ctx);
586 sbctl_ch = find_chassis(sbctl_ctx, ctx->argv[1], must_exist);
587 if (sbctl_ch) {
588 if (sbctl_ch->ch_cfg) {
3b74b8c0
AW
589 size_t i;
590
591 for (i = 0; i < sbctl_ch->ch_cfg->n_encaps; i++) {
592 sbrec_encap_delete(sbctl_ch->ch_cfg->encaps[i]);
593 }
fed00ab1
AW
594 sbrec_chassis_delete(sbctl_ch->ch_cfg);
595 }
596 shash_find_and_delete(&sbctl_ctx->chassis, ctx->argv[1]);
597 free(sbctl_ch);
598 }
599}
600
601static void
602cmd_lport_bind(struct ctl_context *ctx)
603{
604 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
605 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
606 struct sbctl_chassis *sbctl_ch;
607 struct sbctl_port_binding *sbctl_bd;
608 char *lport_name, *ch_name;
609
610 /* port_binding must exist, chassis must exist! */
611 lport_name = ctx->argv[1];
612 ch_name = ctx->argv[2];
613
614 sbctl_context_populate_cache(ctx);
615 sbctl_bd = find_port_binding(sbctl_ctx, lport_name, true);
616 sbctl_ch = find_chassis(sbctl_ctx, ch_name, true);
617
618 if (sbctl_bd->bd_cfg->chassis) {
619 if (may_exist && sbctl_bd->bd_cfg->chassis == sbctl_ch->ch_cfg) {
620 return;
621 } else {
622 ctl_fatal("lport (%s) has already been binded to chassis (%s)",
623 lport_name, sbctl_bd->bd_cfg->chassis->name);
624 }
625 }
626 sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, sbctl_ch->ch_cfg);
627 sbctl_context_invalidate_cache(ctx);
628}
629
630static void
631cmd_lport_unbind(struct ctl_context *ctx)
632{
633 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
634 bool must_exist = !shash_find(&ctx->options, "--if-exists");
635 struct sbctl_port_binding *sbctl_bd;
636 char *lport_name;
637
638 lport_name = ctx->argv[1];
639 sbctl_context_populate_cache(ctx);
640 sbctl_bd = find_port_binding(sbctl_ctx, lport_name, must_exist);
641 if (sbctl_bd) {
642 sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, NULL);
643 }
644}
645
dc70b67b
RB
646enum {
647 PL_INGRESS,
648 PL_EGRESS,
649};
650
651/* Help ensure we catch any future pipeline values */
652static int
653pipeline_encode(const char *pl)
654{
655 if (!strcmp(pl, "ingress")) {
656 return PL_INGRESS;
657 } else if (!strcmp(pl, "egress")) {
658 return PL_EGRESS;
659 }
660
661 OVS_NOT_REACHED();
662}
663
664static int
665lflow_cmp(const void *lf1_, const void *lf2_)
666{
35107449
BP
667 const struct sbrec_logical_flow *const *lf1p = lf1_;
668 const struct sbrec_logical_flow *const *lf2p = lf2_;
669 const struct sbrec_logical_flow *lf1 = *lf1p;
670 const struct sbrec_logical_flow *lf2 = *lf2p;
dc70b67b
RB
671
672 int pl1 = pipeline_encode(lf1->pipeline);
673 int pl2 = pipeline_encode(lf2->pipeline);
674
675#define CMP(expr) \
676 do { \
677 int res; \
678 res = (expr); \
679 if (res) { \
680 return res; \
681 } \
682 } while (0)
683
684 CMP(uuid_compare_3way(&lf1->logical_datapath->header_.uuid,
685 &lf2->logical_datapath->header_.uuid));
686 CMP(pl1 - pl2);
687 CMP(lf1->table_id > lf2->table_id ? 1 :
688 (lf1->table_id < lf2->table_id ? -1 : 0));
689 CMP(lf1->priority > lf2->priority ? -1 :
690 (lf1->priority < lf2->priority ? 1 : 0));
691 CMP(strcmp(lf1->match, lf2->match));
692
693#undef CMP
694
695 return 0;
696}
697
698static void
699cmd_lflow_list(struct ctl_context *ctx)
700{
701 const char *datapath = ctx->argc == 2 ? ctx->argv[1] : NULL;
702 struct uuid datapath_uuid = { .parts = { 0, }};
703 const struct sbrec_logical_flow **lflows;
704 const struct sbrec_logical_flow *lflow;
705 size_t n_flows = 0, n_capacity = 64;
706
707 if (datapath && !uuid_from_string(&datapath_uuid, datapath)) {
708 VLOG_ERR("Invalid format of datapath UUID");
709 return;
710 }
711
712 lflows = xmalloc(sizeof *lflows * n_capacity);
713 SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->idl) {
714 if (n_flows == n_capacity) {
715 lflows = x2nrealloc(lflows, &n_capacity, sizeof *lflows);
716 }
717 lflows[n_flows] = lflow;
718 n_flows++;
719 }
720
721 qsort(lflows, n_flows, sizeof *lflows, lflow_cmp);
722
723 const char *cur_pipeline = "";
724 size_t i;
725 for (i = 0; i < n_flows; i++) {
726 lflow = lflows[i];
727 if (datapath && !uuid_equals(&datapath_uuid,
728 &lflow->logical_datapath->header_.uuid)) {
729 continue;
730 }
731 if (strcmp(cur_pipeline, lflow->pipeline)) {
732 printf("Datapath: " UUID_FMT " Pipeline: %s\n",
733 UUID_ARGS(&lflow->logical_datapath->header_.uuid),
734 lflow->pipeline);
735 cur_pipeline = lflow->pipeline;
736 }
ebbcddeb
JP
737
738 const char *table_name = smap_get(&lflow->external_ids, "stage-name");
e0c9e58b 739 printf(" table=%" PRId64 "(%16s), priority=%5" PRId64
ebbcddeb
JP
740 ", match=(%s), action=(%s)\n",
741 lflow->table_id, table_name ? table_name : "",
742 lflow->priority, lflow->match, lflow->actions);
dc70b67b
RB
743 }
744
745 free(lflows);
746}
747
fed00ab1
AW
748\f
749static const struct ctl_table_class tables[] = {
750 {&sbrec_table_chassis,
751 {{&sbrec_table_chassis, &sbrec_chassis_col_name, NULL},
752 {NULL, NULL, NULL}}},
753
754 {&sbrec_table_encap,
755 {{NULL, NULL, NULL},
756 {NULL, NULL, NULL}}},
757
758 {&sbrec_table_logical_flow,
759 {{&sbrec_table_logical_flow, NULL,
760 &sbrec_logical_flow_col_logical_datapath},
761 {NULL, NULL, NULL}}},
762
763 {&sbrec_table_multicast_group,
764 {{NULL, NULL, NULL},
765 {NULL, NULL, NULL}}},
766
767 {&sbrec_table_datapath_binding,
768 {{NULL, NULL, NULL},
769 {NULL, NULL, NULL}}},
770
771 {&sbrec_table_port_binding,
772 {{&sbrec_table_port_binding, &sbrec_port_binding_col_logical_port, NULL},
773 {NULL, NULL, NULL}}},
774
0bac7164
BP
775 {&sbrec_table_mac_binding,
776 {{&sbrec_table_mac_binding, &sbrec_mac_binding_col_logical_port, NULL},
777 {NULL, NULL, NULL}}},
778
fed00ab1
AW
779 {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
780};
781
782\f
783static void
784sbctl_context_init_command(struct sbctl_context *sbctl_ctx,
785 struct ctl_command *command)
786{
787 ctl_context_init_command(&sbctl_ctx->base, command);
788}
789
790static void
791sbctl_context_init(struct sbctl_context *sbctl_ctx,
792 struct ctl_command *command, struct ovsdb_idl *idl,
793 struct ovsdb_idl_txn *txn,
794 struct ovsdb_symbol_table *symtab)
795{
796 ctl_context_init(&sbctl_ctx->base, command, idl, txn, symtab,
797 sbctl_context_invalidate_cache);
798 sbctl_ctx->cache_valid = false;
799}
800
801static void
802sbctl_context_done_command(struct sbctl_context *sbctl_ctx,
803 struct ctl_command *command)
804{
805 ctl_context_done_command(&sbctl_ctx->base, command);
806}
807
808static void
809sbctl_context_done(struct sbctl_context *sbctl_ctx,
810 struct ctl_command *command)
811{
812 ctl_context_done(&sbctl_ctx->base, command);
813}
814
815static void
816run_prerequisites(struct ctl_command *commands, size_t n_commands,
817 struct ovsdb_idl *idl)
818{
819 struct ctl_command *c;
820
821 for (c = commands; c < &commands[n_commands]; c++) {
822 if (c->syntax->prerequisites) {
823 struct sbctl_context sbctl_ctx;
824
825 ds_init(&c->output);
826 c->table = NULL;
827
828 sbctl_context_init(&sbctl_ctx, c, idl, NULL, NULL);
829 (c->syntax->prerequisites)(&sbctl_ctx.base);
830 sbctl_context_done(&sbctl_ctx, c);
831
832 ovs_assert(!c->output.string);
833 ovs_assert(!c->table);
834 }
835 }
836}
837
838static void
839do_sbctl(const char *args, struct ctl_command *commands, size_t n_commands,
840 struct ovsdb_idl *idl)
841{
842 struct ovsdb_idl_txn *txn;
843 enum ovsdb_idl_txn_status status;
844 struct ovsdb_symbol_table *symtab;
845 struct sbctl_context sbctl_ctx;
846 struct ctl_command *c;
847 struct shash_node *node;
848 char *error = NULL;
849
850 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
851 if (dry_run) {
852 ovsdb_idl_txn_set_dry_run(txn);
853 }
854
855 ovsdb_idl_txn_add_comment(txn, "ovs-sbctl: %s", args);
856
857 symtab = ovsdb_symbol_table_create();
858 for (c = commands; c < &commands[n_commands]; c++) {
859 ds_init(&c->output);
860 c->table = NULL;
861 }
862 sbctl_context_init(&sbctl_ctx, NULL, idl, txn, symtab);
863 for (c = commands; c < &commands[n_commands]; c++) {
864 sbctl_context_init_command(&sbctl_ctx, c);
865 if (c->syntax->run) {
866 (c->syntax->run)(&sbctl_ctx.base);
867 }
868 sbctl_context_done_command(&sbctl_ctx, c);
869
870 if (sbctl_ctx.base.try_again) {
871 sbctl_context_done(&sbctl_ctx, NULL);
872 goto try_again;
873 }
874 }
875 sbctl_context_done(&sbctl_ctx, NULL);
876
877 SHASH_FOR_EACH (node, &symtab->sh) {
878 struct ovsdb_symbol *symbol = node->data;
879 if (!symbol->created) {
880 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
b31301bc
BP
881 "with \"-- --id=%s create ...\")",
882 node->name, node->name);
fed00ab1
AW
883 }
884 if (!symbol->strong_ref) {
885 if (!symbol->weak_ref) {
886 VLOG_WARN("row id \"%s\" was created but no reference to it "
887 "was inserted, so it will not actually appear in "
888 "the database", node->name);
889 } else {
890 VLOG_WARN("row id \"%s\" was created but only a weak "
891 "reference to it was inserted, so it will not "
892 "actually appear in the database", node->name);
893 }
894 }
895 }
896
897 status = ovsdb_idl_txn_commit_block(txn);
898 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
899 for (c = commands; c < &commands[n_commands]; c++) {
900 if (c->syntax->postprocess) {
901 sbctl_context_init(&sbctl_ctx, c, idl, txn, symtab);
902 (c->syntax->postprocess)(&sbctl_ctx.base);
903 sbctl_context_done(&sbctl_ctx, c);
904 }
905 }
906 }
907 error = xstrdup(ovsdb_idl_txn_get_error(txn));
908
909 switch (status) {
910 case TXN_UNCOMMITTED:
911 case TXN_INCOMPLETE:
912 OVS_NOT_REACHED();
913
914 case TXN_ABORTED:
915 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
916 ctl_fatal("transaction aborted");
917
918 case TXN_UNCHANGED:
919 case TXN_SUCCESS:
920 break;
921
922 case TXN_TRY_AGAIN:
923 goto try_again;
924
925 case TXN_ERROR:
926 ctl_fatal("transaction error: %s", error);
927
928 case TXN_NOT_LOCKED:
929 /* Should not happen--we never call ovsdb_idl_set_lock(). */
930 ctl_fatal("database not locked");
931
932 default:
933 OVS_NOT_REACHED();
934 }
935 free(error);
936
937 ovsdb_symbol_table_destroy(symtab);
938
939 for (c = commands; c < &commands[n_commands]; c++) {
940 struct ds *ds = &c->output;
941
942 if (c->table) {
943 table_print(c->table, &table_style);
944 } else if (oneline) {
945 size_t j;
946
947 ds_chomp(ds, '\n');
948 for (j = 0; j < ds->length; j++) {
949 int ch = ds->string[j];
950 switch (ch) {
951 case '\n':
952 fputs("\\n", stdout);
953 break;
954
955 case '\\':
956 fputs("\\\\", stdout);
957 break;
958
959 default:
960 putchar(ch);
961 }
962 }
963 putchar('\n');
964 } else {
965 fputs(ds_cstr(ds), stdout);
966 }
967 ds_destroy(&c->output);
968 table_destroy(c->table);
969 free(c->table);
970
971 shash_destroy_free_data(&c->options);
972 }
973 free(commands);
974 ovsdb_idl_txn_destroy(txn);
975 ovsdb_idl_destroy(idl);
976
977 exit(EXIT_SUCCESS);
978
979try_again:
980 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
981 * resources and return so that the caller can try again. */
982 if (txn) {
983 ovsdb_idl_txn_abort(txn);
984 ovsdb_idl_txn_destroy(txn);
985 the_idl_txn = NULL;
986 }
987 ovsdb_symbol_table_destroy(symtab);
988 for (c = commands; c < &commands[n_commands]; c++) {
989 ds_destroy(&c->output);
990 table_destroy(c->table);
991 free(c->table);
992 }
993 free(error);
994}
995
996/* Frees the current transaction and the underlying IDL and then calls
997 * exit(status).
998 *
999 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1000 * for a clean memory leak report from valgrind in the normal case. That makes
1001 * it easier to notice real memory leaks. */
1002static void
1003sbctl_exit(int status)
1004{
1005 if (the_idl_txn) {
1006 ovsdb_idl_txn_abort(the_idl_txn);
1007 ovsdb_idl_txn_destroy(the_idl_txn);
1008 }
1009 ovsdb_idl_destroy(the_idl);
1010 exit(status);
1011}
1012
1013static const struct ctl_command_syntax sbctl_commands[] = {
1014 /* Chassis commands. */
1015 {"chassis-add", 3, 3, "CHASSIS ENCAP-TYPE ENCAP-IP", pre_get_info,
1016 cmd_chassis_add, NULL, "--may-exist", RW},
1017 {"chassis-del", 1, 1, "CHASSIS", pre_get_info, cmd_chassis_del, NULL,
1018 "--if-exists", RW},
1019
1020 /* Port binding commands. */
1021 {"lport-bind", 2, 2, "LPORT CHASSIS", pre_get_info, cmd_lport_bind, NULL,
1022 "--may-exist", RW},
1023 {"lport-unbind", 1, 1, "LPORT", pre_get_info, cmd_lport_unbind, NULL,
1024 "--if-exists", RW},
1025
dc70b67b
RB
1026 /* Logical flow commands */
1027 {"lflow-list", 0, 1, "[DATAPATH]", pre_get_info, cmd_lflow_list, NULL,
1028 "", RO},
1029 {"dump-flows", 0, 1, "[DATAPATH]", pre_get_info, cmd_lflow_list, NULL,
1030 "", RO}, /* Friendly alias for lflow-list */
1031
fed00ab1
AW
1032 /* SSL commands (To Be Added). */
1033
1034 {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
1035};
1036
1037/* Registers sbctl and common db commands. */
1038static void
1039sbctl_cmd_init(void)
1040{
1041 ctl_init(tables, cmd_show_tables, sbctl_exit);
1042 ctl_register_commands(sbctl_commands);
1043}