2 * Copyright (c) 2015, 2016, 2017 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
31 #include "command-line.h"
33 #include "db-ctl-base.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"
51 #include "stream-ssl.h"
58 VLOG_DEFINE_THIS_MODULE(sbctl
);
62 /* --db: The database server to contact. */
63 static const char *db
;
65 /* --oneline: Write each command's output as a single line? */
68 /* --dry-run: Do not commit any changes. */
71 /* --timeout: Time to wait for a connection to 'db'. */
72 static unsigned int timeout
;
74 /* Format for table output. */
75 static struct table_style table_style
= TABLE_STYLE_DEFAULT
;
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
);
84 /* --leader-only, --no-leader-only: Only accept the leader in a cluster. */
85 static int leader_only
= true;
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
,
92 static bool do_sbctl(const char *args
, struct ctl_command
*, size_t n
,
96 main(int argc
, char *argv
[])
98 struct ovsdb_idl
*idl
;
99 struct ctl_command
*commands
;
100 struct shash local_options
;
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");
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
);
118 ctl_fatal("%s", error
);
120 VLOG(ctl_might_write_to_db(commands
, n_commands
) ? VLL_INFO
: VLL_DBG
,
121 "Called as %s", args
);
123 ctl_timeout_setup(timeout
);
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
);
130 /* Execute the commands.
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
);
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
));
146 if (seqno
!= ovsdb_idl_get_seqno(idl
)) {
147 seqno
= ovsdb_idl_get_seqno(idl
);
148 if (do_sbctl(args
, commands
, n_commands
, idl
)) {
154 if (seqno
== ovsdb_idl_get_seqno(idl
)) {
162 parse_options(int argc
, char *argv
[], struct shash
*local_options
)
165 OPT_DB
= UCHAR_MAX
+ 1,
172 OPT_BOOTSTRAP_CA_CERT
,
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'},
190 STREAM_SSL_LONG_OPTIONS
,
191 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
195 const int n_global_long_options
= ARRAY_SIZE(global_long_options
) - 1;
196 char *tmp
, *short_options
;
198 struct option
*options
;
199 size_t allocated_options
;
203 tmp
= ovs_cmdl_long_options_to_short_options(global_long_options
);
204 short_options
= xasprintf("+%s", tmp
);
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
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
);
220 c
= getopt_long(argc
, argv
, short_options
, options
, &idx
);
235 vlog_set_levels(&this_module
, VLF_SYSLOG
, VLL_WARN
);
243 if (shash_find(local_options
, options
[idx
].name
)) {
244 ctl_fatal("'%s' option specified multiple times",
247 shash_add_nocopy(local_options
,
248 xasprintf("--%s", options
[idx
].name
),
249 nullable_xstrdup(optarg
));
256 ctl_print_commands();
260 ctl_print_options(global_long_options
);
264 ovs_print_version(0, 0);
265 printf("DB Schema %s\n", sbrec_get_db_version());
269 if (!str_to_uint(optarg
, 10, &timeout
) || !timeout
) {
270 ctl_fatal("value %s on -t or --timeout is invalid", optarg
);
275 TABLE_OPTION_HANDLERS(&table_style
)
276 STREAM_SSL_OPTION_HANDLERS
278 case OPT_BOOTSTRAP_CA_CERT
:
279 stream_ssl_set_ca_cert_file(optarg
, true);
295 db
= default_sb_db();
298 for (i
= n_global_long_options
; options
[i
].name
; i
++) {
299 free(CONST_CAST(char *, options
[i
].name
));
308 %s: OVN southbound DB management utility\n\
310 usage: %s [OPTIONS] COMMAND [ARG...]\n\
313 show print overview of database contents\n\
316 chassis-add CHASSIS ENCAP-TYPE ENCAP-IP create a new chassis named\n\
317 CHASSIS with ENCAP-TYPE tunnels\n\
319 chassis-del CHASSIS delete CHASSIS and all of its encaps\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\
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\
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\
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\
346 --db=DATABASE connect to DATABASE\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());
357 --no-syslog equivalent to --verbose=sbctl:syslog:warn\n");
360 -h, --help display this help message\n\
361 -V, --version display version information\n");
362 stream_usage("database", true, true, true);
367 /* ovs-sbctl specific context. Inherits the 'struct ctl_context' as base. */
368 struct sbctl_context
{
369 struct ctl_context base
;
371 /* A cache of the contents of the database.
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. */
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
;
385 /* Casts 'base' into 'struct sbctl_context'. */
386 static struct sbctl_context
*
387 sbctl_context_cast(struct ctl_context
*base
)
389 return CONTAINER_OF(base
, struct sbctl_context
, base
);
392 struct sbctl_chassis
{
393 const struct sbrec_chassis
*ch_cfg
;
396 struct sbctl_port_binding
{
397 const struct sbrec_port_binding
*bd_cfg
;
401 sbctl_context_invalidate_cache(struct ctl_context
*ctx
)
403 struct sbctl_context
*sbctl_ctx
= sbctl_context_cast(ctx
);
405 if (!sbctl_ctx
->cache_valid
) {
408 sbctl_ctx
->cache_valid
= false;
409 shash_destroy_free_data(&sbctl_ctx
->chassis
);
410 shash_destroy_free_data(&sbctl_ctx
->port_bindings
);
414 sbctl_context_populate_cache(struct ctl_context
*ctx
)
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
;
421 if (sbctl_ctx
->cache_valid
) {
422 /* Cache is already populated. */
425 sbctl_ctx
->cache_valid
= true;
426 shash_init(&sbctl_ctx
->chassis
);
427 shash_init(&sbctl_ctx
->port_bindings
);
429 SBREC_CHASSIS_FOR_EACH(chassis_rec
, ctx
->idl
) {
430 struct sbctl_chassis
*ch
;
432 if (!sset_add(&chassis
, chassis_rec
->name
)) {
433 VLOG_WARN("database contains duplicate chassis name (%s)",
438 ch
= xmalloc(sizeof *ch
);
439 ch
->ch_cfg
= chassis_rec
;
440 shash_add(&sbctl_ctx
->chassis
, chassis_rec
->name
, ch
);
442 sset_destroy(&chassis
);
444 sset_init(&port_bindings
);
445 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec
, ctx
->idl
) {
446 struct sbctl_port_binding
*bd
;
448 if (!sset_add(&port_bindings
, port_binding_rec
->logical_port
)) {
449 VLOG_WARN("database contains duplicate port binding for logical "
451 port_binding_rec
->logical_port
);
455 bd
= xmalloc(sizeof *bd
);
456 bd
->bd_cfg
= port_binding_rec
;
457 shash_add(&sbctl_ctx
->port_bindings
, port_binding_rec
->logical_port
,
460 sset_destroy(&port_bindings
);
464 check_conflicts(struct sbctl_context
*sbctl_ctx
, const char *name
,
467 if (shash_find(&sbctl_ctx
->chassis
, name
)) {
468 ctl_fatal("%s because a chassis named %s already exists",
474 static struct sbctl_chassis
*
475 find_chassis(struct sbctl_context
*sbctl_ctx
, const char *name
,
478 struct sbctl_chassis
*sbctl_ch
;
480 ovs_assert(sbctl_ctx
->cache_valid
);
482 sbctl_ch
= shash_find_data(&sbctl_ctx
->chassis
, name
);
483 if (must_exist
&& !sbctl_ch
) {
484 ctl_fatal("no chassis named %s", name
);
490 static struct sbctl_port_binding
*
491 find_port_binding(struct sbctl_context
*sbctl_ctx
, const char *name
,
494 struct sbctl_port_binding
*bd
;
496 ovs_assert(sbctl_ctx
->cache_valid
);
498 bd
= shash_find_data(&sbctl_ctx
->port_bindings
, name
);
499 if (must_exist
&& !bd
) {
500 ctl_fatal("no port named %s", name
);
507 pre_get_info(struct ctl_context
*ctx
)
509 ovsdb_idl_add_column(ctx
->idl
, &sbrec_chassis_col_name
);
510 ovsdb_idl_add_column(ctx
->idl
, &sbrec_chassis_col_encaps
);
512 ovsdb_idl_add_column(ctx
->idl
, &sbrec_encap_col_type
);
513 ovsdb_idl_add_column(ctx
->idl
, &sbrec_encap_col_ip
);
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
);
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
);
526 ovsdb_idl_add_column(ctx
->idl
, &sbrec_datapath_binding_col_external_ids
);
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
);
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
,
538 {&sbrec_table_port_binding
,
539 &sbrec_port_binding_col_logical_port
,
540 &sbrec_port_binding_col_chassis
}},
543 &sbrec_encap_col_type
,
544 {&sbrec_encap_col_ip
,
545 &sbrec_encap_col_options
,
549 {NULL
, NULL
, {NULL
, NULL
, NULL
}, {NULL
, NULL
, NULL
}},
553 sbctl_init(struct ctl_context
*ctx OVS_UNUSED
)
558 cmd_chassis_add(struct ctl_context
*ctx
)
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
;
564 ch_name
= ctx
->argv
[1];
565 encap_types
= ctx
->argv
[2];
566 encap_ip
= ctx
->argv
[3];
568 sbctl_context_populate_cache(ctx
);
570 struct sbctl_chassis
*sbctl_ch
;
572 sbctl_ch
= find_chassis(sbctl_ctx
, ch_name
, false);
577 check_conflicts(sbctl_ctx
, ch_name
,
578 xasprintf("cannot create a chassis named %s", ch_name
));
580 struct sset encap_set
;
581 sset_from_delimited_string(&encap_set
, encap_types
, ",");
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
;
588 SSET_FOR_EACH (encap_type
, &encap_set
){
589 encaps
[i
] = sbrec_encap_insert(ctx
->txn
);
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
);
597 sset_destroy(&encap_set
);
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
);
604 sbctl_context_invalidate_cache(ctx
);
608 cmd_chassis_del(struct ctl_context
*ctx
)
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
;
614 sbctl_context_populate_cache(ctx
);
615 sbctl_ch
= find_chassis(sbctl_ctx
, ctx
->argv
[1], must_exist
);
617 if (sbctl_ch
->ch_cfg
) {
620 for (i
= 0; i
< sbctl_ch
->ch_cfg
->n_encaps
; i
++) {
621 sbrec_encap_delete(sbctl_ch
->ch_cfg
->encaps
[i
]);
623 sbrec_chassis_delete(sbctl_ch
->ch_cfg
);
625 shash_find_and_delete(&sbctl_ctx
->chassis
, ctx
->argv
[1]);
631 cmd_lsp_bind(struct ctl_context
*ctx
)
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
;
639 /* port_binding must exist, chassis must exist! */
640 lport_name
= ctx
->argv
[1];
641 ch_name
= ctx
->argv
[2];
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);
647 if (sbctl_bd
->bd_cfg
->chassis
) {
648 if (may_exist
&& sbctl_bd
->bd_cfg
->chassis
== sbctl_ch
->ch_cfg
) {
651 ctl_fatal("lport (%s) has already been binded to chassis (%s)",
652 lport_name
, sbctl_bd
->bd_cfg
->chassis
->name
);
655 sbrec_port_binding_set_chassis(sbctl_bd
->bd_cfg
, sbctl_ch
->ch_cfg
);
656 sbctl_context_invalidate_cache(ctx
);
660 cmd_lsp_unbind(struct ctl_context
*ctx
)
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
;
667 lport_name
= ctx
->argv
[1];
668 sbctl_context_populate_cache(ctx
);
669 sbctl_bd
= find_port_binding(sbctl_ctx
, lport_name
, must_exist
);
671 sbrec_port_binding_set_chassis(sbctl_bd
->bd_cfg
, NULL
);
680 /* Help ensure we catch any future pipeline values */
682 pipeline_encode(const char *pl
)
684 if (!strcmp(pl
, "ingress")) {
686 } else if (!strcmp(pl
, "egress")) {
694 lflow_cmp(const void *lf1_
, const void *lf2_
)
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
;
701 int pl1
= pipeline_encode(lf1
->pipeline
);
702 int pl2
= pipeline_encode(lf2
->pipeline
);
713 CMP(uuid_compare_3way(&lf1
->logical_datapath
->header_
.uuid
,
714 &lf2
->logical_datapath
->header_
.uuid
));
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
));
728 parse_partial_uuid(char *s
)
730 /* Accept a full or partial UUID. */
731 if (uuid_is_partial_string(s
)) {
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)) {
742 /* Not a (partial) UUID. */
747 strip_leading_zero(const char *s
)
749 return s
+ strspn(s
, "0");
753 is_partial_uuid_match(const struct uuid
*uuid
, const char *match
)
755 char uuid_s
[UUID_LEN
+ 1];
756 snprintf(uuid_s
, sizeof uuid_s
, UUID_FMT
, UUID_ARGS(uuid
));
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
);
764 return !strncmp(s1
, s2
, strlen(s2
));
770 return xasprintf("unix:%s/br-int.mgmt", ovs_rundir());
773 static struct vconn
*
774 sbctl_open_vconn(struct shash
*options
)
776 struct shash_node
*ovs
= shash_find(options
, "--ovs");
781 char *remote
= ovs
->data
? xstrdup(ovs
->data
) : default_ovs();
783 int retval
= vconn_open_block(remote
, 1 << OFP13_VERSION
, 0, -1, &vconn
);
785 VLOG_WARN("%s: connection failed (%s)", remote
, ovs_strerror(retval
));
792 sbctl_dump_openflow(struct vconn
*vconn
, const struct uuid
*uuid
, bool stats
)
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
,
802 struct ofputil_flow_stats
*fses
;
804 int error
= vconn_dump_flows(vconn
, &fsr
, OFPUTIL_P_OF13_OXM
,
807 VLOG_WARN("%s: error obtaining flow stats (%s)",
808 vconn_get_name(vconn
), ovs_strerror(error
));
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
];
819 ofputil_flow_stats_format(&s
, fs
, NULL
, NULL
, true);
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
, ' ');
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
);
832 printf(" %s\n", ds_cstr(&s
));
837 for (size_t i
= 0; i
< n_fses
; i
++) {
838 free(CONST_CAST(struct ofpact
*, fses
[i
].ofpacts
));
844 cmd_lflow_list(struct ctl_context
*ctx
)
846 const struct sbrec_datapath_binding
*datapath
= NULL
;
848 const struct ovsdb_idl_row
*row
;
849 char *error
= ctl_get_row(ctx
, &sbrec_table_datapath_binding
,
850 ctx
->argv
[1], false, &row
);
852 ctl_fatal("%s", error
);
855 datapath
= (const struct sbrec_datapath_binding
*)row
;
862 for (size_t i
= 1; i
< ctx
->argc
; i
++) {
863 char *s
= parse_partial_uuid(ctx
->argv
[i
]);
865 ctl_fatal("%s is not a UUID or the beginning of a UUID",
871 struct vconn
*vconn
= sbctl_open_vconn(&ctx
->options
);
872 bool stats
= shash_find(&ctx
->options
, "--stats") != NULL
;
874 const struct sbrec_logical_flow
**lflows
= NULL
;
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
) {
883 if (n_flows
== n_capacity
) {
884 lflows
= x2nrealloc(lflows
, &n_capacity
, sizeof *lflows
);
886 lflows
[n_flows
] = lflow
;
891 qsort(lflows
, n_flows
, sizeof *lflows
, lflow_cmp
);
894 bool print_uuid
= shash_find(&ctx
->options
, "--uuid") != NULL
;
896 const struct sbrec_logical_flow
*prev
= NULL
;
897 for (size_t i
= 0; i
< n_flows
; i
++) {
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. */
906 for (size_t j
= 1; j
< ctx
->argc
; j
++) {
907 if (is_partial_uuid_match(&lflow
->header_
.uuid
,
920 /* Print a header line for this datapath or pipeline, if we haven't
921 * already done so. */
923 || prev
->logical_datapath
!= lflow
->logical_datapath
924 || strcmp(prev
->pipeline
, lflow
->pipeline
)) {
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");
931 printf(" \"%s\" aka \"%s\"", name
, name2
);
932 } else if (name
|| name2
) {
933 printf(" \"%s\"", name
? name
: name2
);
935 printf(" ("UUID_FMT
") Pipeline: %s\n",
936 UUID_ARGS(&lflow
->logical_datapath
->header_
.uuid
),
940 /* Print the flow. */
943 printf("uuid=0x%08"PRIx32
", ", lflow
->header_
.uuid
.parts
[0]);
945 printf("table=%-2"PRId64
"(%-19s), priority=%-5"PRId64
946 ", match=(%s), action=(%s)\n",
948 smap_get_def(&lflow
->external_ids
, "stage-name", ""),
949 lflow
->priority
, lflow
->match
, lflow
->actions
);
951 sbctl_dump_openflow(vconn
, &lflow
->header_
.uuid
, stats
);
961 sbctl_ip_mcast_flush_switch(struct ctl_context
*ctx
,
962 const struct sbrec_datapath_binding
*dp
)
964 const struct sbrec_ip_multicast
*ip_mcast
;
966 /* Lookup the corresponding IP_Multicast entry. */
967 SBREC_IP_MULTICAST_FOR_EACH (ip_mcast
, ctx
->idl
) {
968 if (ip_mcast
->datapath
!= dp
) {
972 sbrec_ip_multicast_set_seq_no(ip_mcast
, ip_mcast
->seq_no
+ 1);
977 sbctl_ip_mcast_flush(struct ctl_context
*ctx
)
979 const struct sbrec_datapath_binding
*dp
;
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
);
990 ctl_fatal("%s", error
);
993 dp
= (const struct sbrec_datapath_binding
*)row
;
995 ctl_fatal("%s is not a valid datapath", ctx
->argv
[1]);
998 sbctl_ip_mcast_flush_switch(ctx
, dp
);
1000 SBREC_DATAPATH_BINDING_FOR_EACH (dp
, ctx
->idl
) {
1001 sbctl_ip_mcast_flush_switch(ctx
, dp
);
1007 verify_connections(struct ctl_context
*ctx
)
1009 const struct sbrec_sb_global
*sb_global
= sbrec_sb_global_first(ctx
->idl
);
1010 const struct sbrec_connection
*conn
;
1012 sbrec_sb_global_verify_connections(sb_global
);
1014 SBREC_CONNECTION_FOR_EACH(conn
, ctx
->idl
) {
1015 sbrec_connection_verify_target(conn
);
1020 pre_connection(struct ctl_context
*ctx
)
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
);
1030 cmd_get_connection(struct ctl_context
*ctx
)
1032 const struct sbrec_connection
*conn
;
1033 struct svec targets
;
1036 verify_connections(ctx
);
1038 /* Print the targets in sorted order for reproducibility. */
1039 svec_init(&targets
);
1041 SBREC_CONNECTION_FOR_EACH(conn
, ctx
->idl
) {
1044 s
= xasprintf("%s role=\"%s\" %s",
1045 conn
->read_only
? "read-only" : "read-write",
1048 svec_add(&targets
, s
);
1052 svec_sort_unique(&targets
);
1053 for (i
= 0; i
< targets
.n
; i
++) {
1054 ds_put_format(&ctx
->output
, "%s\n", targets
.names
[i
]);
1056 svec_destroy(&targets
);
1060 delete_connections(struct ctl_context
*ctx
)
1062 const struct sbrec_sb_global
*sb_global
= sbrec_sb_global_first(ctx
->idl
);
1063 const struct sbrec_connection
*conn
, *next
;
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
);
1070 /* Delete 'Manager' row refs in 'manager_options' column. */
1071 sbrec_sb_global_set_connections(sb_global
, NULL
, 0);
1075 cmd_del_connection(struct ctl_context
*ctx
)
1077 verify_connections(ctx
);
1078 delete_connections(ctx
);
1082 insert_connections(struct ctl_context
*ctx
, char *targets
[], size_t n
)
1084 const struct sbrec_sb_global
*sb_global
= sbrec_sb_global_first(ctx
->idl
);
1085 struct sbrec_connection
**connections
;
1087 bool read_only
= false;
1089 const char *inactivity_probe
= shash_find_data(&ctx
->options
,
1090 "--inactivity-probe");
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")) {
1098 } else if (!strcmp(targets
[i
], "read-write")) {
1101 } else if (!strncmp(targets
[i
], "role=", 5)) {
1102 role
= targets
[i
] + 5;
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
]);
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
],
1121 /* Store uuids of new connection rows in 'connection' column. */
1122 sbrec_sb_global_set_connections(sb_global
, connections
, conns
);
1127 cmd_set_connection(struct ctl_context
*ctx
)
1129 const size_t n
= ctx
->argc
- 1;
1131 verify_connections(ctx
);
1132 delete_connections(ctx
);
1133 insert_connections(ctx
, &ctx
->argv
[1], n
);
1137 pre_cmd_get_ssl(struct ctl_context
*ctx
)
1139 ovsdb_idl_add_column(ctx
->idl
, &sbrec_sb_global_col_ssl
);
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
);
1148 cmd_get_ssl(struct ctl_context
*ctx
)
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
);
1153 sbrec_sb_global_verify_ssl(sb_global
);
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
);
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");
1169 pre_cmd_del_ssl(struct ctl_context
*ctx
)
1171 ovsdb_idl_add_column(ctx
->idl
, &sbrec_sb_global_col_ssl
);
1175 cmd_del_ssl(struct ctl_context
*ctx
)
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
);
1181 sbrec_sb_global_verify_ssl(sb_global
);
1182 sbrec_ssl_delete(ssl
);
1183 sbrec_sb_global_set_ssl(sb_global
, NULL
);
1188 pre_cmd_set_ssl(struct ctl_context
*ctx
)
1190 ovsdb_idl_add_column(ctx
->idl
, &sbrec_sb_global_col_ssl
);
1194 cmd_set_ssl(struct ctl_context
*ctx
)
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
);
1200 sbrec_sb_global_verify_ssl(sb_global
);
1202 sbrec_ssl_delete(ssl
);
1204 ssl
= sbrec_ssl_insert(ctx
->txn
);
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]);
1210 sbrec_ssl_set_bootstrap_ca_cert(ssl
, bootstrap
);
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]);
1219 sbrec_sb_global_set_ssl(sb_global
, ssl
);
1223 static const struct ctl_table_class tables
[SBREC_N_TABLES
] = {
1224 [SBREC_TABLE_CHASSIS
].row_ids
[0] = {&sbrec_chassis_col_name
, NULL
, NULL
},
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
}},
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
}},
1236 [SBREC_TABLE_MAC_BINDING
].row_ids
[0] =
1237 {&sbrec_mac_binding_col_logical_port
, NULL
, NULL
},
1239 [SBREC_TABLE_ADDRESS_SET
].row_ids
[0]
1240 = {&sbrec_address_set_col_name
, NULL
, NULL
},
1242 [SBREC_TABLE_HA_CHASSIS_GROUP
].row_ids
[0]
1243 = {&sbrec_ha_chassis_group_col_name
, NULL
, NULL
},
1245 [SBREC_TABLE_HA_CHASSIS
].row_ids
[0]
1246 = {&sbrec_ha_chassis_col_chassis
, NULL
, NULL
},
1251 sbctl_context_init_command(struct sbctl_context
*sbctl_ctx
,
1252 struct ctl_command
*command
)
1254 ctl_context_init_command(&sbctl_ctx
->base
, command
);
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
)
1263 ctl_context_init(&sbctl_ctx
->base
, command
, idl
, txn
, symtab
,
1264 sbctl_context_invalidate_cache
);
1265 sbctl_ctx
->cache_valid
= false;
1269 sbctl_context_done_command(struct sbctl_context
*sbctl_ctx
,
1270 struct ctl_command
*command
)
1272 ctl_context_done_command(&sbctl_ctx
->base
, command
);
1276 sbctl_context_done(struct sbctl_context
*sbctl_ctx
,
1277 struct ctl_command
*command
)
1279 ctl_context_done(&sbctl_ctx
->base
, command
);
1283 run_prerequisites(struct ctl_command
*commands
, size_t n_commands
,
1284 struct ovsdb_idl
*idl
)
1286 ovsdb_idl_add_table(idl
, &sbrec_table_sb_global
);
1288 for (struct ctl_command
*c
= commands
; c
< &commands
[n_commands
]; c
++) {
1289 if (c
->syntax
->prerequisites
) {
1290 struct sbctl_context sbctl_ctx
;
1292 ds_init(&c
->output
);
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
);
1300 sbctl_context_done(&sbctl_ctx
, c
);
1302 ovs_assert(!c
->output
.string
);
1303 ovs_assert(!c
->table
);
1309 do_sbctl(const char *args
, struct ctl_command
*commands
, size_t n_commands
,
1310 struct ovsdb_idl
*idl
)
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
;
1319 txn
= the_idl_txn
= ovsdb_idl_txn_create(idl
);
1321 ovsdb_idl_txn_set_dry_run(txn
);
1324 ovsdb_idl_txn_add_comment(txn
, "ovs-sbctl: %s", args
);
1326 const struct sbrec_sb_global
*sb
= sbrec_sb_global_first(idl
);
1328 /* XXX add verification that table is empty */
1329 sbrec_sb_global_insert(txn
);
1332 symtab
= ovsdb_symbol_table_create();
1333 for (c
= commands
; c
< &commands
[n_commands
]; c
++) {
1334 ds_init(&c
->output
);
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
);
1343 if (sbctl_ctx
.base
.error
) {
1344 ctl_fatal("%s", sbctl_ctx
.base
.error
);
1346 sbctl_context_done_command(&sbctl_ctx
, c
);
1348 if (sbctl_ctx
.base
.try_again
) {
1349 sbctl_context_done(&sbctl_ctx
, NULL
);
1353 sbctl_context_done(&sbctl_ctx
, NULL
);
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
);
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
);
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
);
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
);
1384 sbctl_context_done(&sbctl_ctx
, c
);
1390 case TXN_UNCOMMITTED
:
1391 case TXN_INCOMPLETE
:
1395 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
1396 ctl_fatal("transaction aborted");
1406 ctl_fatal("transaction error: %s", ovsdb_idl_txn_get_error(txn
));
1408 case TXN_NOT_LOCKED
:
1409 /* Should not happen--we never call ovsdb_idl_set_lock(). */
1410 ctl_fatal("database not locked");
1416 ovsdb_symbol_table_destroy(symtab
);
1418 for (c
= commands
; c
< &commands
[n_commands
]; c
++) {
1419 struct ds
*ds
= &c
->output
;
1422 table_print(c
->table
, &table_style
);
1423 } else if (oneline
) {
1427 for (j
= 0; j
< ds
->length
; j
++) {
1428 int ch
= ds
->string
[j
];
1431 fputs("\\n", stdout
);
1435 fputs("\\\\", stdout
);
1444 fputs(ds_cstr(ds
), stdout
);
1446 ds_destroy(&c
->output
);
1447 table_destroy(c
->table
);
1450 shash_destroy_free_data(&c
->options
);
1453 ovsdb_idl_txn_destroy(txn
);
1454 ovsdb_idl_destroy(idl
);
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
);
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
);
1474 /* Frees the current transaction and the underlying IDL and then calls
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. */
1481 sbctl_exit(int status
)
1484 ovsdb_idl_txn_abort(the_idl_txn
);
1485 ovsdb_idl_txn_destroy(the_idl_txn
);
1487 ovsdb_idl_destroy(the_idl
);
1491 static const struct ctl_command_syntax sbctl_commands
[] = {
1492 { "init", 0, 0, "", NULL
, sbctl_init
, NULL
, "", RW
},
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
,
1500 /* Port binding commands. */
1501 {"lsp-bind", 2, 2, "PORT CHASSIS", pre_get_info
, cmd_lsp_bind
, NULL
,
1503 {"lsp-unbind", 1, 1, "PORT", pre_get_info
, cmd_lsp_unbind
, NULL
,
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 */
1514 /* IP multicast commands. */
1515 {"ip-multicast-flush", 0, 1, "SWITCH",
1516 pre_get_info
, sbctl_ip_mcast_flush
, NULL
, "", RW
},
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
},
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
},
1528 "PRIVATE-KEY CERTIFICATE CA-CERT [SSL-PROTOS [SSL-CIPHERS]]",
1529 pre_cmd_set_ssl
, cmd_set_ssl
, NULL
, "--bootstrap", RW
},
1531 {NULL
, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
, RO
},
1534 /* Registers sbctl and common db commands. */
1536 sbctl_cmd_init(void)
1538 ctl_init(&sbrec_idl_class
, sbrec_table_classes
, tables
,
1539 cmd_show_tables
, sbctl_exit
);
1540 ctl_register_commands(sbctl_commands
);