]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/utilities/ovn-sbctl.c
flow: Refactor ct_orig_tuple check in miniflow_extract().
[mirror_ovs.git] / ovn / utilities / ovn-sbctl.c
CommitLineData
fed00ab1 1/*
3f5b5f7b 2 * Copyright (c) 2015, 2016, 2017 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
c2f4c39b 30#include "colors.h"
fed00ab1
AW
31#include "command-line.h"
32#include "compiler.h"
8ad609c0
BP
33#include "db-ctl-base.h"
34#include "dirs.h"
fed00ab1 35#include "fatal-signal.h"
8ad609c0 36#include "openvswitch/dynamic-string.h"
ee89ea7b 37#include "openvswitch/json.h"
c2f4c39b
BP
38#include "openvswitch/ofp-actions.h"
39#include "openvswitch/ofp-print.h"
8ad609c0 40#include "openvswitch/shash.h"
c2f4c39b 41#include "openvswitch/vconn.h"
8ad609c0
BP
42#include "openvswitch/vlog.h"
43#include "ovn/lib/ovn-sb-idl.h"
44#include "ovn/lib/ovn-util.h"
fed00ab1
AW
45#include "ovsdb-data.h"
46#include "ovsdb-idl.h"
47#include "poll-loop.h"
48#include "process.h"
49#include "sset.h"
dda825b8 50#include "stream-ssl.h"
66cf8908 51#include "stream.h"
fed00ab1
AW
52#include "table.h"
53#include "timeval.h"
54#include "util.h"
10471820 55#include "svec.h"
fed00ab1
AW
56
57VLOG_DEFINE_THIS_MODULE(sbctl);
58
59struct sbctl_context;
60
61/* --db: The database server to contact. */
62static const char *db;
63
64/* --oneline: Write each command's output as a single line? */
65static bool oneline;
66
67/* --dry-run: Do not commit any changes. */
68static bool dry_run;
69
70/* --timeout: Time to wait for a connection to 'db'. */
71static int timeout;
72
73/* Format for table output. */
74static struct table_style table_style = TABLE_STYLE_DEFAULT;
75
76/* The IDL we're using and the current transaction, if any.
77 * This is for use by sbctl_exit() only, to allow it to clean up.
78 * Other code should use its context arguments. */
79static struct ovsdb_idl *the_idl;
80static struct ovsdb_idl_txn *the_idl_txn;
81OVS_NO_RETURN static void sbctl_exit(int status);
82
83static void sbctl_cmd_init(void);
84OVS_NO_RETURN static void usage(void);
85static void parse_options(int argc, char *argv[], struct shash *local_options);
86static void run_prerequisites(struct ctl_command[], size_t n_commands,
87 struct ovsdb_idl *);
8ee574c3 88static bool do_sbctl(const char *args, struct ctl_command *, size_t n,
fed00ab1
AW
89 struct ovsdb_idl *);
90
91int
92main(int argc, char *argv[])
93{
fed00ab1
AW
94 struct ovsdb_idl *idl;
95 struct ctl_command *commands;
96 struct shash local_options;
97 unsigned int seqno;
98 size_t n_commands;
99 char *args;
100
101 set_program_name(argv[0]);
102 fatal_ignore_sigpipe();
103 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
45863ce5 104 vlog_set_levels_from_string_assert("reconnect:warn");
fed00ab1
AW
105
106 sbctl_cmd_init();
107
108 /* Log our arguments. This is often valuable for debugging systems. */
109 args = process_escape_args(argv);
110 VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG, "Called as %s", args);
111
112 /* Parse command line. */
113 shash_init(&local_options);
114 parse_options(argc, argv, &local_options);
115 commands = ctl_parse_commands(argc - optind, argv + optind, &local_options,
116 &n_commands);
117
118 if (timeout) {
119 time_alarm(timeout);
120 }
121
122 /* Initialize IDL. */
123 idl = the_idl = ovsdb_idl_create(db, &sbrec_idl_class, false, false);
124 run_prerequisites(commands, n_commands, idl);
125
126 /* Execute the commands.
127 *
128 * 'seqno' is the database sequence number for which we last tried to
129 * execute our transaction. There's no point in trying to commit more than
130 * once for any given sequence number, because if the transaction fails
131 * it's because the database changed and we need to obtain an up-to-date
132 * view of the database before we try the transaction again. */
133 seqno = ovsdb_idl_get_seqno(idl);
134 for (;;) {
135 ovsdb_idl_run(idl);
136 if (!ovsdb_idl_is_alive(idl)) {
137 int retval = ovsdb_idl_get_last_error(idl);
138 ctl_fatal("%s: database connection failed (%s)",
139 db, ovs_retval_to_string(retval));
140 }
141
142 if (seqno != ovsdb_idl_get_seqno(idl)) {
143 seqno = ovsdb_idl_get_seqno(idl);
8ee574c3
WT
144 if (do_sbctl(args, commands, n_commands, idl)) {
145 free(args);
146 exit(EXIT_SUCCESS);
147 }
fed00ab1
AW
148 }
149
150 if (seqno == ovsdb_idl_get_seqno(idl)) {
151 ovsdb_idl_wait(idl);
152 poll_block();
153 }
154 }
155}
156
157static void
158parse_options(int argc, char *argv[], struct shash *local_options)
159{
160 enum {
161 OPT_DB = UCHAR_MAX + 1,
162 OPT_ONELINE,
163 OPT_NO_SYSLOG,
164 OPT_DRY_RUN,
fed00ab1
AW
165 OPT_LOCAL,
166 OPT_COMMANDS,
167 OPT_OPTIONS,
168 VLOG_OPTION_ENUMS,
e18a1d08
ER
169 TABLE_OPTION_ENUMS,
170 SSL_OPTION_ENUMS,
fed00ab1
AW
171 };
172 static const struct option global_long_options[] = {
173 {"db", required_argument, NULL, OPT_DB},
174 {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG},
175 {"dry-run", no_argument, NULL, OPT_DRY_RUN},
176 {"oneline", no_argument, NULL, OPT_ONELINE},
177 {"timeout", required_argument, NULL, 't'},
178 {"help", no_argument, NULL, 'h'},
179 {"commands", no_argument, NULL, OPT_COMMANDS},
180 {"options", no_argument, NULL, OPT_OPTIONS},
181 {"version", no_argument, NULL, 'V'},
182 VLOG_LONG_OPTIONS,
dda825b8 183 STREAM_SSL_LONG_OPTIONS,
fed00ab1
AW
184 TABLE_LONG_OPTIONS,
185 {NULL, 0, NULL, 0},
186 };
187 const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1;
188 char *tmp, *short_options;
189
190 struct option *options;
191 size_t allocated_options;
192 size_t n_options;
193 size_t i;
194
195 tmp = ovs_cmdl_long_options_to_short_options(global_long_options);
196 short_options = xasprintf("+%s", tmp);
197 free(tmp);
198
199 /* We want to parse both global and command-specific options here, but
200 * getopt_long() isn't too convenient for the job. We copy our global
201 * options into a dynamic array, then append all of the command-specific
202 * options. */
203 options = xmemdup(global_long_options, sizeof global_long_options);
204 allocated_options = ARRAY_SIZE(global_long_options);
205 n_options = n_global_long_options;
206 ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL);
fed00ab1
AW
207
208 for (;;) {
209 int idx;
210 int c;
211
212 c = getopt_long(argc, argv, short_options, options, &idx);
213 if (c == -1) {
214 break;
215 }
216
217 switch (c) {
218 case OPT_DB:
219 db = optarg;
220 break;
221
222 case OPT_ONELINE:
223 oneline = true;
224 break;
225
226 case OPT_NO_SYSLOG:
922fed06 227 vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN);
fed00ab1
AW
228 break;
229
230 case OPT_DRY_RUN:
231 dry_run = true;
232 break;
233
234 case OPT_LOCAL:
235 if (shash_find(local_options, options[idx].name)) {
236 ctl_fatal("'%s' option specified multiple times",
237 options[idx].name);
238 }
239 shash_add_nocopy(local_options,
240 xasprintf("--%s", options[idx].name),
2225c0b9 241 nullable_xstrdup(optarg));
fed00ab1
AW
242 break;
243
244 case 'h':
245 usage();
246
247 case OPT_COMMANDS:
248 ctl_print_commands();
249
250 case OPT_OPTIONS:
251 ctl_print_options(global_long_options);
252
253 case 'V':
254 ovs_print_version(0, 0);
255 printf("DB Schema %s\n", sbrec_get_db_version());
256 exit(EXIT_SUCCESS);
257
258 case 't':
259 timeout = strtoul(optarg, NULL, 10);
260 if (timeout < 0) {
b31301bc 261 ctl_fatal("value %s on -t or --timeout is invalid", optarg);
fed00ab1
AW
262 }
263 break;
264
265 VLOG_OPTION_HANDLERS
266 TABLE_OPTION_HANDLERS(&table_style)
dda825b8 267 STREAM_SSL_OPTION_HANDLERS
fed00ab1
AW
268
269 case '?':
270 exit(EXIT_FAILURE);
271
272 default:
273 abort();
274 }
275 }
276 free(short_options);
277
278 if (!db) {
8ad609c0 279 db = default_sb_db();
fed00ab1
AW
280 }
281
282 for (i = n_global_long_options; options[i].name; i++) {
283 free(CONST_CAST(char *, options[i].name));
284 }
285 free(options);
286}
287
288static void
289usage(void)
290{
291 printf("\
66cf8908 292%s: OVN southbound DB management utility\n\
fed00ab1 293\n\
fed00ab1
AW
294usage: %s [OPTIONS] COMMAND [ARG...]\n\
295\n\
66cf8908 296General commands:\n\
fed00ab1
AW
297 show print overview of database contents\n\
298\n\
299Chassis commands:\n\
300 chassis-add CHASSIS ENCAP-TYPE ENCAP-IP create a new chassis named\n\
3c653533
JP
301 CHASSIS with ENCAP-TYPE tunnels\n\
302 and ENCAP-IP\n\
303 chassis-del CHASSIS delete CHASSIS and all of its encaps\n\
fed00ab1
AW
304 and gateway_ports\n\
305\n\
306Port binding commands:\n\
f0f96ba8
RB
307 lsp-bind PORT CHASSIS bind logical port PORT to CHASSIS\n\
308 lsp-unbind PORT reset the port binding of logical port PORT\n\
fed00ab1 309\n\
dc70b67b 310Logical flow commands:\n\
c80eac1f
BP
311 lflow-list [DATAPATH] [LFLOW...] List logical flows for DATAPATH\n\
312 dump-flows [DATAPATH] [LFLOW...] Alias for lflow-list\n\
dc70b67b 313\n\
10471820
LR
314Connection commands:\n\
315 get-connection print the connections\n\
316 del-connection delete the connections\n\
317 set-connection TARGET... set the list of connections to TARGET...\n\
318\n\
319SSL commands:\n\
320 get-ssl print the SSL configuration\n\
321 del-ssl delete the SSL configuration\n\
322 set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\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",
8ad609c0
BP
332 program_name, program_name, ctl_get_db_cmd_usage(),
333 default_sb_db());
bcb58ce0 334 table_usage();
fed00ab1
AW
335 vlog_usage();
336 printf("\
337 --no-syslog equivalent to --verbose=sbctl:syslog:warn\n");
338 printf("\n\
339Other options:\n\
340 -h, --help display this help message\n\
341 -V, --version display version information\n");
66cf8908 342 stream_usage("database", true, true, false);
fed00ab1
AW
343 exit(EXIT_SUCCESS);
344}
345
346\f
347/* ovs-sbctl specific context. Inherits the 'struct ctl_context' as base. */
348struct sbctl_context {
349 struct ctl_context base;
350
351 /* A cache of the contents of the database.
352 *
353 * A command that needs to use any of this information must first call
354 * sbctl_context_populate_cache(). A command that changes anything that
355 * could invalidate the cache must either call
356 * sbctl_context_invalidate_cache() or manually update the cache to
357 * maintain its correctness. */
358 bool cache_valid;
359 /* Maps from chassis name to struct sbctl_chassis. */
360 struct shash chassis;
361 /* Maps from lport name to struct sbctl_port_binding. */
362 struct shash port_bindings;
363};
364
ec4eed45 365/* Casts 'base' into 'struct sbctl_context'. */
fed00ab1
AW
366static struct sbctl_context *
367sbctl_context_cast(struct ctl_context *base)
368{
369 return CONTAINER_OF(base, struct sbctl_context, base);
370}
371
372struct sbctl_chassis {
373 const struct sbrec_chassis *ch_cfg;
374};
375
376struct sbctl_port_binding {
377 const struct sbrec_port_binding *bd_cfg;
378};
379
380static void
381sbctl_context_invalidate_cache(struct ctl_context *ctx)
382{
383 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
384
385 if (!sbctl_ctx->cache_valid) {
386 return;
387 }
388 sbctl_ctx->cache_valid = false;
389 shash_destroy_free_data(&sbctl_ctx->chassis);
390 shash_destroy_free_data(&sbctl_ctx->port_bindings);
391}
392
393static void
394sbctl_context_populate_cache(struct ctl_context *ctx)
395{
396 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
397 const struct sbrec_chassis *chassis_rec;
398 const struct sbrec_port_binding *port_binding_rec;
399 struct sset chassis, port_bindings;
400
401 if (sbctl_ctx->cache_valid) {
402 /* Cache is already populated. */
403 return;
404 }
405 sbctl_ctx->cache_valid = true;
406 shash_init(&sbctl_ctx->chassis);
407 shash_init(&sbctl_ctx->port_bindings);
408 sset_init(&chassis);
409 SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->idl) {
410 struct sbctl_chassis *ch;
411
412 if (!sset_add(&chassis, chassis_rec->name)) {
413 VLOG_WARN("database contains duplicate chassis name (%s)",
414 chassis_rec->name);
415 continue;
416 }
417
418 ch = xmalloc(sizeof *ch);
419 ch->ch_cfg = chassis_rec;
420 shash_add(&sbctl_ctx->chassis, chassis_rec->name, ch);
421 }
422 sset_destroy(&chassis);
423
424 sset_init(&port_bindings);
425 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->idl) {
426 struct sbctl_port_binding *bd;
427
428 if (!sset_add(&port_bindings, port_binding_rec->logical_port)) {
429 VLOG_WARN("database contains duplicate port binding for logical "
430 "port (%s)",
431 port_binding_rec->logical_port);
432 continue;
433 }
434
435 bd = xmalloc(sizeof *bd);
436 bd->bd_cfg = port_binding_rec;
437 shash_add(&sbctl_ctx->port_bindings, port_binding_rec->logical_port,
438 bd);
439 }
440 sset_destroy(&port_bindings);
441}
442
443static void
444check_conflicts(struct sbctl_context *sbctl_ctx, const char *name,
445 char *msg)
446{
447 if (shash_find(&sbctl_ctx->chassis, name)) {
448 ctl_fatal("%s because a chassis named %s already exists",
449 msg, name);
450 }
451 free(msg);
452}
453
454static struct sbctl_chassis *
455find_chassis(struct sbctl_context *sbctl_ctx, const char *name,
456 bool must_exist)
457{
458 struct sbctl_chassis *sbctl_ch;
459
460 ovs_assert(sbctl_ctx->cache_valid);
461
462 sbctl_ch = shash_find_data(&sbctl_ctx->chassis, name);
463 if (must_exist && !sbctl_ch) {
464 ctl_fatal("no chassis named %s", name);
465 }
466
467 return sbctl_ch;
468}
469
470static struct sbctl_port_binding *
471find_port_binding(struct sbctl_context *sbctl_ctx, const char *name,
472 bool must_exist)
473{
474 struct sbctl_port_binding *bd;
475
476 ovs_assert(sbctl_ctx->cache_valid);
477
478 bd = shash_find_data(&sbctl_ctx->port_bindings, name);
479 if (must_exist && !bd) {
480 ctl_fatal("no port named %s", name);
481 }
482
483 return bd;
484}
485
486static void
487pre_get_info(struct ctl_context *ctx)
488{
489 ovsdb_idl_add_column(ctx->idl, &sbrec_chassis_col_name);
490 ovsdb_idl_add_column(ctx->idl, &sbrec_chassis_col_encaps);
491
492 ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_type);
493 ovsdb_idl_add_column(ctx->idl, &sbrec_encap_col_ip);
494
495 ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_logical_port);
496 ovsdb_idl_add_column(ctx->idl, &sbrec_port_binding_col_chassis);
dc70b67b
RB
497
498 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_logical_datapath);
499 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_pipeline);
500 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_actions);
501 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_priority);
502 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_table_id);
503 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_match);
ebbcddeb 504 ovsdb_idl_add_column(ctx->idl, &sbrec_logical_flow_col_external_ids);
0f8e9c12
BP
505
506 ovsdb_idl_add_column(ctx->idl, &sbrec_datapath_binding_col_external_ids);
fed00ab1
AW
507}
508
509static struct cmd_show_table cmd_show_tables[] = {
510 {&sbrec_table_chassis,
511 &sbrec_chassis_col_name,
2229f3ec
RB
512 {&sbrec_chassis_col_hostname,
513 &sbrec_chassis_col_encaps,
016e4684
AW
514 NULL},
515 {&sbrec_table_port_binding,
516 &sbrec_port_binding_col_logical_port,
517 &sbrec_port_binding_col_chassis}},
fed00ab1
AW
518
519 {&sbrec_table_encap,
520 &sbrec_encap_col_type,
521 {&sbrec_encap_col_ip,
522 &sbrec_encap_col_options,
016e4684
AW
523 NULL},
524 {NULL, NULL, NULL}},
fed00ab1 525
016e4684 526 {NULL, NULL, {NULL, NULL, NULL}, {NULL, NULL, NULL}},
fed00ab1
AW
527};
528
fa183acc
BP
529static void
530sbctl_init(struct ctl_context *ctx OVS_UNUSED)
531{
532}
533
fed00ab1
AW
534static void
535cmd_chassis_add(struct ctl_context *ctx)
536{
537 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
fed00ab1 538 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
3c653533 539 const char *ch_name, *encap_types, *encap_ip;
fed00ab1
AW
540
541 ch_name = ctx->argv[1];
3c653533 542 encap_types = ctx->argv[2];
fed00ab1
AW
543 encap_ip = ctx->argv[3];
544
545 sbctl_context_populate_cache(ctx);
546 if (may_exist) {
547 struct sbctl_chassis *sbctl_ch;
548
549 sbctl_ch = find_chassis(sbctl_ctx, ch_name, false);
550 if (sbctl_ch) {
551 return;
552 }
553 }
554 check_conflicts(sbctl_ctx, ch_name,
555 xasprintf("cannot create a chassis named %s", ch_name));
3c653533 556
63a10e1e
BP
557 struct sset encap_set;
558 sset_from_delimited_string(&encap_set, encap_types, ",");
3c653533
JP
559
560 size_t n_encaps = sset_count(&encap_set);
561 struct sbrec_encap **encaps = xmalloc(n_encaps * sizeof *encaps);
36283d78 562 const struct smap options = SMAP_CONST1(&options, "csum", "true");
3c653533
JP
563 const char *encap_type;
564 int i = 0;
565 SSET_FOR_EACH (encap_type, &encap_set){
566 encaps[i] = sbrec_encap_insert(ctx->txn);
567
568 sbrec_encap_set_type(encaps[i], encap_type);
569 sbrec_encap_set_ip(encaps[i], encap_ip);
36283d78 570 sbrec_encap_set_options(encaps[i], &options);
3c653533
JP
571 i++;
572 }
573 sset_destroy(&encap_set);
574
575 struct sbrec_chassis *ch = sbrec_chassis_insert(ctx->txn);
fed00ab1 576 sbrec_chassis_set_name(ch, ch_name);
3c653533
JP
577 sbrec_chassis_set_encaps(ch, encaps, n_encaps);
578 free(encaps);
579
fed00ab1
AW
580 sbctl_context_invalidate_cache(ctx);
581}
582
583static void
584cmd_chassis_del(struct ctl_context *ctx)
585{
586 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
587 bool must_exist = !shash_find(&ctx->options, "--if-exists");
588 struct sbctl_chassis *sbctl_ch;
589
590 sbctl_context_populate_cache(ctx);
591 sbctl_ch = find_chassis(sbctl_ctx, ctx->argv[1], must_exist);
592 if (sbctl_ch) {
593 if (sbctl_ch->ch_cfg) {
3b74b8c0
AW
594 size_t i;
595
596 for (i = 0; i < sbctl_ch->ch_cfg->n_encaps; i++) {
597 sbrec_encap_delete(sbctl_ch->ch_cfg->encaps[i]);
598 }
fed00ab1
AW
599 sbrec_chassis_delete(sbctl_ch->ch_cfg);
600 }
601 shash_find_and_delete(&sbctl_ctx->chassis, ctx->argv[1]);
602 free(sbctl_ch);
603 }
604}
605
606static void
f0f96ba8 607cmd_lsp_bind(struct ctl_context *ctx)
fed00ab1
AW
608{
609 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
610 bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;
611 struct sbctl_chassis *sbctl_ch;
612 struct sbctl_port_binding *sbctl_bd;
613 char *lport_name, *ch_name;
614
615 /* port_binding must exist, chassis must exist! */
616 lport_name = ctx->argv[1];
617 ch_name = ctx->argv[2];
618
619 sbctl_context_populate_cache(ctx);
620 sbctl_bd = find_port_binding(sbctl_ctx, lport_name, true);
621 sbctl_ch = find_chassis(sbctl_ctx, ch_name, true);
622
623 if (sbctl_bd->bd_cfg->chassis) {
624 if (may_exist && sbctl_bd->bd_cfg->chassis == sbctl_ch->ch_cfg) {
625 return;
626 } else {
627 ctl_fatal("lport (%s) has already been binded to chassis (%s)",
628 lport_name, sbctl_bd->bd_cfg->chassis->name);
629 }
630 }
631 sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, sbctl_ch->ch_cfg);
632 sbctl_context_invalidate_cache(ctx);
633}
634
635static void
f0f96ba8 636cmd_lsp_unbind(struct ctl_context *ctx)
fed00ab1
AW
637{
638 struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx);
639 bool must_exist = !shash_find(&ctx->options, "--if-exists");
640 struct sbctl_port_binding *sbctl_bd;
641 char *lport_name;
642
643 lport_name = ctx->argv[1];
644 sbctl_context_populate_cache(ctx);
645 sbctl_bd = find_port_binding(sbctl_ctx, lport_name, must_exist);
646 if (sbctl_bd) {
647 sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, NULL);
648 }
649}
650
dc70b67b
RB
651enum {
652 PL_INGRESS,
653 PL_EGRESS,
654};
655
656/* Help ensure we catch any future pipeline values */
657static int
658pipeline_encode(const char *pl)
659{
660 if (!strcmp(pl, "ingress")) {
661 return PL_INGRESS;
662 } else if (!strcmp(pl, "egress")) {
663 return PL_EGRESS;
664 }
665
666 OVS_NOT_REACHED();
667}
668
669static int
670lflow_cmp(const void *lf1_, const void *lf2_)
671{
35107449
BP
672 const struct sbrec_logical_flow *const *lf1p = lf1_;
673 const struct sbrec_logical_flow *const *lf2p = lf2_;
674 const struct sbrec_logical_flow *lf1 = *lf1p;
675 const struct sbrec_logical_flow *lf2 = *lf2p;
dc70b67b
RB
676
677 int pl1 = pipeline_encode(lf1->pipeline);
678 int pl2 = pipeline_encode(lf2->pipeline);
679
680#define CMP(expr) \
681 do { \
682 int res; \
683 res = (expr); \
684 if (res) { \
685 return res; \
686 } \
687 } while (0)
688
689 CMP(uuid_compare_3way(&lf1->logical_datapath->header_.uuid,
690 &lf2->logical_datapath->header_.uuid));
691 CMP(pl1 - pl2);
692 CMP(lf1->table_id > lf2->table_id ? 1 :
693 (lf1->table_id < lf2->table_id ? -1 : 0));
694 CMP(lf1->priority > lf2->priority ? -1 :
695 (lf1->priority < lf2->priority ? 1 : 0));
696 CMP(strcmp(lf1->match, lf2->match));
697
698#undef CMP
699
700 return 0;
701}
702
c80eac1f
BP
703static char *
704parse_partial_uuid(char *s)
705{
706 /* Accept a full or partial UUID. */
2052f3a1 707 if (uuid_is_partial_string(s)) {
c80eac1f
BP
708 return s;
709 }
710
711 /* Accept a full or partial UUID prefixed by 0x, since "ovs-ofctl
712 * dump-flows" prints cookies prefixed by 0x. */
713 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')
2052f3a1 714 && uuid_is_partial_string(s + 2)) {
c80eac1f
BP
715 return s + 2;
716 }
717
718 /* Not a (partial) UUID. */
719 return NULL;
720}
721
8b8d09dc
HZ
722static const char *
723strip_leading_zero(const char *s)
724{
725 return s + strspn(s, "0");
726}
727
c80eac1f
BP
728static bool
729is_partial_uuid_match(const struct uuid *uuid, const char *match)
730{
731 char uuid_s[UUID_LEN + 1];
732 snprintf(uuid_s, sizeof uuid_s, UUID_FMT, UUID_ARGS(uuid));
733
4e3000a0
BP
734 /* We strip leading zeros because we want to accept cookie values derived
735 * from UUIDs, and cookie values are printed without leading zeros because
736 * they're just numbers. */
8b8d09dc
HZ
737 const char *s1 = strip_leading_zero(uuid_s);
738 const char *s2 = strip_leading_zero(match);
739
740 return !strncmp(s1, s2, strlen(s2));
c80eac1f
BP
741}
742
c2f4c39b
BP
743static char *
744default_ovs(void)
745{
746 return xasprintf("unix:%s/br-int.mgmt", ovs_rundir());
747}
748
749static struct vconn *
750sbctl_open_vconn(struct shash *options)
751{
752 struct shash_node *ovs = shash_find(options, "--ovs");
753 if (!ovs) {
754 return NULL;
755 }
756
757 char *remote = ovs->data ? xstrdup(ovs->data) : default_ovs();
758 struct vconn *vconn;
759 int retval = vconn_open_block(remote, 1 << OFP13_VERSION, 0, &vconn);
760 if (retval) {
761 VLOG_WARN("%s: connection failed (%s)", remote, ovs_strerror(retval));
762 }
763 free(remote);
764 return vconn;
765}
766
767static void
768sbctl_dump_openflow(struct vconn *vconn, const struct uuid *uuid, bool stats)
769{
770 struct ofputil_flow_stats_request fsr = {
771 .cookie = htonll(uuid->parts[0]),
772 .cookie_mask = OVS_BE64_MAX,
773 .out_port = OFPP_ANY,
774 .out_group = OFPG_ANY,
775 .table_id = OFPTT_ALL,
776 };
777
778 struct ofputil_flow_stats *fses;
779 size_t n_fses;
780 int error = vconn_dump_flows(vconn, &fsr, OFPUTIL_P_OF13_OXM,
781 &fses, &n_fses);
782 if (error) {
783 VLOG_WARN("%s: error obtaining flow stats (%s)",
784 vconn_get_name(vconn), ovs_strerror(error));
785 return;
786 }
787
788 if (n_fses) {
789 struct ds s = DS_EMPTY_INITIALIZER;
790 for (size_t i = 0; i < n_fses; i++) {
791 const struct ofputil_flow_stats *fs = &fses[i];
792
793 ds_clear(&s);
794 if (stats) {
50f96b10 795 ofp_print_flow_stats(&s, fs, NULL);
c2f4c39b
BP
796 } else {
797 ds_put_format(&s, " %stable=%s%"PRIu8" ",
798 colors.special, colors.end, fs->table_id);
50f96b10 799 match_format(&fs->match, NULL, &s, OFP_DEFAULT_PRIORITY);
c2f4c39b
BP
800 if (ds_last(&s) != ' ') {
801 ds_put_char(&s, ' ');
802 }
803
804 ds_put_format(&s, "%sactions=%s", colors.actions, colors.end);
50f96b10 805 ofpacts_format(fs->ofpacts, fs->ofpacts_len, NULL, &s);
c2f4c39b
BP
806 }
807 printf(" %s\n", ds_cstr(&s));
808 }
809 ds_destroy(&s);
810 }
811
812 for (size_t i = 0; i < n_fses; i++) {
813 free(CONST_CAST(struct ofpact *, fses[i].ofpacts));
814 }
815 free(fses);
816}
817
dc70b67b
RB
818static void
819cmd_lflow_list(struct ctl_context *ctx)
820{
c80eac1f
BP
821 const struct sbrec_datapath_binding *datapath = NULL;
822 if (ctx->argc > 1) {
bed7aef9
BP
823 datapath = (const struct sbrec_datapath_binding *)
824 ctl_get_row(ctx, &sbrec_table_datapath_binding,
825 ctx->argv[1], false);
c80eac1f
BP
826 if (datapath) {
827 ctx->argc--;
828 ctx->argv++;
829 }
830 }
dc70b67b 831
c80eac1f
BP
832 for (size_t i = 1; i < ctx->argc; i++) {
833 char *s = parse_partial_uuid(ctx->argv[i]);
834 if (!s) {
835 ctl_fatal("%s is not a UUID or the beginning of a UUID",
836 ctx->argv[i]);
837 }
838 ctx->argv[i] = s;
dc70b67b
RB
839 }
840
c2f4c39b
BP
841 struct vconn *vconn = sbctl_open_vconn(&ctx->options);
842 bool stats = shash_find(&ctx->options, "--stats") != NULL;
843
c80eac1f
BP
844 const struct sbrec_logical_flow **lflows = NULL;
845 size_t n_flows = 0;
846 size_t n_capacity = 0;
847 const struct sbrec_logical_flow *lflow;
dc70b67b 848 SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->idl) {
c80eac1f
BP
849 if (datapath && lflow->logical_datapath != datapath) {
850 continue;
851 }
852
dc70b67b
RB
853 if (n_flows == n_capacity) {
854 lflows = x2nrealloc(lflows, &n_capacity, sizeof *lflows);
855 }
856 lflows[n_flows] = lflow;
857 n_flows++;
858 }
dc70b67b
RB
859 qsort(lflows, n_flows, sizeof *lflows, lflow_cmp);
860
c80eac1f
BP
861 bool print_uuid = shash_find(&ctx->options, "--uuid") != NULL;
862
863 const struct sbrec_logical_flow *prev = NULL;
864 for (size_t i = 0; i < n_flows; i++) {
dc70b67b 865 lflow = lflows[i];
c80eac1f
BP
866
867 /* Figure out whether to print this particular flow. By default, we
868 * print all flows, but if any UUIDs were listed on the command line
869 * then we only print the matching ones. */
870 bool include;
871 if (ctx->argc > 1) {
872 include = false;
873 for (size_t j = 1; j < ctx->argc; j++) {
874 if (is_partial_uuid_match(&lflow->header_.uuid,
875 ctx->argv[j])) {
876 include = true;
877 break;
878 }
879 }
880 } else {
881 include = true;
882 }
883 if (!include) {
dc70b67b
RB
884 continue;
885 }
c80eac1f
BP
886
887 /* Print a header line for this datapath or pipeline, if we haven't
888 * already done so. */
889 if (!prev
890 || prev->logical_datapath != lflow->logical_datapath
891 || strcmp(prev->pipeline, lflow->pipeline)) {
f658b27c
BP
892 printf("Datapath:");
893
894 const struct smap *ids = &lflow->logical_datapath->external_ids;
895 const char *name = smap_get(ids, "name");
896 const char *name2 = smap_get(ids, "name2");
897 if (name && name2) {
898 printf(" \"%s\" aka \"%s\"", name, name2);
899 } else if (name || name2) {
900 printf(" \"%s\"", name ? name : name2);
901 }
902 printf(" ("UUID_FMT") Pipeline: %s\n",
0f8e9c12
BP
903 UUID_ARGS(&lflow->logical_datapath->header_.uuid),
904 lflow->pipeline);
dc70b67b 905 }
ebbcddeb 906
c80eac1f
BP
907 /* Print the flow. */
908 printf(" ");
909 if (print_uuid) {
910 printf("uuid=0x%08"PRIx32", ", lflow->header_.uuid.parts[0]);
911 }
912 printf("table=%-2"PRId64"(%-19s), priority=%-5"PRId64
ebbcddeb 913 ", match=(%s), action=(%s)\n",
f99f67bd
BP
914 lflow->table_id,
915 smap_get_def(&lflow->external_ids, "stage-name", ""),
ebbcddeb 916 lflow->priority, lflow->match, lflow->actions);
c2f4c39b
BP
917 if (vconn) {
918 sbctl_dump_openflow(vconn, &lflow->header_.uuid, stats);
919 }
c80eac1f 920 prev = lflow;
dc70b67b
RB
921 }
922
c2f4c39b 923 vconn_close(vconn);
dc70b67b
RB
924 free(lflows);
925}
926
10471820
LR
927static void
928verify_connections(struct ctl_context *ctx)
929{
930 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
931 const struct sbrec_connection *conn;
932
933 sbrec_sb_global_verify_connections(sb_global);
934
935 SBREC_CONNECTION_FOR_EACH(conn, ctx->idl) {
936 sbrec_connection_verify_target(conn);
937 }
938}
939
940static void
941pre_connection(struct ctl_context *ctx)
942{
943 ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_connections);
944 ovsdb_idl_add_column(ctx->idl, &sbrec_connection_col_target);
945 ovsdb_idl_add_column(ctx->idl, &sbrec_connection_col_read_only);
946}
947
948static void
949cmd_get_connection(struct ctl_context *ctx)
950{
951 const struct sbrec_connection *conn;
952 struct svec targets;
953 size_t i;
954
955 verify_connections(ctx);
956
957 /* Print the targets in sorted order for reproducibility. */
958 svec_init(&targets);
959
960 SBREC_CONNECTION_FOR_EACH(conn, ctx->idl) {
961 char *s;
962
963 s = xasprintf("%s %s", conn->read_only ? "read-only" : "read-write",
964 conn->target);
965 svec_add(&targets, s);
966 free(s);
967 }
968
969 svec_sort_unique(&targets);
970 for (i = 0; i < targets.n; i++) {
971 ds_put_format(&ctx->output, "%s\n", targets.names[i]);
972 }
973 svec_destroy(&targets);
974}
975
976static void
977delete_connections(struct ctl_context *ctx)
978{
979 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
980 const struct sbrec_connection *conn, *next;
981
982 /* Delete Manager rows pointed to by 'connection_options' column. */
983 SBREC_CONNECTION_FOR_EACH_SAFE(conn, next, ctx->idl) {
984 sbrec_connection_delete(conn);
985 }
986
987 /* Delete 'Manager' row refs in 'manager_options' column. */
988 sbrec_sb_global_set_connections(sb_global, NULL, 0);
989}
990
991static void
992cmd_del_connection(struct ctl_context *ctx)
993{
994 verify_connections(ctx);
995 delete_connections(ctx);
996}
997
998static void
999insert_connections(struct ctl_context *ctx, char *targets[], size_t n)
1000{
1001 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
1002 struct sbrec_connection **connections;
1003 size_t i, conns=0;
1004 bool read_only = false;
1005
1006 /* Insert each connection in a new row in Connection table. */
1007 connections = xmalloc(n * sizeof *connections);
1008 for (i = 0; i < n; i++) {
1009 if (!strcmp(targets[i], "read-only")) {
1010 read_only = true;
1011 continue;
1012 } else if (!strcmp(targets[i], "read-write")) {
1013 read_only = false;
1014 continue;
1015 } else if (stream_verify_name(targets[i]) &&
1016 pstream_verify_name(targets[i])) {
1017 VLOG_WARN("target type \"%s\" is possibly erroneous", targets[i]);
1018 }
1019
1020 connections[conns] = sbrec_connection_insert(ctx->txn);
1021 sbrec_connection_set_target(connections[conns], targets[i]);
1022 sbrec_connection_set_read_only(connections[conns], read_only);
1023 conns++;
1024 }
1025
1026 /* Store uuids of new connection rows in 'connection' column. */
1027 sbrec_sb_global_set_connections(sb_global, connections, conns);
1028 free(connections);
1029}
1030
1031static void
1032cmd_set_connection(struct ctl_context *ctx)
1033{
1034 const size_t n = ctx->argc - 1;
1035
1036 verify_connections(ctx);
1037 delete_connections(ctx);
1038 insert_connections(ctx, &ctx->argv[1], n);
1039}
1040
1041static void
1042pre_cmd_get_ssl(struct ctl_context *ctx)
1043{
1044 ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl);
1045
1046 ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_private_key);
1047 ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_certificate);
1048 ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_ca_cert);
1049 ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_bootstrap_ca_cert);
1050}
1051
1052static void
1053cmd_get_ssl(struct ctl_context *ctx)
1054{
1055 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
1056 const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl);
1057
1058 sbrec_sb_global_verify_ssl(sb_global);
1059 if (ssl) {
1060 sbrec_ssl_verify_private_key(ssl);
1061 sbrec_ssl_verify_certificate(ssl);
1062 sbrec_ssl_verify_ca_cert(ssl);
1063 sbrec_ssl_verify_bootstrap_ca_cert(ssl);
1064
1065 ds_put_format(&ctx->output, "Private key: %s\n", ssl->private_key);
1066 ds_put_format(&ctx->output, "Certificate: %s\n", ssl->certificate);
1067 ds_put_format(&ctx->output, "CA Certificate: %s\n", ssl->ca_cert);
1068 ds_put_format(&ctx->output, "Bootstrap: %s\n",
1069 ssl->bootstrap_ca_cert ? "true" : "false");
1070 }
1071}
1072
1073static void
1074pre_cmd_del_ssl(struct ctl_context *ctx)
1075{
1076 ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl);
1077}
1078
1079static void
1080cmd_del_ssl(struct ctl_context *ctx)
1081{
1082 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
1083 const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl);
1084
1085 if (ssl) {
1086 sbrec_sb_global_verify_ssl(sb_global);
1087 sbrec_ssl_delete(ssl);
1088 sbrec_sb_global_set_ssl(sb_global, NULL);
1089 }
1090}
1091
1092static void
1093pre_cmd_set_ssl(struct ctl_context *ctx)
1094{
1095 ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl);
1096}
1097
1098static void
1099cmd_set_ssl(struct ctl_context *ctx)
1100{
1101 bool bootstrap = shash_find(&ctx->options, "--bootstrap");
1102 const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl);
1103 const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl);
1104
1105 sbrec_sb_global_verify_ssl(sb_global);
1106 if (ssl) {
1107 sbrec_ssl_delete(ssl);
1108 }
1109 ssl = sbrec_ssl_insert(ctx->txn);
1110
1111 sbrec_ssl_set_private_key(ssl, ctx->argv[1]);
1112 sbrec_ssl_set_certificate(ssl, ctx->argv[2]);
1113 sbrec_ssl_set_ca_cert(ssl, ctx->argv[3]);
1114
1115 sbrec_ssl_set_bootstrap_ca_cert(ssl, bootstrap);
1116
1117 sbrec_sb_global_set_ssl(sb_global, ssl);
1118}
1119
fed00ab1 1120\f
3f5b5f7b 1121static const struct ctl_table_class tables[SBREC_N_TABLES] = {
15931827 1122 [SBREC_TABLE_CHASSIS].row_ids[0] = {&sbrec_chassis_col_name, NULL, NULL},
fa183acc 1123
682b4171
BP
1124 [SBREC_TABLE_DATAPATH_BINDING].row_ids
1125 = {{&sbrec_datapath_binding_col_external_ids, "name", NULL},
f658b27c 1126 {&sbrec_datapath_binding_col_external_ids, "name2", NULL},
682b4171
BP
1127 {&sbrec_datapath_binding_col_external_ids, "logical-switch", NULL},
1128 {&sbrec_datapath_binding_col_external_ids, "logical-router", NULL}},
1129
f658b27c
BP
1130 [SBREC_TABLE_PORT_BINDING].row_ids
1131 = {{&sbrec_port_binding_col_logical_port, NULL, NULL},
1132 {&sbrec_port_binding_col_external_ids, "name", NULL}},
9c39b120 1133
3f5b5f7b 1134 [SBREC_TABLE_MAC_BINDING].row_ids[0] =
15931827 1135 {&sbrec_mac_binding_col_logical_port, NULL, NULL},
7fff4eb7 1136
15931827
BP
1137 [SBREC_TABLE_ADDRESS_SET].row_ids[0]
1138 = {&sbrec_address_set_col_name, NULL, NULL},
fed00ab1
AW
1139};
1140
1141\f
1142static void
1143sbctl_context_init_command(struct sbctl_context *sbctl_ctx,
1144 struct ctl_command *command)
1145{
1146 ctl_context_init_command(&sbctl_ctx->base, command);
1147}
1148
1149static void
1150sbctl_context_init(struct sbctl_context *sbctl_ctx,
1151 struct ctl_command *command, struct ovsdb_idl *idl,
1152 struct ovsdb_idl_txn *txn,
1153 struct ovsdb_symbol_table *symtab)
1154{
1155 ctl_context_init(&sbctl_ctx->base, command, idl, txn, symtab,
1156 sbctl_context_invalidate_cache);
1157 sbctl_ctx->cache_valid = false;
1158}
1159
1160static void
1161sbctl_context_done_command(struct sbctl_context *sbctl_ctx,
1162 struct ctl_command *command)
1163{
1164 ctl_context_done_command(&sbctl_ctx->base, command);
1165}
1166
1167static void
1168sbctl_context_done(struct sbctl_context *sbctl_ctx,
1169 struct ctl_command *command)
1170{
1171 ctl_context_done(&sbctl_ctx->base, command);
1172}
1173
1174static void
1175run_prerequisites(struct ctl_command *commands, size_t n_commands,
1176 struct ovsdb_idl *idl)
1177{
fa183acc 1178 ovsdb_idl_add_table(idl, &sbrec_table_sb_global);
fed00ab1 1179
fa183acc 1180 for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) {
fed00ab1
AW
1181 if (c->syntax->prerequisites) {
1182 struct sbctl_context sbctl_ctx;
1183
1184 ds_init(&c->output);
1185 c->table = NULL;
1186
1187 sbctl_context_init(&sbctl_ctx, c, idl, NULL, NULL);
1188 (c->syntax->prerequisites)(&sbctl_ctx.base);
1189 sbctl_context_done(&sbctl_ctx, c);
1190
1191 ovs_assert(!c->output.string);
1192 ovs_assert(!c->table);
1193 }
1194 }
1195}
1196
8ee574c3 1197static bool
fed00ab1
AW
1198do_sbctl(const char *args, struct ctl_command *commands, size_t n_commands,
1199 struct ovsdb_idl *idl)
1200{
1201 struct ovsdb_idl_txn *txn;
1202 enum ovsdb_idl_txn_status status;
1203 struct ovsdb_symbol_table *symtab;
1204 struct sbctl_context sbctl_ctx;
1205 struct ctl_command *c;
1206 struct shash_node *node;
1207 char *error = NULL;
1208
1209 txn = the_idl_txn = ovsdb_idl_txn_create(idl);
1210 if (dry_run) {
1211 ovsdb_idl_txn_set_dry_run(txn);
1212 }
1213
1214 ovsdb_idl_txn_add_comment(txn, "ovs-sbctl: %s", args);
1215
fa183acc
BP
1216 const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl);
1217 if (!sb) {
1218 /* XXX add verification that table is empty */
1219 sb = sbrec_sb_global_insert(txn);
1220 }
1221
fed00ab1
AW
1222 symtab = ovsdb_symbol_table_create();
1223 for (c = commands; c < &commands[n_commands]; c++) {
1224 ds_init(&c->output);
1225 c->table = NULL;
1226 }
1227 sbctl_context_init(&sbctl_ctx, NULL, idl, txn, symtab);
1228 for (c = commands; c < &commands[n_commands]; c++) {
1229 sbctl_context_init_command(&sbctl_ctx, c);
1230 if (c->syntax->run) {
1231 (c->syntax->run)(&sbctl_ctx.base);
1232 }
1233 sbctl_context_done_command(&sbctl_ctx, c);
1234
1235 if (sbctl_ctx.base.try_again) {
1236 sbctl_context_done(&sbctl_ctx, NULL);
1237 goto try_again;
1238 }
1239 }
1240 sbctl_context_done(&sbctl_ctx, NULL);
1241
1242 SHASH_FOR_EACH (node, &symtab->sh) {
1243 struct ovsdb_symbol *symbol = node->data;
1244 if (!symbol->created) {
1245 ctl_fatal("row id \"%s\" is referenced but never created (e.g. "
b31301bc
BP
1246 "with \"-- --id=%s create ...\")",
1247 node->name, node->name);
fed00ab1
AW
1248 }
1249 if (!symbol->strong_ref) {
1250 if (!symbol->weak_ref) {
1251 VLOG_WARN("row id \"%s\" was created but no reference to it "
1252 "was inserted, so it will not actually appear in "
1253 "the database", node->name);
1254 } else {
1255 VLOG_WARN("row id \"%s\" was created but only a weak "
1256 "reference to it was inserted, so it will not "
1257 "actually appear in the database", node->name);
1258 }
1259 }
1260 }
1261
1262 status = ovsdb_idl_txn_commit_block(txn);
1263 if (status == TXN_UNCHANGED || status == TXN_SUCCESS) {
1264 for (c = commands; c < &commands[n_commands]; c++) {
1265 if (c->syntax->postprocess) {
1266 sbctl_context_init(&sbctl_ctx, c, idl, txn, symtab);
1267 (c->syntax->postprocess)(&sbctl_ctx.base);
1268 sbctl_context_done(&sbctl_ctx, c);
1269 }
1270 }
1271 }
1272 error = xstrdup(ovsdb_idl_txn_get_error(txn));
1273
1274 switch (status) {
1275 case TXN_UNCOMMITTED:
1276 case TXN_INCOMPLETE:
1277 OVS_NOT_REACHED();
1278
1279 case TXN_ABORTED:
1280 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1281 ctl_fatal("transaction aborted");
1282
1283 case TXN_UNCHANGED:
1284 case TXN_SUCCESS:
1285 break;
1286
1287 case TXN_TRY_AGAIN:
1288 goto try_again;
1289
1290 case TXN_ERROR:
1291 ctl_fatal("transaction error: %s", error);
1292
1293 case TXN_NOT_LOCKED:
1294 /* Should not happen--we never call ovsdb_idl_set_lock(). */
1295 ctl_fatal("database not locked");
1296
1297 default:
1298 OVS_NOT_REACHED();
1299 }
1300 free(error);
1301
1302 ovsdb_symbol_table_destroy(symtab);
1303
1304 for (c = commands; c < &commands[n_commands]; c++) {
1305 struct ds *ds = &c->output;
1306
1307 if (c->table) {
1308 table_print(c->table, &table_style);
1309 } else if (oneline) {
1310 size_t j;
1311
1312 ds_chomp(ds, '\n');
1313 for (j = 0; j < ds->length; j++) {
1314 int ch = ds->string[j];
1315 switch (ch) {
1316 case '\n':
1317 fputs("\\n", stdout);
1318 break;
1319
1320 case '\\':
1321 fputs("\\\\", stdout);
1322 break;
1323
1324 default:
1325 putchar(ch);
1326 }
1327 }
1328 putchar('\n');
1329 } else {
1330 fputs(ds_cstr(ds), stdout);
1331 }
1332 ds_destroy(&c->output);
1333 table_destroy(c->table);
1334 free(c->table);
1335
1336 shash_destroy_free_data(&c->options);
1337 }
1338 free(commands);
1339 ovsdb_idl_txn_destroy(txn);
1340 ovsdb_idl_destroy(idl);
1341
8ee574c3 1342 return true;
fed00ab1
AW
1343
1344try_again:
1345 /* Our transaction needs to be rerun, or a prerequisite was not met. Free
1346 * resources and return so that the caller can try again. */
6851589c
BP
1347 ovsdb_idl_txn_abort(txn);
1348 ovsdb_idl_txn_destroy(txn);
1349 the_idl_txn = NULL;
1350
fed00ab1
AW
1351 ovsdb_symbol_table_destroy(symtab);
1352 for (c = commands; c < &commands[n_commands]; c++) {
1353 ds_destroy(&c->output);
1354 table_destroy(c->table);
1355 free(c->table);
1356 }
1357 free(error);
8ee574c3 1358 return false;
fed00ab1
AW
1359}
1360
1361/* Frees the current transaction and the underlying IDL and then calls
1362 * exit(status).
1363 *
1364 * Freeing the transaction and the IDL is not strictly necessary, but it makes
1365 * for a clean memory leak report from valgrind in the normal case. That makes
1366 * it easier to notice real memory leaks. */
1367static void
1368sbctl_exit(int status)
1369{
1370 if (the_idl_txn) {
1371 ovsdb_idl_txn_abort(the_idl_txn);
1372 ovsdb_idl_txn_destroy(the_idl_txn);
1373 }
1374 ovsdb_idl_destroy(the_idl);
1375 exit(status);
1376}
1377
1378static const struct ctl_command_syntax sbctl_commands[] = {
fa183acc
BP
1379 { "init", 0, 0, "", NULL, sbctl_init, NULL, "", RW },
1380
fed00ab1
AW
1381 /* Chassis commands. */
1382 {"chassis-add", 3, 3, "CHASSIS ENCAP-TYPE ENCAP-IP", pre_get_info,
1383 cmd_chassis_add, NULL, "--may-exist", RW},
1384 {"chassis-del", 1, 1, "CHASSIS", pre_get_info, cmd_chassis_del, NULL,
1385 "--if-exists", RW},
1386
1387 /* Port binding commands. */
f0f96ba8 1388 {"lsp-bind", 2, 2, "PORT CHASSIS", pre_get_info, cmd_lsp_bind, NULL,
fed00ab1 1389 "--may-exist", RW},
f0f96ba8 1390 {"lsp-unbind", 1, 1, "PORT", pre_get_info, cmd_lsp_unbind, NULL,
fed00ab1
AW
1391 "--if-exists", RW},
1392
dc70b67b 1393 /* Logical flow commands */
c80eac1f
BP
1394 {"lflow-list", 0, INT_MAX, "[DATAPATH] [LFLOW...]",
1395 pre_get_info, cmd_lflow_list, NULL,
c2f4c39b 1396 "--uuid,--ovs?,--stats", RO},
c80eac1f
BP
1397 {"dump-flows", 0, INT_MAX, "[DATAPATH] [LFLOW...]",
1398 pre_get_info, cmd_lflow_list, NULL,
c2f4c39b 1399 "--uuid,--ovs?,--stats", RO}, /* Friendly alias for lflow-list */
dc70b67b 1400
10471820
LR
1401 /* Connection commands. */
1402 {"get-connection", 0, 0, "", pre_connection, cmd_get_connection, NULL, "", RO},
1403 {"del-connection", 0, 0, "", pre_connection, cmd_del_connection, NULL, "", RW},
1404 {"set-connection", 1, INT_MAX, "TARGET...", pre_connection, cmd_set_connection,
1405 NULL, "", RW},
1406
1407 /* SSL commands. */
1408 {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO},
1409 {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
1410 {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl,
1411 cmd_set_ssl, NULL, "--bootstrap", RW},
fed00ab1
AW
1412
1413 {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO},
1414};
1415
1416/* Registers sbctl and common db commands. */
1417static void
1418sbctl_cmd_init(void)
1419{
3f5b5f7b 1420 ctl_init(sbrec_table_classes, tables, cmd_show_tables, sbctl_exit);
fed00ab1
AW
1421 ctl_register_commands(sbctl_commands);
1422}