2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 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 parse_options(argc, argv);
94 fatal_ignore_sigpipe();
96 daemon_become_new_user(false);
98 ovs_fatal(0, "missing command name; use --help for help");
101 for (command = get_all_commands(); ; command++) {
102 if (!command->name) {
103 VLOG_FATAL("unknown command '%s'; use --help for help",
105 } else if (!strcmp(command->name, argv[optind])) {
111 if (command->need != NEED_NONE) {
112 if (argc - optind > command->min_args
113 && (isalpha((unsigned char) argv[optind][0])
114 && strchr(argv[optind], ':'))) {
115 rpc = open_jsonrpc(argv[optind++]);
117 char *sock = xasprintf("unix:%s/db.sock", ovs_rundir());
118 rpc = open_jsonrpc(sock);
125 if (command->need == NEED_DATABASE) {
129 fetch_dbs(rpc, &dbs);
130 if (argc - optind > command->min_args
131 && svec_contains(&dbs, argv[optind])) {
132 database = xstrdup(argv[optind++]);
133 } else if (dbs.n == 1) {
134 database = xstrdup(dbs.names[0]);
135 } else if (svec_contains(&dbs, "Open_vSwitch")) {
136 database = xstrdup("Open_vSwitch");
139 ovs_fatal(0, "no default database for `%s' command, please "
140 "specify a database name", command->name);
147 if (argc - optind < command->min_args ||
148 argc - optind > command->max_args) {
150 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
154 command->handler(rpc, database, argc - optind, argv + optind);
159 if (ferror(stdout)) {
160 VLOG_FATAL("write to stdout failed");
162 if (ferror(stderr)) {
163 VLOG_FATAL("write to stderr failed");
170 parse_options(int argc, char *argv[])
173 OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
179 static const struct option long_options[] = {
180 {"help", no_argument, NULL, 'h'},
181 {"version", no_argument, NULL, 'V'},
182 {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
186 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
187 STREAM_SSL_LONG_OPTIONS,
192 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
197 c = getopt_long(argc, argv, short_options, long_options, NULL);
207 ovs_print_version(0, 0);
211 DAEMON_OPTION_HANDLERS
212 TABLE_OPTION_HANDLERS(&table_style)
213 STREAM_SSL_OPTION_HANDLERS
215 case OPT_BOOTSTRAP_CA_CERT:
216 stream_ssl_set_ca_cert_file(optarg, true);
227 /* getopt_long() already set the value for us. */
240 printf("%s: Open vSwitch database JSON-RPC client\n"
241 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
242 "\nValid commands are:\n"
243 "\n list-dbs [SERVER]\n"
244 " list databases available on SERVER\n"
245 "\n get-schema [SERVER] [DATABASE]\n"
246 " retrieve schema for DATABASE from SERVER\n"
247 "\n get-schema-version [SERVER] [DATABASE]\n"
248 " retrieve schema for DATABASE from SERVER and report only its\n"
249 " version number on stdout\n"
250 "\n list-tables [SERVER] [DATABASE]\n"
251 " list tables for DATABASE on SERVER\n"
252 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
253 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
254 "\n transact [SERVER] TRANSACTION\n"
255 " run TRANSACTION (a JSON array of operations) on SERVER\n"
256 " and print the results as JSON on stdout\n"
257 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
258 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
259 " COLUMNs may include !initial, !insert, !delete, !modify\n"
260 " to avoid seeing the specified kinds of changes.\n"
261 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
262 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
263 " DATABASE on SERVER.\n"
264 " COLUMNs may include !initial, !insert, !delete, !modify\n"
265 " to avoid seeing the specified kinds of changes.\n"
266 "\n monitor [SERVER] [DATABASE] ALL\n"
267 " monitor all changes to all columns in all tables\n"
268 " in DATBASE on SERVER.\n"
269 "\n dump [SERVER] [DATABASE]\n"
270 " dump contents of DATABASE on SERVER to stdout\n"
271 "\n lock [SERVER] LOCK\n"
272 " create or wait for LOCK in SERVER\n"
273 "\n steal [SERVER] LOCK\n"
274 " steal LOCK from SERVER\n"
275 "\n unlock [SERVER] LOCK\n"
276 " unlock LOCK from SERVER\n"
277 "\nThe default SERVER is unix:%s/db.sock.\n"
278 "The default DATABASE is Open_vSwitch.\n",
279 program_name, program_name, ovs_rundir());
280 stream_usage("SERVER", true, true, true);
281 printf("\nOutput formatting options:\n"
282 " -f, --format=FORMAT set output formatting to FORMAT\n"
283 " (\"table\", \"html\", \"csv\", "
285 " --no-headings omit table heading row\n"
286 " --pretty pretty-print JSON in output\n"
287 " --timestamp timestamp \"monitor\" output");
290 printf("\nOther options:\n"
291 " -h, --help display this help message\n"
292 " -V, --version display version information\n");
297 check_txn(int error, struct jsonrpc_msg **reply_)
299 struct jsonrpc_msg *reply = *reply_;
302 ovs_fatal(error, "transaction failed");
306 ovs_fatal(error, "transaction returned error: %s",
307 json_to_string(reply->error, table_style.json_flags));
312 parse_json(const char *s)
314 struct json *json = json_from_string(s);
315 if (json->type == JSON_STRING) {
316 ovs_fatal(0, "\"%s\": %s", s, json->u.string);
321 static struct jsonrpc *
322 open_jsonrpc(const char *server)
324 struct stream *stream;
327 error = stream_open_block(jsonrpc_stream_open(server, &stream,
328 DSCP_DEFAULT), &stream);
329 if (error == EAFNOSUPPORT) {
330 struct pstream *pstream;
332 error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
334 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
337 VLOG_INFO("%s: waiting for connection...", server);
338 error = pstream_accept_block(pstream, &stream);
340 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
343 pstream_close(pstream);
345 ovs_fatal(error, "failed to connect to \"%s\"", server);
348 return jsonrpc_open(stream);
352 print_json(struct json *json)
354 char *string = json_to_string(json, table_style.json_flags);
355 fputs(string, stdout);
360 print_and_free_json(struct json *json)
367 check_ovsdb_error(struct ovsdb_error *error)
370 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
374 static struct ovsdb_schema *
375 fetch_schema(struct jsonrpc *rpc, const char *database)
377 struct jsonrpc_msg *request, *reply;
378 struct ovsdb_schema *schema;
380 request = jsonrpc_create_request("get_schema",
382 json_string_create(database)),
384 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
385 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
386 jsonrpc_msg_destroy(reply);
392 fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
394 struct jsonrpc_msg *request, *reply;
397 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
400 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
401 if (reply->result->type != JSON_ARRAY) {
402 ovs_fatal(0, "list_dbs response is not array");
405 for (i = 0; i < reply->result->u.array.n; i++) {
406 const struct json *name = reply->result->u.array.elems[i];
408 if (name->type != JSON_STRING) {
409 ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
411 svec_add(dbs, name->u.string);
413 jsonrpc_msg_destroy(reply);
418 do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
419 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
426 fetch_dbs(rpc, &dbs);
427 SVEC_FOR_EACH (i, db_name, &dbs) {
434 do_get_schema(struct jsonrpc *rpc, const char *database,
435 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
437 struct ovsdb_schema *schema = fetch_schema(rpc, database);
438 print_and_free_json(ovsdb_schema_to_json(schema));
439 ovsdb_schema_destroy(schema);
443 do_get_schema_version(struct jsonrpc *rpc, const char *database,
444 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
446 struct ovsdb_schema *schema = fetch_schema(rpc, database);
447 puts(schema->version);
448 ovsdb_schema_destroy(schema);
452 do_list_tables(struct jsonrpc *rpc, const char *database,
453 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
455 struct ovsdb_schema *schema;
456 struct shash_node *node;
459 schema = fetch_schema(rpc, database);
461 table_add_column(&t, "Table");
462 SHASH_FOR_EACH (node, &schema->tables) {
463 struct ovsdb_table_schema *ts = node->data;
466 table_add_cell(&t)->text = xstrdup(ts->name);
468 ovsdb_schema_destroy(schema);
469 table_print(&t, &table_style);
474 do_list_columns(struct jsonrpc *rpc, const char *database,
475 int argc OVS_UNUSED, char *argv[])
477 const char *table_name = argv[0];
478 struct ovsdb_schema *schema;
479 struct shash_node *table_node;
482 schema = fetch_schema(rpc, database);
485 table_add_column(&t, "Table");
487 table_add_column(&t, "Column");
488 table_add_column(&t, "Type");
489 SHASH_FOR_EACH (table_node, &schema->tables) {
490 struct ovsdb_table_schema *ts = table_node->data;
492 if (!table_name || !strcmp(table_name, ts->name)) {
493 struct shash_node *column_node;
495 SHASH_FOR_EACH (column_node, &ts->columns) {
496 const struct ovsdb_column *column = column_node->data;
500 table_add_cell(&t)->text = xstrdup(ts->name);
502 table_add_cell(&t)->text = xstrdup(column->name);
503 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
507 ovsdb_schema_destroy(schema);
508 table_print(&t, &table_style);
513 do_transact(struct jsonrpc *rpc, const char *database OVS_UNUSED,
514 int argc OVS_UNUSED, char *argv[])
516 struct jsonrpc_msg *request, *reply;
517 struct json *transaction;
519 transaction = parse_json(argv[0]);
521 request = jsonrpc_create_request("transact", transaction, NULL);
522 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
523 print_json(reply->result);
525 jsonrpc_msg_destroy(reply);
528 /* "monitor" command. */
530 struct monitored_table {
531 struct ovsdb_table_schema *table;
532 struct ovsdb_column_set columns;
536 monitor_print_row(struct json *row, const char *type, const char *uuid,
537 const struct ovsdb_column_set *columns, struct table *t)
542 ovs_error(0, "missing %s row", type);
544 } else if (row->type != JSON_OBJECT) {
545 ovs_error(0, "<row> is not object");
550 table_add_cell(t)->text = xstrdup(uuid);
551 table_add_cell(t)->text = xstrdup(type);
552 for (i = 0; i < columns->n_columns; i++) {
553 const struct ovsdb_column *column = columns->columns[i];
554 struct json *value = shash_find_data(json_object(row), column->name);
555 struct cell *cell = table_add_cell(t);
557 cell->json = json_clone(value);
558 cell->type = &column->type;
564 monitor_print_table(struct json *table_update,
565 const struct monitored_table *mt, char *caption,
568 const struct ovsdb_table_schema *table = mt->table;
569 const struct ovsdb_column_set *columns = &mt->columns;
570 struct shash_node *node;
574 if (table_update->type != JSON_OBJECT) {
575 ovs_error(0, "<table-update> for table %s is not object", table->name);
580 table_set_timestamp(&t, timestamp);
581 table_set_caption(&t, caption);
583 table_add_column(&t, "row");
584 table_add_column(&t, "action");
585 for (i = 0; i < columns->n_columns; i++) {
586 table_add_column(&t, "%s", columns->columns[i]->name);
588 SHASH_FOR_EACH (node, json_object(table_update)) {
589 struct json *row_update = node->data;
590 struct json *old, *new;
592 if (row_update->type != JSON_OBJECT) {
593 ovs_error(0, "<row-update> is not object");
596 old = shash_find_data(json_object(row_update), "old");
597 new = shash_find_data(json_object(row_update), "new");
599 monitor_print_row(new, "initial", node->name, columns, &t);
601 monitor_print_row(new, "insert", node->name, columns, &t);
603 monitor_print_row(old, "delete", node->name, columns, &t);
605 monitor_print_row(old, "old", node->name, columns, &t);
606 monitor_print_row(new, "new", "", columns, &t);
609 table_print(&t, &table_style);
614 monitor_print(struct json *table_updates,
615 const struct monitored_table *mts, size_t n_mts,
620 if (table_updates->type != JSON_OBJECT) {
621 ovs_error(0, "<table-updates> is not object");
625 for (i = 0; i < n_mts; i++) {
626 const struct monitored_table *mt = &mts[i];
627 struct json *table_update = shash_find_data(json_object(table_updates),
630 monitor_print_table(table_update, mt,
631 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
638 monitor2_print_row(struct json *row, const char *type, const char *uuid,
639 const struct ovsdb_column_set *columns, struct table *t)
641 if (!strcmp(type, "delete")) {
642 if (row->type != JSON_NULL) {
643 ovs_error(0, "delete method does not expect <row>");
648 table_add_cell(t)->text = xstrdup(uuid);
649 table_add_cell(t)->text = xstrdup(type);
651 if (!row || row->type != JSON_OBJECT) {
652 ovs_error(0, "<row> is not object");
655 monitor_print_row(row, type, uuid, columns, t);
660 monitor2_print_table(struct json *table_update2,
661 const struct monitored_table *mt, char *caption)
663 const struct ovsdb_table_schema *table = mt->table;
664 const struct ovsdb_column_set *columns = &mt->columns;
665 struct shash_node *node;
668 if (table_update2->type != JSON_OBJECT) {
669 ovs_error(0, "<table-update> for table %s is not object", table->name);
674 table_set_timestamp(&t, timestamp);
675 table_set_caption(&t, caption);
677 table_add_column(&t, "row");
678 table_add_column(&t, "action");
679 for (size_t i = 0; i < columns->n_columns; i++) {
680 table_add_column(&t, "%s", columns->columns[i]->name);
682 SHASH_FOR_EACH (node, json_object(table_update2)) {
683 struct json *row_update2 = node->data;
684 const char *operation;
686 const char *ops[] = {"delete", "initial", "modify", "insert"};
688 if (row_update2->type != JSON_OBJECT) {
689 ovs_error(0, "<row-update2> is not object");
693 /* row_update2 contains one of objects indexed by ops[] */
694 for (int i = 0; i < ARRAY_SIZE(ops); i++) {
696 row = shash_find_data(json_object(row_update2), operation);
699 monitor2_print_row(row, operation, node->name, columns, &t);
704 table_print(&t, &table_style);
709 monitor2_print(struct json *table_updates2,
710 const struct monitored_table *mts, size_t n_mts)
714 if (table_updates2->type != JSON_OBJECT) {
715 ovs_error(0, "<table-updates2> is not object");
719 for (i = 0; i < n_mts; i++) {
720 const struct monitored_table *mt = &mts[i];
721 struct json *table_update = shash_find_data(
722 json_object(table_updates2),
725 monitor2_print_table(table_update, mt,
726 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
732 add_column(const char *server, const struct ovsdb_column *column,
733 struct ovsdb_column_set *columns, struct json *columns_json)
735 if (ovsdb_column_set_contains(columns, column->index)) {
736 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
737 server, column->name);
739 ovsdb_column_set_add(columns, column);
740 json_array_add(columns_json, json_string_create(column->name));
744 parse_monitor_columns(char *arg, const char *server, const char *database,
745 const struct ovsdb_table_schema *table,
746 struct ovsdb_column_set *columns)
748 bool initial, insert, delete, modify;
749 struct json *mr, *columns_json;
750 char *save_ptr = NULL;
753 mr = json_object_create();
754 columns_json = json_array_create_empty();
755 json_object_put(mr, "columns", columns_json);
757 initial = insert = delete = modify = true;
758 for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
759 token = strtok_r(NULL, ",", &save_ptr)) {
760 if (!strcmp(token, "!initial")) {
762 } else if (!strcmp(token, "!insert")) {
764 } else if (!strcmp(token, "!delete")) {
766 } else if (!strcmp(token, "!modify")) {
769 const struct ovsdb_column *column;
771 column = ovsdb_table_schema_get_column(table, token);
773 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
774 "column named \"%s\"",
775 server, table->name, database, token);
777 add_column(server, column, columns, columns_json);
781 if (columns_json->u.array.n == 0) {
782 const struct shash_node **nodes;
785 n = shash_count(&table->columns);
786 nodes = shash_sort(&table->columns);
787 for (i = 0; i < n; i++) {
788 const struct ovsdb_column *column = nodes[i]->data;
789 if (column->index != OVSDB_COL_UUID
790 && column->index != OVSDB_COL_VERSION) {
791 add_column(server, column, columns, columns_json);
796 add_column(server, ovsdb_table_schema_get_column(table, "_version"),
797 columns, columns_json);
800 if (!initial || !insert || !delete || !modify) {
801 struct json *select = json_object_create();
802 json_object_put(select, "initial", json_boolean_create(initial));
803 json_object_put(select, "insert", json_boolean_create(insert));
804 json_object_put(select, "delete", json_boolean_create(delete));
805 json_object_put(select, "modify", json_boolean_create(modify));
806 json_object_put(mr, "select", select);
813 ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
814 const char *argv[] OVS_UNUSED, void *exiting_)
816 bool *exiting = exiting_;
818 unixctl_command_reply(conn, NULL);
822 ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
823 const char *argv[] OVS_UNUSED, void *blocked_)
825 bool *blocked = blocked_;
829 unixctl_command_reply(conn, NULL);
831 unixctl_command_reply(conn, "already blocking");
836 ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
837 const char *argv[] OVS_UNUSED, void *blocked_)
839 bool *blocked = blocked_;
843 unixctl_command_reply(conn, NULL);
845 unixctl_command_reply(conn, "already unblocked");
850 ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
851 const char *argv[], void *rpc_)
853 struct jsonrpc *rpc = rpc_;
854 struct json *monitor_cond_update_requests = json_object_create();
855 struct json *monitor_cond_update_request = json_object_create();
857 struct jsonrpc_msg *request;
859 json_object_put(monitor_cond_update_request, "where",
860 json_from_string(argv[2]));
861 json_object_put(monitor_cond_update_requests,
863 json_array_create_1(monitor_cond_update_request));
865 params = json_array_create_3(json_null_create(),json_null_create(),
866 monitor_cond_update_requests);
868 request = jsonrpc_create_request("monitor_cond_change", params, NULL);
869 jsonrpc_send(rpc, request);
871 VLOG_DBG("cond change %s %s", argv[1], argv[2]);
872 unixctl_command_reply(conn, "condiiton changed");
876 add_monitored_table(int argc, char *argv[],
877 const char *server, const char *database,
878 struct json *condition,
879 struct ovsdb_table_schema *table,
880 struct json *monitor_requests,
881 struct monitored_table **mts,
882 size_t *n_mts, size_t *allocated_mts)
884 struct json *monitor_request_array, *mr;
885 struct monitored_table *mt;
887 if (*n_mts >= *allocated_mts) {
888 *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
890 mt = &(*mts)[(*n_mts)++];
892 ovsdb_column_set_init(&mt->columns);
894 monitor_request_array = json_array_create_empty();
898 for (i = 1; i < argc; i++) {
899 mr = parse_monitor_columns(argv[i], server, database, table,
901 if (i == 1 && condition) {
902 json_object_put(mr, "where", condition);
904 json_array_add(monitor_request_array, mr);
907 /* Allocate a writable empty string since parse_monitor_columns()
908 * is going to strtok() it and that's risky with literal "". */
911 mr = parse_monitor_columns(empty, server, database,
912 table, &mt->columns);
914 json_object_put(mr, "where", condition);
916 json_array_add(monitor_request_array, mr);
919 json_object_put(monitor_requests, table->name, monitor_request_array);
923 destroy_monitored_table(struct monitored_table *mts, size_t n)
927 for (i = 0; i < n; i++) {
928 struct monitored_table *mt = &mts[i];
929 ovsdb_column_set_destroy(&mt->columns);
936 do_monitor__(struct jsonrpc *rpc, const char *database,
937 enum ovsdb_monitor_version version,
938 int argc, char *argv[], struct json *condition)
940 const char *server = jsonrpc_get_name(rpc);
941 const char *table_name = argv[0];
942 struct unixctl_server *unixctl;
943 struct ovsdb_schema *schema;
944 struct jsonrpc_msg *request;
945 struct json *monitor, *monitor_requests, *request_id;
946 bool exiting = false;
947 bool blocked = false;
949 struct monitored_table *mts;
950 size_t n_mts, allocated_mts;
952 ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
954 daemon_save_fd(STDOUT_FILENO);
955 daemonize_start(false);
959 error = unixctl_server_create(NULL, &unixctl);
961 ovs_fatal(error, "failed to create unixctl server");
964 unixctl_command_register("exit", "", 0, 0,
965 ovsdb_client_exit, &exiting);
966 unixctl_command_register("ovsdb-client/block", "", 0, 0,
967 ovsdb_client_block, &blocked);
968 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
969 ovsdb_client_unblock, &blocked);
970 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
971 ovsdb_client_cond_change, rpc);
976 schema = fetch_schema(rpc, database);
978 monitor_requests = json_object_create();
981 n_mts = allocated_mts = 0;
982 if (strcmp(table_name, "ALL")) {
983 struct ovsdb_table_schema *table;
985 table = shash_find_data(&schema->tables, table_name);
987 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
988 server, database, table_name);
991 add_monitored_table(argc, argv, server, database, condition, table,
992 monitor_requests, &mts, &n_mts, &allocated_mts);
994 size_t n = shash_count(&schema->tables);
995 const struct shash_node **nodes = shash_sort(&schema->tables);
999 ovs_fatal(0, "ALL tables are not allowed with condition");
1002 for (i = 0; i < n; i++) {
1003 struct ovsdb_table_schema *table = nodes[i]->data;
1005 add_monitored_table(argc, argv, server, database, NULL, table,
1007 &mts, &n_mts, &allocated_mts);
1012 monitor = json_array_create_3(json_string_create(database),
1013 json_null_create(), monitor_requests);
1014 const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
1017 request = jsonrpc_create_request(method, monitor, NULL);
1018 request_id = json_clone(request->id);
1019 jsonrpc_send(rpc, request);
1022 unixctl_server_run(unixctl);
1024 struct jsonrpc_msg *msg;
1027 error = jsonrpc_recv(rpc, &msg);
1028 if (error == EAGAIN) {
1031 ovs_fatal(error, "%s: receive failed", server);
1034 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1035 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1037 } else if (msg->type == JSONRPC_REPLY
1038 && json_equal(msg->id, request_id)) {
1040 case OVSDB_MONITOR_V1:
1041 monitor_print(msg->result, mts, n_mts, true);
1043 case OVSDB_MONITOR_V2:
1044 monitor2_print(msg->result, mts, n_mts);
1046 case OVSDB_MONITOR_VERSION_MAX:
1051 daemonize_complete();
1052 } else if (msg->type == JSONRPC_NOTIFY
1053 && !strcmp(msg->method, "update")) {
1054 struct json *params = msg->params;
1055 if (params->type == JSON_ARRAY
1056 && params->u.array.n == 2
1057 && params->u.array.elems[0]->type == JSON_NULL) {
1058 monitor_print(params->u.array.elems[1], mts, n_mts, false);
1061 } else if (msg->type == JSONRPC_NOTIFY
1062 && version == OVSDB_MONITOR_V2
1063 && !strcmp(msg->method, "update2")) {
1064 struct json *params = msg->params;
1065 if (params->type == JSON_ARRAY
1066 && params->u.array.n == 2
1067 && params->u.array.elems[0]->type == JSON_NULL) {
1068 monitor2_print(params->u.array.elems[1], mts, n_mts);
1072 jsonrpc_msg_destroy(msg);
1082 jsonrpc_recv_wait(rpc);
1084 unixctl_server_wait(unixctl);
1088 json_destroy(request_id);
1089 unixctl_server_destroy(unixctl);
1090 ovsdb_schema_destroy(schema);
1091 destroy_monitored_table(mts, n_mts);
1095 do_monitor(struct jsonrpc *rpc, const char *database,
1096 int argc, char *argv[])
1098 do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL);
1102 do_monitor_cond(struct jsonrpc *rpc, const char *database,
1103 int argc, char *argv[])
1105 struct ovsdb_condition cnd;
1106 struct json *condition = NULL;
1107 struct ovsdb_schema *schema;
1108 struct ovsdb_table_schema *table;
1109 const char *table_name = argv[1];
1111 ovs_assert(argc > 1);
1112 schema = fetch_schema(rpc, database);
1113 table = shash_find_data(&schema->tables, table_name);
1115 ovs_fatal(0, "%s does not have a table named \"%s\"",
1116 database, table_name);
1118 condition = parse_json(argv[0]);
1119 check_ovsdb_error(ovsdb_condition_from_json(table, condition,
1121 ovsdb_condition_destroy(&cnd);
1122 do_monitor__(rpc, database, OVSDB_MONITOR_V2, --argc, ++argv, condition);
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;