2 * Copyright (c) 2009-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.
28 #include "command-line.h"
33 #include "openvswitch/dynamic-string.h"
34 #include "fatal-signal.h"
35 #include "openvswitch/json.h"
37 #include "lib/table.h"
39 #include "ovsdb-data.h"
40 #include "ovsdb-error.h"
41 #include "poll-loop.h"
45 #include "stream-ssl.h"
48 #include "condition.h"
52 #include "openvswitch/vlog.h"
54 VLOG_DEFINE_THIS_MODULE(ovsdb_client
);
57 NEED_NONE
, /* No JSON-RPC connection or database name needed. */
58 NEED_RPC
, /* JSON-RPC connection needed. */
59 NEED_DATABASE
/* JSON-RPC connection and database name needed. */
62 struct ovsdb_client_command
{
64 enum args_needed need
;
67 void (*handler
)(struct jsonrpc
*rpc
, const char *database
,
68 int argc
, char *argv
[]);
71 /* --timestamp: Print a timestamp before each update on "monitor" command? */
72 static bool timestamp
;
74 /* Format for table output. */
75 static struct table_style table_style
= TABLE_STYLE_DEFAULT
;
77 static const struct ovsdb_client_command
*get_all_commands(void);
79 OVS_NO_RETURN
static void usage(void);
80 static void parse_options(int argc
, char *argv
[]);
81 static struct jsonrpc
*open_jsonrpc(const char *server
);
82 static void fetch_dbs(struct jsonrpc
*, struct svec
*dbs
);
85 main(int argc
, char *argv
[])
87 const struct ovsdb_client_command
*command
;
91 ovs_cmdl_proctitle_init(argc
, argv
);
92 set_program_name(argv
[0]);
93 service_start(&argc
, &argv
);
94 parse_options(argc
, argv
);
95 fatal_ignore_sigpipe();
97 daemon_become_new_user(false);
99 ovs_fatal(0, "missing command name; use --help for help");
102 for (command
= get_all_commands(); ; command
++) {
103 if (!command
->name
) {
104 VLOG_FATAL("unknown command '%s'; use --help for help",
106 } else if (!strcmp(command
->name
, argv
[optind
])) {
112 if (command
->need
!= NEED_NONE
) {
113 if (argc
- optind
> command
->min_args
114 && (isalpha((unsigned char) argv
[optind
][0])
115 && strchr(argv
[optind
], ':'))) {
116 rpc
= open_jsonrpc(argv
[optind
++]);
118 char *sock
= xasprintf("unix:%s/db.sock", ovs_rundir());
119 rpc
= open_jsonrpc(sock
);
126 if (command
->need
== NEED_DATABASE
) {
130 fetch_dbs(rpc
, &dbs
);
131 if (argc
- optind
> command
->min_args
132 && svec_contains(&dbs
, argv
[optind
])) {
133 database
= xstrdup(argv
[optind
++]);
134 } else if (dbs
.n
== 1) {
135 database
= xstrdup(dbs
.names
[0]);
136 } else if (svec_contains(&dbs
, "Open_vSwitch")) {
137 database
= xstrdup("Open_vSwitch");
140 ovs_fatal(0, "no default database for `%s' command, please "
141 "specify a database name", command
->name
);
148 if (argc
- optind
< command
->min_args
||
149 argc
- optind
> command
->max_args
) {
151 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
155 command
->handler(rpc
, database
, argc
- optind
, argv
+ optind
);
160 if (ferror(stdout
)) {
161 VLOG_FATAL("write to stdout failed");
163 if (ferror(stderr
)) {
164 VLOG_FATAL("write to stderr failed");
171 parse_options(int argc
, char *argv
[])
174 OPT_BOOTSTRAP_CA_CERT
= UCHAR_MAX
+ 1,
181 static const struct option long_options
[] = {
182 {"help", no_argument
, NULL
, 'h'},
183 {"version", no_argument
, NULL
, 'V'},
184 {"timestamp", no_argument
, NULL
, OPT_TIMESTAMP
},
188 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
189 STREAM_SSL_LONG_OPTIONS
,
194 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
196 table_style
.format
= TF_TABLE
;
201 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
211 ovs_print_version(0, 0);
215 DAEMON_OPTION_HANDLERS
216 TABLE_OPTION_HANDLERS(&table_style
)
217 STREAM_SSL_OPTION_HANDLERS
219 case OPT_BOOTSTRAP_CA_CERT
:
220 stream_ssl_set_ca_cert_file(optarg
, true);
231 /* getopt_long() already set the value for us. */
244 printf("%s: Open vSwitch database JSON-RPC client\n"
245 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
246 "\nValid commands are:\n"
247 "\n list-dbs [SERVER]\n"
248 " list databases available on SERVER\n"
249 "\n get-schema [SERVER] [DATABASE]\n"
250 " retrieve schema for DATABASE from SERVER\n"
251 "\n get-schema-version [SERVER] [DATABASE]\n"
252 " retrieve schema for DATABASE from SERVER and report only its\n"
253 " version number on stdout\n"
254 "\n list-tables [SERVER] [DATABASE]\n"
255 " list tables for DATABASE on SERVER\n"
256 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
257 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
258 "\n transact [SERVER] TRANSACTION\n"
259 " run TRANSACTION (a JSON array of operations) on SERVER\n"
260 " and print the results as JSON on stdout\n"
261 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
262 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
263 " COLUMNs may include !initial, !insert, !delete, !modify\n"
264 " to avoid seeing the specified kinds of changes.\n"
265 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
266 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
267 " DATABASE on SERVER.\n"
268 " COLUMNs may include !initial, !insert, !delete, !modify\n"
269 " to avoid seeing the specified kinds of changes.\n"
270 "\n monitor [SERVER] [DATABASE] ALL\n"
271 " monitor all changes to all columns in all tables\n"
272 " in DATBASE on SERVER.\n"
273 "\n dump [SERVER] [DATABASE]\n"
274 " dump contents of DATABASE on SERVER to stdout\n"
275 "\n lock [SERVER] LOCK\n"
276 " create or wait for LOCK in SERVER\n"
277 "\n steal [SERVER] LOCK\n"
278 " steal LOCK from SERVER\n"
279 "\n unlock [SERVER] LOCK\n"
280 " unlock LOCK from SERVER\n"
281 "\nThe default SERVER is unix:%s/db.sock.\n"
282 "The default DATABASE is Open_vSwitch.\n",
283 program_name
, program_name
, ovs_rundir());
284 stream_usage("SERVER", true, true, true);
286 printf(" --timestamp timestamp \"monitor\" output");
289 printf("\nOther options:\n"
290 " -h, --help display this help message\n"
291 " -V, --version display version information\n");
296 check_txn(int error
, struct jsonrpc_msg
**reply_
)
298 struct jsonrpc_msg
*reply
= *reply_
;
301 ovs_fatal(error
, "transaction failed");
305 ovs_fatal(error
, "transaction returned error: %s",
306 json_to_string(reply
->error
, table_style
.json_flags
));
311 parse_json(const char *s
)
313 struct json
*json
= json_from_string(s
);
314 if (json
->type
== JSON_STRING
) {
315 ovs_fatal(0, "\"%s\": %s", s
, json
->u
.string
);
320 static struct jsonrpc
*
321 open_jsonrpc(const char *server
)
323 struct stream
*stream
;
326 error
= stream_open_block(jsonrpc_stream_open(server
, &stream
,
327 DSCP_DEFAULT
), &stream
);
328 if (error
== EAFNOSUPPORT
) {
329 struct pstream
*pstream
;
331 error
= jsonrpc_pstream_open(server
, &pstream
, DSCP_DEFAULT
);
333 ovs_fatal(error
, "failed to connect or listen to \"%s\"", server
);
336 VLOG_INFO("%s: waiting for connection...", server
);
337 error
= pstream_accept_block(pstream
, &stream
);
339 ovs_fatal(error
, "failed to accept connection on \"%s\"", server
);
342 pstream_close(pstream
);
344 ovs_fatal(error
, "failed to connect to \"%s\"", server
);
347 return jsonrpc_open(stream
);
351 print_json(struct json
*json
)
353 char *string
= json_to_string(json
, table_style
.json_flags
);
354 fputs(string
, stdout
);
359 print_and_free_json(struct json
*json
)
366 check_ovsdb_error(struct ovsdb_error
*error
)
369 ovs_fatal(0, "%s", ovsdb_error_to_string(error
));
373 static struct ovsdb_schema
*
374 fetch_schema(struct jsonrpc
*rpc
, const char *database
)
376 struct jsonrpc_msg
*request
, *reply
;
377 struct ovsdb_schema
*schema
;
379 request
= jsonrpc_create_request("get_schema",
381 json_string_create(database
)),
383 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
384 check_ovsdb_error(ovsdb_schema_from_json(reply
->result
, &schema
));
385 jsonrpc_msg_destroy(reply
);
391 fetch_dbs(struct jsonrpc
*rpc
, struct svec
*dbs
)
393 struct jsonrpc_msg
*request
, *reply
;
396 request
= jsonrpc_create_request("list_dbs", json_array_create_empty(),
399 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
400 if (reply
->result
->type
!= JSON_ARRAY
) {
401 ovs_fatal(0, "list_dbs response is not array");
404 for (i
= 0; i
< reply
->result
->u
.array
.n
; i
++) {
405 const struct json
*name
= reply
->result
->u
.array
.elems
[i
];
407 if (name
->type
!= JSON_STRING
) {
408 ovs_fatal(0, "list_dbs response %"PRIuSIZE
" is not string", i
);
410 svec_add(dbs
, name
->u
.string
);
412 jsonrpc_msg_destroy(reply
);
417 do_list_dbs(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
418 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
425 fetch_dbs(rpc
, &dbs
);
426 SVEC_FOR_EACH (i
, db_name
, &dbs
) {
433 do_get_schema(struct jsonrpc
*rpc
, const char *database
,
434 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
436 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
437 print_and_free_json(ovsdb_schema_to_json(schema
));
438 ovsdb_schema_destroy(schema
);
442 do_get_schema_version(struct jsonrpc
*rpc
, const char *database
,
443 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
445 struct ovsdb_schema
*schema
= fetch_schema(rpc
, database
);
446 puts(schema
->version
);
447 ovsdb_schema_destroy(schema
);
451 do_list_tables(struct jsonrpc
*rpc
, const char *database
,
452 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
454 struct ovsdb_schema
*schema
;
455 struct shash_node
*node
;
458 schema
= fetch_schema(rpc
, database
);
460 table_add_column(&t
, "Table");
461 SHASH_FOR_EACH (node
, &schema
->tables
) {
462 struct ovsdb_table_schema
*ts
= node
->data
;
465 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
467 ovsdb_schema_destroy(schema
);
468 table_print(&t
, &table_style
);
473 do_list_columns(struct jsonrpc
*rpc
, const char *database
,
474 int argc OVS_UNUSED
, char *argv
[])
476 const char *table_name
= argv
[0];
477 struct ovsdb_schema
*schema
;
478 struct shash_node
*table_node
;
481 schema
= fetch_schema(rpc
, database
);
484 table_add_column(&t
, "Table");
486 table_add_column(&t
, "Column");
487 table_add_column(&t
, "Type");
488 SHASH_FOR_EACH (table_node
, &schema
->tables
) {
489 struct ovsdb_table_schema
*ts
= table_node
->data
;
491 if (!table_name
|| !strcmp(table_name
, ts
->name
)) {
492 struct shash_node
*column_node
;
494 SHASH_FOR_EACH (column_node
, &ts
->columns
) {
495 const struct ovsdb_column
*column
= column_node
->data
;
499 table_add_cell(&t
)->text
= xstrdup(ts
->name
);
501 table_add_cell(&t
)->text
= xstrdup(column
->name
);
502 table_add_cell(&t
)->json
= ovsdb_type_to_json(&column
->type
);
506 ovsdb_schema_destroy(schema
);
507 table_print(&t
, &table_style
);
512 do_transact(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
513 int argc OVS_UNUSED
, char *argv
[])
515 struct jsonrpc_msg
*request
, *reply
;
516 struct json
*transaction
;
518 transaction
= parse_json(argv
[0]);
520 request
= jsonrpc_create_request("transact", transaction
, NULL
);
521 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
522 print_json(reply
->result
);
524 jsonrpc_msg_destroy(reply
);
527 /* "monitor" command. */
529 struct monitored_table
{
530 struct ovsdb_table_schema
*table
;
531 struct ovsdb_column_set columns
;
535 monitor_print_row(struct json
*row
, const char *type
, const char *uuid
,
536 const struct ovsdb_column_set
*columns
, struct table
*t
)
541 ovs_error(0, "missing %s row", type
);
543 } else if (row
->type
!= JSON_OBJECT
) {
544 ovs_error(0, "<row> is not object");
549 table_add_cell(t
)->text
= xstrdup(uuid
);
550 table_add_cell(t
)->text
= xstrdup(type
);
551 for (i
= 0; i
< columns
->n_columns
; i
++) {
552 const struct ovsdb_column
*column
= columns
->columns
[i
];
553 struct json
*value
= shash_find_data(json_object(row
), column
->name
);
554 struct cell
*cell
= table_add_cell(t
);
556 cell
->json
= json_clone(value
);
557 cell
->type
= &column
->type
;
563 monitor_print_table(struct json
*table_update
,
564 const struct monitored_table
*mt
, char *caption
,
567 const struct ovsdb_table_schema
*table
= mt
->table
;
568 const struct ovsdb_column_set
*columns
= &mt
->columns
;
569 struct shash_node
*node
;
573 if (table_update
->type
!= JSON_OBJECT
) {
574 ovs_error(0, "<table-update> for table %s is not object", table
->name
);
579 table_set_timestamp(&t
, timestamp
);
580 table_set_caption(&t
, caption
);
582 table_add_column(&t
, "row");
583 table_add_column(&t
, "action");
584 for (i
= 0; i
< columns
->n_columns
; i
++) {
585 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
587 SHASH_FOR_EACH (node
, json_object(table_update
)) {
588 struct json
*row_update
= node
->data
;
589 struct json
*old
, *new;
591 if (row_update
->type
!= JSON_OBJECT
) {
592 ovs_error(0, "<row-update> is not object");
595 old
= shash_find_data(json_object(row_update
), "old");
596 new = shash_find_data(json_object(row_update
), "new");
598 monitor_print_row(new, "initial", node
->name
, columns
, &t
);
600 monitor_print_row(new, "insert", node
->name
, columns
, &t
);
602 monitor_print_row(old
, "delete", node
->name
, columns
, &t
);
604 monitor_print_row(old
, "old", node
->name
, columns
, &t
);
605 monitor_print_row(new, "new", "", columns
, &t
);
608 table_print(&t
, &table_style
);
613 monitor_print(struct json
*table_updates
,
614 const struct monitored_table
*mts
, size_t n_mts
,
619 if (table_updates
->type
!= JSON_OBJECT
) {
620 ovs_error(0, "<table-updates> is not object");
624 for (i
= 0; i
< n_mts
; i
++) {
625 const struct monitored_table
*mt
= &mts
[i
];
626 struct json
*table_update
= shash_find_data(json_object(table_updates
),
629 monitor_print_table(table_update
, mt
,
630 n_mts
> 1 ? xstrdup(mt
->table
->name
) : NULL
,
637 monitor2_print_row(struct json
*row
, const char *type
, const char *uuid
,
638 const struct ovsdb_column_set
*columns
, struct table
*t
)
640 if (!strcmp(type
, "delete")) {
641 if (row
->type
!= JSON_NULL
) {
642 ovs_error(0, "delete method does not expect <row>");
647 table_add_cell(t
)->text
= xstrdup(uuid
);
648 table_add_cell(t
)->text
= xstrdup(type
);
650 if (!row
|| row
->type
!= JSON_OBJECT
) {
651 ovs_error(0, "<row> is not object");
654 monitor_print_row(row
, type
, uuid
, columns
, t
);
659 monitor2_print_table(struct json
*table_update2
,
660 const struct monitored_table
*mt
, char *caption
)
662 const struct ovsdb_table_schema
*table
= mt
->table
;
663 const struct ovsdb_column_set
*columns
= &mt
->columns
;
664 struct shash_node
*node
;
667 if (table_update2
->type
!= JSON_OBJECT
) {
668 ovs_error(0, "<table-update> for table %s is not object", table
->name
);
673 table_set_timestamp(&t
, timestamp
);
674 table_set_caption(&t
, caption
);
676 table_add_column(&t
, "row");
677 table_add_column(&t
, "action");
678 for (size_t i
= 0; i
< columns
->n_columns
; i
++) {
679 table_add_column(&t
, "%s", columns
->columns
[i
]->name
);
681 SHASH_FOR_EACH (node
, json_object(table_update2
)) {
682 struct json
*row_update2
= node
->data
;
683 const char *operation
;
685 const char *ops
[] = {"delete", "initial", "modify", "insert"};
687 if (row_update2
->type
!= JSON_OBJECT
) {
688 ovs_error(0, "<row-update2> is not object");
692 /* row_update2 contains one of objects indexed by ops[] */
693 for (int i
= 0; i
< ARRAY_SIZE(ops
); i
++) {
695 row
= shash_find_data(json_object(row_update2
), operation
);
698 monitor2_print_row(row
, operation
, node
->name
, columns
, &t
);
703 table_print(&t
, &table_style
);
708 monitor2_print(struct json
*table_updates2
,
709 const struct monitored_table
*mts
, size_t n_mts
)
713 if (table_updates2
->type
!= JSON_OBJECT
) {
714 ovs_error(0, "<table-updates2> is not object");
718 for (i
= 0; i
< n_mts
; i
++) {
719 const struct monitored_table
*mt
= &mts
[i
];
720 struct json
*table_update
= shash_find_data(
721 json_object(table_updates2
),
724 monitor2_print_table(table_update
, mt
,
725 n_mts
> 1 ? xstrdup(mt
->table
->name
) : NULL
);
731 add_column(const char *server
, const struct ovsdb_column
*column
,
732 struct ovsdb_column_set
*columns
, struct json
*columns_json
)
734 if (ovsdb_column_set_contains(columns
, column
->index
)) {
735 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
736 server
, column
->name
);
738 ovsdb_column_set_add(columns
, column
);
739 json_array_add(columns_json
, json_string_create(column
->name
));
743 parse_monitor_columns(char *arg
, const char *server
, const char *database
,
744 const struct ovsdb_table_schema
*table
,
745 struct ovsdb_column_set
*columns
)
747 bool initial
, insert
, delete, modify
;
748 struct json
*mr
, *columns_json
;
749 char *save_ptr
= NULL
;
752 mr
= json_object_create();
753 columns_json
= json_array_create_empty();
754 json_object_put(mr
, "columns", columns_json
);
756 initial
= insert
= delete = modify
= true;
757 for (token
= strtok_r(arg
, ",", &save_ptr
); token
!= NULL
;
758 token
= strtok_r(NULL
, ",", &save_ptr
)) {
759 if (!strcmp(token
, "!initial")) {
761 } else if (!strcmp(token
, "!insert")) {
763 } else if (!strcmp(token
, "!delete")) {
765 } else if (!strcmp(token
, "!modify")) {
768 const struct ovsdb_column
*column
;
770 column
= ovsdb_table_schema_get_column(table
, token
);
772 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
773 "column named \"%s\"",
774 server
, table
->name
, database
, token
);
776 add_column(server
, column
, columns
, columns_json
);
780 if (columns_json
->u
.array
.n
== 0) {
781 const struct shash_node
**nodes
;
784 n
= shash_count(&table
->columns
);
785 nodes
= shash_sort(&table
->columns
);
786 for (i
= 0; i
< n
; i
++) {
787 const struct ovsdb_column
*column
= nodes
[i
]->data
;
788 if (column
->index
!= OVSDB_COL_UUID
789 && column
->index
!= OVSDB_COL_VERSION
) {
790 add_column(server
, column
, columns
, columns_json
);
795 add_column(server
, ovsdb_table_schema_get_column(table
, "_version"),
796 columns
, columns_json
);
799 if (!initial
|| !insert
|| !delete || !modify
) {
800 struct json
*select
= json_object_create();
801 json_object_put(select
, "initial", json_boolean_create(initial
));
802 json_object_put(select
, "insert", json_boolean_create(insert
));
803 json_object_put(select
, "delete", json_boolean_create(delete));
804 json_object_put(select
, "modify", json_boolean_create(modify
));
805 json_object_put(mr
, "select", select
);
812 ovsdb_client_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
813 const char *argv
[] OVS_UNUSED
, void *exiting_
)
815 bool *exiting
= exiting_
;
817 unixctl_command_reply(conn
, NULL
);
821 ovsdb_client_block(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
822 const char *argv
[] OVS_UNUSED
, void *blocked_
)
824 bool *blocked
= blocked_
;
828 unixctl_command_reply(conn
, NULL
);
830 unixctl_command_reply(conn
, "already blocking");
835 ovsdb_client_unblock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
836 const char *argv
[] OVS_UNUSED
, void *blocked_
)
838 bool *blocked
= blocked_
;
842 unixctl_command_reply(conn
, NULL
);
844 unixctl_command_reply(conn
, "already unblocked");
849 ovsdb_client_cond_change(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
850 const char *argv
[], void *rpc_
)
852 struct jsonrpc
*rpc
= rpc_
;
853 struct json
*monitor_cond_update_requests
= json_object_create();
854 struct json
*monitor_cond_update_request
= json_object_create();
856 struct jsonrpc_msg
*request
;
858 json_object_put(monitor_cond_update_request
, "where",
859 json_from_string(argv
[2]));
860 json_object_put(monitor_cond_update_requests
,
862 json_array_create_1(monitor_cond_update_request
));
864 params
= json_array_create_3(json_null_create(),json_null_create(),
865 monitor_cond_update_requests
);
867 request
= jsonrpc_create_request("monitor_cond_change", params
, NULL
);
868 jsonrpc_send(rpc
, request
);
870 VLOG_DBG("cond change %s %s", argv
[1], argv
[2]);
871 unixctl_command_reply(conn
, "condiiton changed");
875 add_monitored_table(int argc
, char *argv
[],
876 const char *server
, const char *database
,
877 struct json
*condition
,
878 struct ovsdb_table_schema
*table
,
879 struct json
*monitor_requests
,
880 struct monitored_table
**mts
,
881 size_t *n_mts
, size_t *allocated_mts
)
883 struct json
*monitor_request_array
, *mr
;
884 struct monitored_table
*mt
;
886 if (*n_mts
>= *allocated_mts
) {
887 *mts
= x2nrealloc(*mts
, allocated_mts
, sizeof **mts
);
889 mt
= &(*mts
)[(*n_mts
)++];
891 ovsdb_column_set_init(&mt
->columns
);
893 monitor_request_array
= json_array_create_empty();
897 for (i
= 1; i
< argc
; i
++) {
898 mr
= parse_monitor_columns(argv
[i
], server
, database
, table
,
900 if (i
== 1 && condition
) {
901 json_object_put(mr
, "where", condition
);
903 json_array_add(monitor_request_array
, mr
);
906 /* Allocate a writable empty string since parse_monitor_columns()
907 * is going to strtok() it and that's risky with literal "". */
910 mr
= parse_monitor_columns(empty
, server
, database
,
911 table
, &mt
->columns
);
913 json_object_put(mr
, "where", condition
);
915 json_array_add(monitor_request_array
, mr
);
918 json_object_put(monitor_requests
, table
->name
, monitor_request_array
);
922 destroy_monitored_table(struct monitored_table
*mts
, size_t n
)
926 for (i
= 0; i
< n
; i
++) {
927 struct monitored_table
*mt
= &mts
[i
];
928 ovsdb_column_set_destroy(&mt
->columns
);
935 do_monitor__(struct jsonrpc
*rpc
, const char *database
,
936 enum ovsdb_monitor_version version
,
937 int argc
, char *argv
[], struct json
*condition
)
939 const char *server
= jsonrpc_get_name(rpc
);
940 const char *table_name
= argv
[0];
941 struct unixctl_server
*unixctl
;
942 struct ovsdb_schema
*schema
;
943 struct jsonrpc_msg
*request
;
944 struct json
*monitor
, *monitor_requests
, *request_id
;
945 bool exiting
= false;
946 bool blocked
= false;
948 struct monitored_table
*mts
;
949 size_t n_mts
, allocated_mts
;
951 ovs_assert(version
< OVSDB_MONITOR_VERSION_MAX
);
953 daemon_save_fd(STDOUT_FILENO
);
954 daemonize_start(false);
958 error
= unixctl_server_create(NULL
, &unixctl
);
960 ovs_fatal(error
, "failed to create unixctl server");
963 unixctl_command_register("exit", "", 0, 0,
964 ovsdb_client_exit
, &exiting
);
965 unixctl_command_register("ovsdb-client/block", "", 0, 0,
966 ovsdb_client_block
, &blocked
);
967 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
968 ovsdb_client_unblock
, &blocked
);
969 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
970 ovsdb_client_cond_change
, rpc
);
975 schema
= fetch_schema(rpc
, database
);
977 monitor_requests
= json_object_create();
980 n_mts
= allocated_mts
= 0;
981 if (strcmp(table_name
, "ALL")) {
982 struct ovsdb_table_schema
*table
;
984 table
= shash_find_data(&schema
->tables
, table_name
);
986 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
987 server
, database
, table_name
);
990 add_monitored_table(argc
, argv
, server
, database
, condition
, table
,
991 monitor_requests
, &mts
, &n_mts
, &allocated_mts
);
993 size_t n
= shash_count(&schema
->tables
);
994 const struct shash_node
**nodes
= shash_sort(&schema
->tables
);
998 ovs_fatal(0, "ALL tables are not allowed with condition");
1001 for (i
= 0; i
< n
; i
++) {
1002 struct ovsdb_table_schema
*table
= nodes
[i
]->data
;
1004 add_monitored_table(argc
, argv
, server
, database
, NULL
, table
,
1006 &mts
, &n_mts
, &allocated_mts
);
1011 monitor
= json_array_create_3(json_string_create(database
),
1012 json_null_create(), monitor_requests
);
1013 const char *method
= version
== OVSDB_MONITOR_V2
? "monitor_cond"
1016 request
= jsonrpc_create_request(method
, monitor
, NULL
);
1017 request_id
= json_clone(request
->id
);
1018 jsonrpc_send(rpc
, request
);
1021 unixctl_server_run(unixctl
);
1023 struct jsonrpc_msg
*msg
;
1026 error
= jsonrpc_recv(rpc
, &msg
);
1027 if (error
== EAGAIN
) {
1030 ovs_fatal(error
, "%s: receive failed", server
);
1033 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
1034 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
1036 } else if (msg
->type
== JSONRPC_REPLY
1037 && json_equal(msg
->id
, request_id
)) {
1039 case OVSDB_MONITOR_V1
:
1040 monitor_print(msg
->result
, mts
, n_mts
, true);
1042 case OVSDB_MONITOR_V2
:
1043 monitor2_print(msg
->result
, mts
, n_mts
);
1045 case OVSDB_MONITOR_VERSION_MAX
:
1050 daemonize_complete();
1051 } else if (msg
->type
== JSONRPC_NOTIFY
1052 && !strcmp(msg
->method
, "update")) {
1053 struct json
*params
= msg
->params
;
1054 if (params
->type
== JSON_ARRAY
1055 && params
->u
.array
.n
== 2
1056 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
1057 monitor_print(params
->u
.array
.elems
[1], mts
, n_mts
, false);
1060 } else if (msg
->type
== JSONRPC_NOTIFY
1061 && version
== OVSDB_MONITOR_V2
1062 && !strcmp(msg
->method
, "update2")) {
1063 struct json
*params
= msg
->params
;
1064 if (params
->type
== JSON_ARRAY
1065 && params
->u
.array
.n
== 2
1066 && params
->u
.array
.elems
[0]->type
== JSON_NULL
) {
1067 monitor2_print(params
->u
.array
.elems
[1], mts
, n_mts
);
1071 jsonrpc_msg_destroy(msg
);
1081 jsonrpc_recv_wait(rpc
);
1083 unixctl_server_wait(unixctl
);
1087 json_destroy(request_id
);
1088 unixctl_server_destroy(unixctl
);
1089 ovsdb_schema_destroy(schema
);
1090 destroy_monitored_table(mts
, n_mts
);
1094 do_monitor(struct jsonrpc
*rpc
, const char *database
,
1095 int argc
, char *argv
[])
1097 do_monitor__(rpc
, database
, OVSDB_MONITOR_V1
, argc
, argv
, NULL
);
1101 do_monitor_cond(struct jsonrpc
*rpc
, const char *database
,
1102 int argc
, char *argv
[])
1104 struct ovsdb_condition cnd
;
1105 struct json
*condition
= NULL
;
1106 struct ovsdb_schema
*schema
;
1107 struct ovsdb_table_schema
*table
;
1108 const char *table_name
= argv
[1];
1110 ovs_assert(argc
> 1);
1111 schema
= fetch_schema(rpc
, database
);
1112 table
= shash_find_data(&schema
->tables
, table_name
);
1114 ovs_fatal(0, "%s does not have a table named \"%s\"",
1115 database
, table_name
);
1117 condition
= parse_json(argv
[0]);
1118 check_ovsdb_error(ovsdb_condition_from_json(table
, condition
,
1120 ovsdb_condition_destroy(&cnd
);
1121 do_monitor__(rpc
, database
, OVSDB_MONITOR_V2
, --argc
, ++argv
, condition
);
1122 ovsdb_schema_destroy(schema
);
1125 struct dump_table_aux
{
1126 struct ovsdb_datum
**data
;
1127 const struct ovsdb_column
**columns
;
1132 compare_data(size_t a_y
, size_t b_y
, size_t x
,
1133 const struct dump_table_aux
*aux
)
1135 return ovsdb_datum_compare_3way(&aux
->data
[a_y
][x
],
1137 &aux
->columns
[x
]->type
);
1141 compare_rows(size_t a_y
, size_t b_y
, void *aux_
)
1143 struct dump_table_aux
*aux
= aux_
;
1146 /* Skip UUID columns on the first pass, since their values tend to be
1147 * random and make our results less reproducible. */
1148 for (x
= 0; x
< aux
->n_columns
; x
++) {
1149 if (aux
->columns
[x
]->type
.key
.type
!= OVSDB_TYPE_UUID
) {
1150 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1157 /* Use UUID columns as tie-breakers. */
1158 for (x
= 0; x
< aux
->n_columns
; x
++) {
1159 if (aux
->columns
[x
]->type
.key
.type
== OVSDB_TYPE_UUID
) {
1160 int cmp
= compare_data(a_y
, b_y
, x
, aux
);
1171 swap_rows(size_t a_y
, size_t b_y
, void *aux_
)
1173 struct dump_table_aux
*aux
= aux_
;
1174 struct ovsdb_datum
*tmp
= aux
->data
[a_y
];
1175 aux
->data
[a_y
] = aux
->data
[b_y
];
1176 aux
->data
[b_y
] = tmp
;
1180 compare_columns(const void *a_
, const void *b_
)
1182 const struct ovsdb_column
*const *ap
= a_
;
1183 const struct ovsdb_column
*const *bp
= b_
;
1184 const struct ovsdb_column
*a
= *ap
;
1185 const struct ovsdb_column
*b
= *bp
;
1187 return strcmp(a
->name
, b
->name
);
1191 dump_table(const char *table_name
, const struct shash
*cols
,
1192 struct json_array
*rows
)
1194 const struct ovsdb_column
**columns
;
1197 struct ovsdb_datum
**data
;
1199 struct dump_table_aux aux
;
1200 struct shash_node
*node
;
1204 /* Sort columns by name, for reproducibility. */
1205 columns
= xmalloc(shash_count(cols
) * sizeof *columns
);
1207 SHASH_FOR_EACH (node
, cols
) {
1208 struct ovsdb_column
*column
= node
->data
;
1209 if (strcmp(column
->name
, "_version")) {
1210 columns
[n_columns
++] = column
;
1213 qsort(columns
, n_columns
, sizeof *columns
, compare_columns
);
1215 /* Extract data from table. */
1216 data
= xmalloc(rows
->n
* sizeof *data
);
1217 for (y
= 0; y
< rows
->n
; y
++) {
1220 if (rows
->elems
[y
]->type
!= JSON_OBJECT
) {
1221 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response is not a JSON object: "
1222 "%s", y
, table_name
, json_to_string(rows
->elems
[y
], 0));
1224 row
= json_object(rows
->elems
[y
]);
1226 data
[y
] = xmalloc(n_columns
* sizeof **data
);
1227 for (x
= 0; x
< n_columns
; x
++) {
1228 const struct json
*json
= shash_find_data(row
, columns
[x
]->name
);
1230 ovs_fatal(0, "row %"PRIuSIZE
" in table %s response lacks %s column",
1231 y
, table_name
, columns
[x
]->name
);
1234 check_ovsdb_error(ovsdb_datum_from_json(&data
[y
][x
],
1240 /* Sort rows by column values, for reproducibility. */
1242 aux
.columns
= columns
;
1243 aux
.n_columns
= n_columns
;
1244 sort(rows
->n
, compare_rows
, swap_rows
, &aux
);
1246 /* Add column headings. */
1248 table_set_caption(&t
, xasprintf("%s table", table_name
));
1249 for (x
= 0; x
< n_columns
; x
++) {
1250 table_add_column(&t
, "%s", columns
[x
]->name
);
1254 for (y
= 0; y
< rows
->n
; y
++) {
1256 for (x
= 0; x
< n_columns
; x
++) {
1257 struct cell
*cell
= table_add_cell(&t
);
1258 cell
->json
= ovsdb_datum_to_json(&data
[y
][x
], &columns
[x
]->type
);
1259 cell
->type
= &columns
[x
]->type
;
1260 ovsdb_datum_destroy(&data
[y
][x
], &columns
[x
]->type
);
1264 table_print(&t
, &table_style
);
1272 do_dump(struct jsonrpc
*rpc
, const char *database
,
1273 int argc
, char *argv
[])
1275 struct jsonrpc_msg
*request
, *reply
;
1276 struct ovsdb_schema
*schema
;
1277 struct json
*transaction
;
1279 const struct shash_node
*node
, **tables
;
1281 struct ovsdb_table_schema
*tschema
;
1282 const struct shash
*columns
;
1283 struct shash custom_columns
;
1287 shash_init(&custom_columns
);
1288 schema
= fetch_schema(rpc
, database
);
1290 node
= shash_find(&schema
->tables
, argv
[0]);
1292 ovs_fatal(0, "No table \"%s\" found.", argv
[0]);
1294 tables
= xmemdup(&node
, sizeof node
);
1296 tschema
= tables
[0]->data
;
1297 for (i
= 1; i
< argc
; i
++) {
1298 node
= shash_find(&tschema
->columns
, argv
[i
]);
1300 ovs_fatal(0, "Table \"%s\" has no column %s.", argv
[0], argv
[1]);
1302 shash_add(&custom_columns
, argv
[1], node
->data
);
1305 tables
= shash_sort(&schema
->tables
);
1306 n_tables
= shash_count(&schema
->tables
);
1309 /* Construct transaction to retrieve entire database. */
1310 transaction
= json_array_create_1(json_string_create(database
));
1311 for (i
= 0; i
< n_tables
; i
++) {
1312 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1313 struct json
*op
, *jcolumns
;
1316 columns
= &custom_columns
;
1318 columns
= &ts
->columns
;
1320 jcolumns
= json_array_create_empty();
1321 SHASH_FOR_EACH (node
, columns
) {
1322 const struct ovsdb_column
*column
= node
->data
;
1324 if (strcmp(column
->name
, "_version")) {
1325 json_array_add(jcolumns
, json_string_create(column
->name
));
1329 op
= json_object_create();
1330 json_object_put_string(op
, "op", "select");
1331 json_object_put_string(op
, "table", tables
[i
]->name
);
1332 json_object_put(op
, "where", json_array_create_empty());
1333 json_object_put(op
, "columns", jcolumns
);
1334 json_array_add(transaction
, op
);
1337 /* Send request, get reply. */
1338 request
= jsonrpc_create_request("transact", transaction
, NULL
);
1339 check_txn(jsonrpc_transact_block(rpc
, request
, &reply
), &reply
);
1341 /* Print database contents. */
1342 if (reply
->result
->type
!= JSON_ARRAY
1343 || reply
->result
->u
.array
.n
!= n_tables
) {
1344 ovs_fatal(0, "reply is not array of %"PRIuSIZE
" elements: %s",
1345 n_tables
, json_to_string(reply
->result
, 0));
1347 for (i
= 0; i
< n_tables
; i
++) {
1348 const struct ovsdb_table_schema
*ts
= tables
[i
]->data
;
1349 const struct json
*op_result
= reply
->result
->u
.array
.elems
[i
];
1352 if (op_result
->type
!= JSON_OBJECT
1353 || !(rows
= shash_find_data(json_object(op_result
), "rows"))
1354 || rows
->type
!= JSON_ARRAY
) {
1355 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1357 ts
->name
, json_to_string(op_result
, 0));
1361 dump_table(tables
[i
]->name
, &custom_columns
, &rows
->u
.array
);
1363 dump_table(tables
[i
]->name
, &ts
->columns
, &rows
->u
.array
);
1367 jsonrpc_msg_destroy(reply
);
1368 shash_destroy(&custom_columns
);
1370 ovsdb_schema_destroy(schema
);
1374 do_help(struct jsonrpc
*rpc OVS_UNUSED
, const char *database OVS_UNUSED
,
1375 int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1381 /* "lock" command. */
1383 struct ovsdb_client_lock_req
{
1389 lock_req_init(struct ovsdb_client_lock_req
*lock_req
,
1390 const char *method
, const char *lock_name
)
1392 if (lock_req
->method
|| lock_req
->lock
) {
1395 lock_req
->method
= method
;
1396 lock_req
->lock
= xstrdup(lock_name
);
1400 lock_req_is_set(struct ovsdb_client_lock_req
*lock_req
)
1402 return lock_req
->method
;
1406 lock_req_destroy(struct ovsdb_client_lock_req
*lock_req
)
1408 free(lock_req
->lock
);
1409 lock_req
->method
= NULL
;
1410 lock_req
->lock
= NULL
;
1413 /* Create a lock class request. Caller is responsible for free
1414 * the 'request' message. */
1415 static struct jsonrpc_msg
*
1416 create_lock_request(struct ovsdb_client_lock_req
*lock_req
)
1418 struct json
*locks
, *lock
;
1420 locks
= json_array_create_empty();
1421 lock
= json_string_create(lock_req
->lock
);
1422 json_array_add(locks
, lock
);
1424 return jsonrpc_create_request(lock_req
->method
, locks
, NULL
);
1428 ovsdb_client_lock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1429 const char *argv
[], void *lock_req_
)
1431 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1432 lock_req_init(lock_req
, "lock", argv
[1]);
1433 unixctl_command_reply(conn
, NULL
);
1437 ovsdb_client_unlock(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1438 const char *argv
[], void *lock_req_
)
1440 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1441 lock_req_init(lock_req
, "unlock", argv
[1]);
1442 unixctl_command_reply(conn
, NULL
);
1446 ovsdb_client_steal(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1447 const char *argv
[], void *lock_req_
)
1449 struct ovsdb_client_lock_req
*lock_req
= lock_req_
;
1450 lock_req_init(lock_req
, "steal", argv
[1]);
1451 unixctl_command_reply(conn
, NULL
);
1455 do_lock(struct jsonrpc
*rpc
, const char *method
, const char *lock
)
1457 struct ovsdb_client_lock_req lock_req
= {NULL
, NULL
};
1458 struct unixctl_server
*unixctl
;
1459 struct jsonrpc_msg
*request
;
1460 struct json
*request_id
= NULL
;
1461 bool exiting
= false;
1462 bool enable_lock_request
= true; /* Don't send another request before
1463 getting a reply of the previous
1465 daemon_save_fd(STDOUT_FILENO
);
1466 daemonize_start(false);
1467 lock_req_init(&lock_req
, method
, lock
);
1472 error
= unixctl_server_create(NULL
, &unixctl
);
1474 ovs_fatal(error
, "failed to create unixctl server");
1477 unixctl_command_register("unlock", "LOCK", 1, 1,
1478 ovsdb_client_unlock
, &lock_req
);
1479 unixctl_command_register("steal", "LOCK", 1, 1,
1480 ovsdb_client_steal
, &lock_req
);
1481 unixctl_command_register("lock", "LOCK", 1, 1,
1482 ovsdb_client_lock
, &lock_req
);
1483 unixctl_command_register("exit", "", 0, 0,
1484 ovsdb_client_exit
, &exiting
);
1490 struct jsonrpc_msg
*msg
;
1493 unixctl_server_run(unixctl
);
1494 if (enable_lock_request
&& lock_req_is_set(&lock_req
)) {
1495 request
= create_lock_request(&lock_req
);
1496 request_id
= json_clone(request
->id
);
1497 jsonrpc_send(rpc
, request
);
1498 lock_req_destroy(&lock_req
);
1501 error
= jsonrpc_recv(rpc
, &msg
);
1502 if (error
== EAGAIN
) {
1505 ovs_fatal(error
, "%s: receive failed", jsonrpc_get_name(rpc
));
1508 if (msg
->type
== JSONRPC_REQUEST
&& !strcmp(msg
->method
, "echo")) {
1509 jsonrpc_send(rpc
, jsonrpc_create_reply(json_clone(msg
->params
),
1511 } else if (msg
->type
== JSONRPC_REPLY
1512 && json_equal(msg
->id
, request_id
)) {
1513 print_json(msg
->result
);
1516 enable_lock_request
= true;
1517 json_destroy(request_id
);
1519 daemonize_complete();
1520 } else if (msg
->type
== JSONRPC_NOTIFY
) {
1522 print_json(msg
->params
);
1527 jsonrpc_msg_destroy(msg
);
1536 jsonrpc_recv_wait(rpc
);
1538 unixctl_server_wait(unixctl
);
1542 json_destroy(request_id
);
1543 unixctl_server_destroy(unixctl
);
1547 do_lock_create(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1548 int argc OVS_UNUSED
, char *argv
[])
1550 do_lock(rpc
, "lock", argv
[0]);
1554 do_lock_steal(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1555 int argc OVS_UNUSED
, char *argv
[])
1557 do_lock(rpc
, "steal", argv
[0]);
1561 do_lock_unlock(struct jsonrpc
*rpc
, const char *database OVS_UNUSED
,
1562 int argc OVS_UNUSED
, char *argv
[])
1564 do_lock(rpc
, "unlock", argv
[0]);
1567 /* All command handlers (except for "help") are expected to take an optional
1568 * server socket name (e.g. "unix:...") as their first argument. The socket
1569 * name argument must be included in max_args (but left out of min_args). The
1570 * command name and socket name are not included in the arguments passed to the
1571 * handler: the argv[0] passed to the handler is the first argument after the
1572 * optional server socket name. The connection to the server is available as
1573 * global variable 'rpc'. */
1574 static const struct ovsdb_client_command all_commands
[] = {
1575 { "list-dbs", NEED_RPC
, 0, 0, do_list_dbs
},
1576 { "get-schema", NEED_DATABASE
, 0, 0, do_get_schema
},
1577 { "get-schema-version", NEED_DATABASE
, 0, 0, do_get_schema_version
},
1578 { "list-tables", NEED_DATABASE
, 0, 0, do_list_tables
},
1579 { "list-columns", NEED_DATABASE
, 0, 1, do_list_columns
},
1580 { "transact", NEED_RPC
, 1, 1, do_transact
},
1581 { "monitor", NEED_DATABASE
, 1, INT_MAX
, do_monitor
},
1582 { "monitor-cond", NEED_DATABASE
, 2, 3, do_monitor_cond
},
1583 { "dump", NEED_DATABASE
, 0, INT_MAX
, do_dump
},
1584 { "lock", NEED_RPC
, 1, 1, do_lock_create
},
1585 { "steal", NEED_RPC
, 1, 1, do_lock_steal
},
1586 { "unlock", NEED_RPC
, 1, 1, do_lock_unlock
},
1587 { "help", NEED_NONE
, 0, INT_MAX
, do_help
},
1589 { NULL
, 0, 0, 0, NULL
},
1592 static const struct ovsdb_client_command
*get_all_commands(void)
1594 return all_commands
;