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