]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/ovsdb-client.c
ovsdb-tool: Document database numbering scheme.
[mirror_ovs.git] / ovsdb / ovsdb-client.c
CommitLineData
d0632593 1/*
af65491d 2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
d0632593
BP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
53ffefe9 19#include <ctype.h>
d0632593
BP
20#include <errno.h>
21#include <getopt.h>
22#include <limits.h>
23#include <signal.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include "command-line.h"
29#include "column.h"
30#include "compiler.h"
3f262d7d 31#include "daemon.h"
53ffefe9 32#include "dirs.h"
3e8a2ad1 33#include "openvswitch/dynamic-string.h"
8a777cf6 34#include "fatal-signal.h"
ee89ea7b 35#include "openvswitch/json.h"
d0632593 36#include "jsonrpc.h"
3a3eb9da 37#include "lib/table.h"
d0632593 38#include "ovsdb.h"
c3a0bfd5 39#include "ovsdb-data.h"
d0632593 40#include "ovsdb-error.h"
4227b221 41#include "poll-loop.h"
25c269ef 42#include "sort.h"
9a614624 43#include "svec.h"
d0632593 44#include "stream.h"
9467fe62 45#include "stream-ssl.h"
d0632593 46#include "table.h"
85226894 47#include "monitor.h"
c383f3bf 48#include "condition.h"
d0632593 49#include "timeval.h"
4227b221 50#include "unixctl.h"
d0632593 51#include "util.h"
e6211adc 52#include "openvswitch/vlog.h"
5136ce49 53
d98e6007 54VLOG_DEFINE_THIS_MODULE(ovsdb_client);
d0632593 55
53ffefe9
BP
56enum args_needed {
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. */
60};
61
62struct ovsdb_client_command {
63 const char *name;
64 enum args_needed need;
65 int min_args;
66 int max_args;
67 void (*handler)(struct jsonrpc *rpc, const char *database,
68 int argc, char *argv[]);
69};
70
8f46c9bb
BP
71/* --timestamp: Print a timestamp before each update on "monitor" command? */
72static bool timestamp;
73
3a3eb9da
BP
74/* Format for table output. */
75static struct table_style table_style = TABLE_STYLE_DEFAULT;
c3a0bfd5 76
3815d6c2 77static const struct ovsdb_client_command *get_all_commands(void);
d0632593 78
cab50449 79OVS_NO_RETURN static void usage(void);
d0632593 80static void parse_options(int argc, char *argv[]);
53ffefe9 81static struct jsonrpc *open_jsonrpc(const char *server);
9a614624 82static void fetch_dbs(struct jsonrpc *, struct svec *dbs);
d0632593
BP
83
84int
85main(int argc, char *argv[])
86{
53ffefe9 87 const struct ovsdb_client_command *command;
af65491d 88 char *database;
53ffefe9
BP
89 struct jsonrpc *rpc;
90
5f383751 91 ovs_cmdl_proctitle_init(argc, argv);
d0632593 92 set_program_name(argv[0]);
fe559381 93 service_start(&argc, &argv);
d0632593 94 parse_options(argc, argv);
8a777cf6 95 fatal_ignore_sigpipe();
53ffefe9 96
e91b927d 97 daemon_become_new_user(false);
53ffefe9
BP
98 if (optind >= argc) {
99 ovs_fatal(0, "missing command name; use --help for help");
100 }
101
3815d6c2 102 for (command = get_all_commands(); ; command++) {
53ffefe9
BP
103 if (!command->name) {
104 VLOG_FATAL("unknown command '%s'; use --help for help",
105 argv[optind]);
106 } else if (!strcmp(command->name, argv[optind])) {
107 break;
108 }
109 }
110 optind++;
111
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++]);
117 } else {
118 char *sock = xasprintf("unix:%s/db.sock", ovs_rundir());
119 rpc = open_jsonrpc(sock);
120 free(sock);
121 }
122 } else {
123 rpc = NULL;
124 }
125
126 if (command->need == NEED_DATABASE) {
9a614624 127 struct svec dbs;
53ffefe9 128
9a614624 129 svec_init(&dbs);
53ffefe9
BP
130 fetch_dbs(rpc, &dbs);
131 if (argc - optind > command->min_args
9a614624 132 && svec_contains(&dbs, argv[optind])) {
af65491d 133 database = xstrdup(argv[optind++]);
9a614624
BP
134 } else if (dbs.n == 1) {
135 database = xstrdup(dbs.names[0]);
136 } else if (svec_contains(&dbs, "Open_vSwitch")) {
af65491d 137 database = xstrdup("Open_vSwitch");
53ffefe9 138 } else {
af65491d 139 jsonrpc_close(rpc);
53ffefe9
BP
140 ovs_fatal(0, "no default database for `%s' command, please "
141 "specify a database name", command->name);
142 }
9a614624 143 svec_destroy(&dbs);
53ffefe9
BP
144 } else {
145 database = NULL;
146 }
147
148 if (argc - optind < command->min_args ||
149 argc - optind > command->max_args) {
880f5c03 150 free(database);
53ffefe9
BP
151 VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
152 command->name);
153 }
154
155 command->handler(rpc, database, argc - optind, argv + optind);
156
af65491d 157 free(database);
53ffefe9
BP
158 jsonrpc_close(rpc);
159
160 if (ferror(stdout)) {
161 VLOG_FATAL("write to stdout failed");
162 }
163 if (ferror(stderr)) {
164 VLOG_FATAL("write to stderr failed");
165 }
166
d0632593
BP
167 return 0;
168}
169
170static void
171parse_options(int argc, char *argv[])
172{
9467fe62 173 enum {
8274ae95 174 OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
8f46c9bb 175 OPT_TIMESTAMP,
1af09488 176 VLOG_OPTION_ENUMS,
8274ae95 177 DAEMON_OPTION_ENUMS,
e18a1d08
ER
178 TABLE_OPTION_ENUMS,
179 SSL_OPTION_ENUMS,
9467fe62 180 };
07fc4ed3 181 static const struct option long_options[] = {
e3c17733
BP
182 {"help", no_argument, NULL, 'h'},
183 {"version", no_argument, NULL, 'V'},
8f46c9bb 184 {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
1af09488 185 VLOG_LONG_OPTIONS,
3f262d7d 186 DAEMON_LONG_OPTIONS,
9467fe62 187#ifdef HAVE_OPENSSL
e3c17733 188 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
bf8f2167 189 STREAM_SSL_LONG_OPTIONS,
9467fe62 190#endif
bf8f2167 191 TABLE_LONG_OPTIONS,
e3c17733 192 {NULL, 0, NULL, 0},
d0632593 193 };
5f383751 194 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
d0632593 195
d0632593
BP
196 for (;;) {
197 int c;
198
199 c = getopt_long(argc, argv, short_options, long_options, NULL);
200 if (c == -1) {
201 break;
202 }
203
204 switch (c) {
d0632593
BP
205 case 'h':
206 usage();
207
208 case 'V':
55d5bb44 209 ovs_print_version(0, 0);
d0632593
BP
210 exit(EXIT_SUCCESS);
211
1af09488 212 VLOG_OPTION_HANDLERS
3f262d7d 213 DAEMON_OPTION_HANDLERS
3a3eb9da 214 TABLE_OPTION_HANDLERS(&table_style)
9467fe62
BP
215 STREAM_SSL_OPTION_HANDLERS
216
217 case OPT_BOOTSTRAP_CA_CERT:
218 stream_ssl_set_ca_cert_file(optarg, true);
219 break;
9467fe62 220
8f46c9bb
BP
221 case OPT_TIMESTAMP:
222 timestamp = true;
223 break;
224
d0632593
BP
225 case '?':
226 exit(EXIT_FAILURE);
227
228 case 0:
229 /* getopt_long() already set the value for us. */
230 break;
231
232 default:
233 abort();
234 }
235 }
236 free(short_options);
237}
238
239static void
240usage(void)
241{
242 printf("%s: Open vSwitch database JSON-RPC client\n"
243 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
244 "\nValid commands are:\n"
53ffefe9 245 "\n list-dbs [SERVER]\n"
9cb53f26 246 " list databases available on SERVER\n"
53ffefe9 247 "\n get-schema [SERVER] [DATABASE]\n"
9cb53f26 248 " retrieve schema for DATABASE from SERVER\n"
53ffefe9 249 "\n get-schema-version [SERVER] [DATABASE]\n"
8159b984
BP
250 " retrieve schema for DATABASE from SERVER and report only its\n"
251 " version number on stdout\n"
53ffefe9 252 "\n list-tables [SERVER] [DATABASE]\n"
25c269ef 253 " list tables for DATABASE on SERVER\n"
53ffefe9 254 "\n list-columns [SERVER] [DATABASE] [TABLE]\n"
9cb53f26 255 " list columns in TABLE (or all tables) in DATABASE on SERVER\n"
53ffefe9 256 "\n transact [SERVER] TRANSACTION\n"
6d65eee8 257 " run TRANSACTION (a JSON array of operations) on SERVER\n"
a8425c53 258 " and print the results as JSON on stdout\n"
53ffefe9 259 "\n monitor [SERVER] [DATABASE] TABLE [COLUMN,...]...\n"
20aa445d
BP
260 " monitor contents of COLUMNs in TABLE in DATABASE on SERVER.\n"
261 " COLUMNs may include !initial, !insert, !delete, !modify\n"
262 " to avoid seeing the specified kinds of changes.\n"
c383f3bf
LS
263 "\n monitor-cond [SERVER] [DATABASE] CONDITION TABLE [COLUMN,...]...\n"
264 " monitor contents that match CONDITION of COLUMNs in TABLE in\n"
265 " DATABASE on SERVER.\n"
266 " COLUMNs may include !initial, !insert, !delete, !modify\n"
267 " to avoid seeing the specified kinds of changes.\n"
4227b221
BP
268 "\n monitor [SERVER] [DATABASE] ALL\n"
269 " monitor all changes to all columns in all tables\n"
270 " in DATBASE on SERVER.\n"
85226894 271 "\n dump [SERVER] [DATABASE]\n"
53ffefe9 272 " dump contents of DATABASE on SERVER to stdout\n"
9aeba3f4
AZ
273 "\n lock [SERVER] LOCK\n"
274 " create or wait for LOCK in SERVER\n"
275 "\n steal [SERVER] LOCK\n"
276 " steal LOCK from SERVER\n"
277 "\n unlock [SERVER] LOCK\n"
278 " unlock LOCK from SERVER\n"
53ffefe9
BP
279 "\nThe default SERVER is unix:%s/db.sock.\n"
280 "The default DATABASE is Open_vSwitch.\n",
281 program_name, program_name, ovs_rundir());
9467fe62 282 stream_usage("SERVER", true, true, true);
d0632593
BP
283 printf("\nOutput formatting options:\n"
284 " -f, --format=FORMAT set output formatting to FORMAT\n"
ee890a61
BP
285 " (\"table\", \"html\", \"csv\", "
286 "or \"json\")\n"
b87fde85 287 " --no-headings omit table heading row\n"
8f46c9bb
BP
288 " --pretty pretty-print JSON in output\n"
289 " --timestamp timestamp \"monitor\" output");
3f262d7d 290 daemon_usage();
d0632593
BP
291 vlog_usage();
292 printf("\nOther options:\n"
293 " -h, --help display this help message\n"
294 " -V, --version display version information\n");
295 exit(EXIT_SUCCESS);
296}
297\f
d35f8e72
EJ
298static void
299check_txn(int error, struct jsonrpc_msg **reply_)
300{
301 struct jsonrpc_msg *reply = *reply_;
302
303 if (error) {
304 ovs_fatal(error, "transaction failed");
305 }
306
307 if (reply->error) {
308 ovs_fatal(error, "transaction returned error: %s",
309 json_to_string(reply->error, table_style.json_flags));
310 }
311}
312
6d65eee8
BP
313static struct json *
314parse_json(const char *s)
315{
316 struct json *json = json_from_string(s);
317 if (json->type == JSON_STRING) {
318 ovs_fatal(0, "\"%s\": %s", s, json->u.string);
319 }
320 return json;
321}
322
d0632593
BP
323static struct jsonrpc *
324open_jsonrpc(const char *server)
325{
326 struct stream *stream;
327 int error;
328
f125905c
MM
329 error = stream_open_block(jsonrpc_stream_open(server, &stream,
330 DSCP_DEFAULT), &stream);
1b0f0f17
BP
331 if (error == EAFNOSUPPORT) {
332 struct pstream *pstream;
333
f125905c 334 error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
1b0f0f17
BP
335 if (error) {
336 ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
337 }
338
339 VLOG_INFO("%s: waiting for connection...", server);
340 error = pstream_accept_block(pstream, &stream);
341 if (error) {
342 ovs_fatal(error, "failed to accept connection on \"%s\"", server);
343 }
344
345 pstream_close(pstream);
346 } else if (error) {
d0632593
BP
347 ovs_fatal(error, "failed to connect to \"%s\"", server);
348 }
349
350 return jsonrpc_open(stream);
351}
352
353static void
354print_json(struct json *json)
355{
3a3eb9da 356 char *string = json_to_string(json, table_style.json_flags);
d0632593
BP
357 fputs(string, stdout);
358 free(string);
359}
360
361static void
362print_and_free_json(struct json *json)
363{
364 print_json(json);
365 json_destroy(json);
366}
367
368static void
369check_ovsdb_error(struct ovsdb_error *error)
370{
371 if (error) {
372 ovs_fatal(0, "%s", ovsdb_error_to_string(error));
373 }
374}
375
376static struct ovsdb_schema *
53ffefe9 377fetch_schema(struct jsonrpc *rpc, const char *database)
d0632593
BP
378{
379 struct jsonrpc_msg *request, *reply;
380 struct ovsdb_schema *schema;
d0632593 381
9cb53f26
BP
382 request = jsonrpc_create_request("get_schema",
383 json_array_create_1(
384 json_string_create(database)),
20bed8be 385 NULL);
d35f8e72 386 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
d0632593
BP
387 check_ovsdb_error(ovsdb_schema_from_json(reply->result, &schema));
388 jsonrpc_msg_destroy(reply);
a8425c53
BP
389
390 return schema;
391}
392
9cb53f26 393static void
9a614624 394fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
9cb53f26
BP
395{
396 struct jsonrpc_msg *request, *reply;
9cb53f26
BP
397 size_t i;
398
9cb53f26
BP
399 request = jsonrpc_create_request("list_dbs", json_array_create_empty(),
400 NULL);
9cb53f26 401
d35f8e72 402 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
9cb53f26
BP
403 if (reply->result->type != JSON_ARRAY) {
404 ovs_fatal(0, "list_dbs response is not array");
405 }
406
407 for (i = 0; i < reply->result->u.array.n; i++) {
408 const struct json *name = reply->result->u.array.elems[i];
409
410 if (name->type != JSON_STRING) {
34582733 411 ovs_fatal(0, "list_dbs response %"PRIuSIZE" is not string", i);
9cb53f26 412 }
9a614624 413 svec_add(dbs, name->u.string);
9cb53f26
BP
414 }
415 jsonrpc_msg_destroy(reply);
71fceeb0 416 svec_sort(dbs);
9cb53f26 417}
53ffefe9
BP
418\f
419static void
420do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
421 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
422{
423 const char *db_name;
9a614624
BP
424 struct svec dbs;
425 size_t i;
53ffefe9 426
9a614624 427 svec_init(&dbs);
53ffefe9 428 fetch_dbs(rpc, &dbs);
9a614624 429 SVEC_FOR_EACH (i, db_name, &dbs) {
53ffefe9
BP
430 puts(db_name);
431 }
9a614624 432 svec_destroy(&dbs);
53ffefe9 433}
9cb53f26 434
d0632593 435static void
53ffefe9
BP
436do_get_schema(struct jsonrpc *rpc, const char *database,
437 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593 438{
53ffefe9 439 struct ovsdb_schema *schema = fetch_schema(rpc, database);
d0632593
BP
440 print_and_free_json(ovsdb_schema_to_json(schema));
441 ovsdb_schema_destroy(schema);
442}
443
8159b984 444static void
53ffefe9
BP
445do_get_schema_version(struct jsonrpc *rpc, const char *database,
446 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
8159b984 447{
53ffefe9 448 struct ovsdb_schema *schema = fetch_schema(rpc, database);
8159b984
BP
449 puts(schema->version);
450 ovsdb_schema_destroy(schema);
451}
452
d0632593 453static void
53ffefe9
BP
454do_list_tables(struct jsonrpc *rpc, const char *database,
455 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
456{
457 struct ovsdb_schema *schema;
458 struct shash_node *node;
459 struct table t;
460
53ffefe9 461 schema = fetch_schema(rpc, database);
d0632593
BP
462 table_init(&t);
463 table_add_column(&t, "Table");
d0632593
BP
464 SHASH_FOR_EACH (node, &schema->tables) {
465 struct ovsdb_table_schema *ts = node->data;
466
467 table_add_row(&t);
772387d5 468 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593
BP
469 }
470 ovsdb_schema_destroy(schema);
3a3eb9da 471 table_print(&t, &table_style);
af65491d 472 table_destroy(&t);
d0632593
BP
473}
474
475static void
53ffefe9
BP
476do_list_columns(struct jsonrpc *rpc, const char *database,
477 int argc OVS_UNUSED, char *argv[])
d0632593 478{
53ffefe9 479 const char *table_name = argv[0];
d0632593
BP
480 struct ovsdb_schema *schema;
481 struct shash_node *table_node;
482 struct table t;
483
53ffefe9 484 schema = fetch_schema(rpc, database);
d0632593
BP
485 table_init(&t);
486 if (!table_name) {
487 table_add_column(&t, "Table");
488 }
489 table_add_column(&t, "Column");
490 table_add_column(&t, "Type");
d0632593
BP
491 SHASH_FOR_EACH (table_node, &schema->tables) {
492 struct ovsdb_table_schema *ts = table_node->data;
493
494 if (!table_name || !strcmp(table_name, ts->name)) {
495 struct shash_node *column_node;
496
497 SHASH_FOR_EACH (column_node, &ts->columns) {
bd76d25d 498 const struct ovsdb_column *column = column_node->data;
d0632593
BP
499
500 table_add_row(&t);
501 if (!table_name) {
772387d5 502 table_add_cell(&t)->text = xstrdup(ts->name);
d0632593 503 }
772387d5
BP
504 table_add_cell(&t)->text = xstrdup(column->name);
505 table_add_cell(&t)->json = ovsdb_type_to_json(&column->type);
d0632593
BP
506 }
507 }
508 }
509 ovsdb_schema_destroy(schema);
3a3eb9da 510 table_print(&t, &table_style);
af65491d 511 table_destroy(&t);
d0632593
BP
512}
513
6d65eee8 514static void
53ffefe9
BP
515do_transact(struct jsonrpc *rpc, const char *database OVS_UNUSED,
516 int argc OVS_UNUSED, char *argv[])
6d65eee8
BP
517{
518 struct jsonrpc_msg *request, *reply;
519 struct json *transaction;
6d65eee8 520
53ffefe9 521 transaction = parse_json(argv[0]);
6d65eee8 522
20bed8be 523 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 524 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
6d65eee8
BP
525 print_json(reply->result);
526 putchar('\n');
527 jsonrpc_msg_destroy(reply);
6d65eee8 528}
4227b221
BP
529\f
530/* "monitor" command. */
531
532struct monitored_table {
533 struct ovsdb_table_schema *table;
534 struct ovsdb_column_set columns;
535};
6d65eee8 536
a8425c53
BP
537static void
538monitor_print_row(struct json *row, const char *type, const char *uuid,
539 const struct ovsdb_column_set *columns, struct table *t)
540{
541 size_t i;
542
543 if (!row) {
544 ovs_error(0, "missing %s row", type);
545 return;
546 } else if (row->type != JSON_OBJECT) {
547 ovs_error(0, "<row> is not object");
548 return;
549 }
550
551 table_add_row(t);
772387d5
BP
552 table_add_cell(t)->text = xstrdup(uuid);
553 table_add_cell(t)->text = xstrdup(type);
a8425c53
BP
554 for (i = 0; i < columns->n_columns; i++) {
555 const struct ovsdb_column *column = columns->columns[i];
556 struct json *value = shash_find_data(json_object(row), column->name);
772387d5 557 struct cell *cell = table_add_cell(t);
a8425c53 558 if (value) {
772387d5
BP
559 cell->json = json_clone(value);
560 cell->type = &column->type;
a8425c53
BP
561 }
562 }
563}
564
565static void
4227b221
BP
566monitor_print_table(struct json *table_update,
567 const struct monitored_table *mt, char *caption,
568 bool initial)
a8425c53 569{
4227b221
BP
570 const struct ovsdb_table_schema *table = mt->table;
571 const struct ovsdb_column_set *columns = &mt->columns;
a8425c53
BP
572 struct shash_node *node;
573 struct table t;
574 size_t i;
575
a8425c53 576 if (table_update->type != JSON_OBJECT) {
4227b221 577 ovs_error(0, "<table-update> for table %s is not object", table->name);
a8425c53
BP
578 return;
579 }
580
4227b221
BP
581 table_init(&t);
582 table_set_timestamp(&t, timestamp);
583 table_set_caption(&t, caption);
584
a8425c53
BP
585 table_add_column(&t, "row");
586 table_add_column(&t, "action");
587 for (i = 0; i < columns->n_columns; i++) {
588 table_add_column(&t, "%s", columns->columns[i]->name);
589 }
590 SHASH_FOR_EACH (node, json_object(table_update)) {
591 struct json *row_update = node->data;
592 struct json *old, *new;
593
594 if (row_update->type != JSON_OBJECT) {
595 ovs_error(0, "<row-update> is not object");
596 continue;
597 }
598 old = shash_find_data(json_object(row_update), "old");
599 new = shash_find_data(json_object(row_update), "new");
600 if (initial) {
601 monitor_print_row(new, "initial", node->name, columns, &t);
602 } else if (!old) {
603 monitor_print_row(new, "insert", node->name, columns, &t);
604 } else if (!new) {
605 monitor_print_row(old, "delete", node->name, columns, &t);
606 } else {
607 monitor_print_row(old, "old", node->name, columns, &t);
608 monitor_print_row(new, "new", "", columns, &t);
609 }
610 }
3a3eb9da 611 table_print(&t, &table_style);
a8425c53
BP
612 table_destroy(&t);
613}
614
4227b221
BP
615static void
616monitor_print(struct json *table_updates,
617 const struct monitored_table *mts, size_t n_mts,
618 bool initial)
619{
620 size_t i;
621
622 if (table_updates->type != JSON_OBJECT) {
623 ovs_error(0, "<table-updates> is not object");
624 return;
625 }
626
627 for (i = 0; i < n_mts; i++) {
628 const struct monitored_table *mt = &mts[i];
629 struct json *table_update = shash_find_data(json_object(table_updates),
630 mt->table->name);
631 if (table_update) {
632 monitor_print_table(table_update, mt,
633 n_mts > 1 ? xstrdup(mt->table->name) : NULL,
634 initial);
635 }
636 }
637}
638
85226894
AZ
639static void
640monitor2_print_row(struct json *row, const char *type, const char *uuid,
641 const struct ovsdb_column_set *columns, struct table *t)
642{
643 if (!strcmp(type, "delete")) {
644 if (row->type != JSON_NULL) {
645 ovs_error(0, "delete method does not expect <row>");
646 return;
647 }
648
649 table_add_row(t);
650 table_add_cell(t)->text = xstrdup(uuid);
651 table_add_cell(t)->text = xstrdup(type);
652 } else {
653 if (!row || row->type != JSON_OBJECT) {
654 ovs_error(0, "<row> is not object");
655 return;
656 }
657 monitor_print_row(row, type, uuid, columns, t);
658 }
659}
660
661static void
662monitor2_print_table(struct json *table_update2,
663 const struct monitored_table *mt, char *caption)
664{
665 const struct ovsdb_table_schema *table = mt->table;
666 const struct ovsdb_column_set *columns = &mt->columns;
667 struct shash_node *node;
668 struct table t;
85226894
AZ
669
670 if (table_update2->type != JSON_OBJECT) {
671 ovs_error(0, "<table-update> for table %s is not object", table->name);
672 return;
673 }
674
675 table_init(&t);
676 table_set_timestamp(&t, timestamp);
677 table_set_caption(&t, caption);
678
679 table_add_column(&t, "row");
680 table_add_column(&t, "action");
17573cf1 681 for (size_t i = 0; i < columns->n_columns; i++) {
85226894
AZ
682 table_add_column(&t, "%s", columns->columns[i]->name);
683 }
684 SHASH_FOR_EACH (node, json_object(table_update2)) {
685 struct json *row_update2 = node->data;
686 const char *operation;
687 struct json *row;
688 const char *ops[] = {"delete", "initial", "modify", "insert"};
689
690 if (row_update2->type != JSON_OBJECT) {
691 ovs_error(0, "<row-update2> is not object");
692 continue;
693 }
694
695 /* row_update2 contains one of objects indexed by ops[] */
696 for (int i = 0; i < ARRAY_SIZE(ops); i++) {
697 operation = ops[i];
698 row = shash_find_data(json_object(row_update2), operation);
699
700 if (row) {
701 monitor2_print_row(row, operation, node->name, columns, &t);
702 break;
703 }
704 }
705 }
706 table_print(&t, &table_style);
707 table_destroy(&t);
708}
709
710static void
711monitor2_print(struct json *table_updates2,
712 const struct monitored_table *mts, size_t n_mts)
713{
714 size_t i;
715
716 if (table_updates2->type != JSON_OBJECT) {
717 ovs_error(0, "<table-updates2> is not object");
718 return;
719 }
720
721 for (i = 0; i < n_mts; i++) {
722 const struct monitored_table *mt = &mts[i];
723 struct json *table_update = shash_find_data(
724 json_object(table_updates2),
725 mt->table->name);
726 if (table_update) {
727 monitor2_print_table(table_update, mt,
728 n_mts > 1 ? xstrdup(mt->table->name) : NULL);
729 }
730 }
731}
732
a8425c53 733static void
20aa445d
BP
734add_column(const char *server, const struct ovsdb_column *column,
735 struct ovsdb_column_set *columns, struct json *columns_json)
a8425c53 736{
20aa445d
BP
737 if (ovsdb_column_set_contains(columns, column->index)) {
738 ovs_fatal(0, "%s: column \"%s\" mentioned multiple times",
739 server, column->name);
a8425c53 740 }
20aa445d
BP
741 ovsdb_column_set_add(columns, column);
742 json_array_add(columns_json, json_string_create(column->name));
743}
a8425c53 744
20aa445d
BP
745static struct json *
746parse_monitor_columns(char *arg, const char *server, const char *database,
747 const struct ovsdb_table_schema *table,
748 struct ovsdb_column_set *columns)
749{
750 bool initial, insert, delete, modify;
751 struct json *mr, *columns_json;
752 char *save_ptr = NULL;
753 char *token;
754
755 mr = json_object_create();
756 columns_json = json_array_create_empty();
757 json_object_put(mr, "columns", columns_json);
758
759 initial = insert = delete = modify = true;
760 for (token = strtok_r(arg, ",", &save_ptr); token != NULL;
761 token = strtok_r(NULL, ",", &save_ptr)) {
762 if (!strcmp(token, "!initial")) {
763 initial = false;
764 } else if (!strcmp(token, "!insert")) {
765 insert = false;
766 } else if (!strcmp(token, "!delete")) {
767 delete = false;
768 } else if (!strcmp(token, "!modify")) {
769 modify = false;
770 } else {
a8425c53 771 const struct ovsdb_column *column;
20aa445d 772
a8425c53
BP
773 column = ovsdb_table_schema_get_column(table, token);
774 if (!column) {
9cb53f26
BP
775 ovs_fatal(0, "%s: table \"%s\" in %s does not have a "
776 "column named \"%s\"",
20aa445d 777 server, table->name, database, token);
a8425c53 778 }
20aa445d 779 add_column(server, column, columns, columns_json);
a8425c53 780 }
20aa445d
BP
781 }
782
783 if (columns_json->u.array.n == 0) {
a1ae5dc8
BP
784 const struct shash_node **nodes;
785 size_t i, n;
786
787 n = shash_count(&table->columns);
788 nodes = shash_sort(&table->columns);
789 for (i = 0; i < n; i++) {
790 const struct ovsdb_column *column = nodes[i]->data;
791 if (column->index != OVSDB_COL_UUID
792 && column->index != OVSDB_COL_VERSION) {
20aa445d 793 add_column(server, column, columns, columns_json);
a8425c53
BP
794 }
795 }
a1ae5dc8
BP
796 free(nodes);
797
4227b221 798 add_column(server, ovsdb_table_schema_get_column(table, "_version"),
20aa445d 799 columns, columns_json);
a8425c53
BP
800 }
801
20aa445d
BP
802 if (!initial || !insert || !delete || !modify) {
803 struct json *select = json_object_create();
876ba6de
BP
804 json_object_put(select, "initial", json_boolean_create(initial));
805 json_object_put(select, "insert", json_boolean_create(insert));
806 json_object_put(select, "delete", json_boolean_create(delete));
807 json_object_put(select, "modify", json_boolean_create(modify));
20aa445d
BP
808 json_object_put(mr, "select", select);
809 }
810
811 return mr;
812}
813
814static void
4227b221
BP
815ovsdb_client_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
816 const char *argv[] OVS_UNUSED, void *exiting_)
20aa445d 817{
4227b221
BP
818 bool *exiting = exiting_;
819 *exiting = true;
820 unixctl_command_reply(conn, NULL);
821}
20aa445d 822
4227b221
BP
823static void
824ovsdb_client_block(struct unixctl_conn *conn, int argc OVS_UNUSED,
825 const char *argv[] OVS_UNUSED, void *blocked_)
826{
827 bool *blocked = blocked_;
828
829 if (!*blocked) {
830 *blocked = true;
831 unixctl_command_reply(conn, NULL);
832 } else {
833 unixctl_command_reply(conn, "already blocking");
a8425c53 834 }
4227b221
BP
835}
836
837static void
838ovsdb_client_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
839 const char *argv[] OVS_UNUSED, void *blocked_)
840{
841 bool *blocked = blocked_;
842
843 if (*blocked) {
844 *blocked = false;
845 unixctl_command_reply(conn, NULL);
846 } else {
847 unixctl_command_reply(conn, "already unblocked");
848 }
849}
850
c383f3bf
LS
851static void
852ovsdb_client_cond_change(struct unixctl_conn *conn, int argc OVS_UNUSED,
853 const char *argv[], void *rpc_)
854{
855 struct jsonrpc *rpc = rpc_;
856 struct json *monitor_cond_update_requests = json_object_create();
857 struct json *monitor_cond_update_request = json_object_create();
858 struct json *params;
859 struct jsonrpc_msg *request;
860
861 json_object_put(monitor_cond_update_request, "where",
862 json_from_string(argv[2]));
863 json_object_put(monitor_cond_update_requests,
864 argv[1],
865 json_array_create_1(monitor_cond_update_request));
866
867 params = json_array_create_3(json_null_create(),json_null_create(),
868 monitor_cond_update_requests);
869
870 request = jsonrpc_create_request("monitor_cond_change", params, NULL);
871 jsonrpc_send(rpc, request);
872
873 VLOG_DBG("cond change %s %s", argv[1], argv[2]);
874 unixctl_command_reply(conn, "condiiton changed");
875}
876
4227b221
BP
877static void
878add_monitored_table(int argc, char *argv[],
879 const char *server, const char *database,
c383f3bf 880 struct json *condition,
4227b221
BP
881 struct ovsdb_table_schema *table,
882 struct json *monitor_requests,
883 struct monitored_table **mts,
884 size_t *n_mts, size_t *allocated_mts)
885{
c383f3bf 886 struct json *monitor_request_array, *mr;
4227b221
BP
887 struct monitored_table *mt;
888
889 if (*n_mts >= *allocated_mts) {
890 *mts = x2nrealloc(*mts, allocated_mts, sizeof **mts);
891 }
892 mt = &(*mts)[(*n_mts)++];
893 mt->table = table;
894 ovsdb_column_set_init(&mt->columns);
a8425c53 895
20aa445d 896 monitor_request_array = json_array_create_empty();
53ffefe9 897 if (argc > 1) {
20aa445d
BP
898 int i;
899
53ffefe9 900 for (i = 1; i < argc; i++) {
c383f3bf
LS
901 mr = parse_monitor_columns(argv[i], server, database, table,
902 &mt->columns);
903 if (i == 1 && condition) {
904 json_object_put(mr, "where", condition);
905 }
906 json_array_add(monitor_request_array, mr);
20aa445d
BP
907 }
908 } else {
4227b221
BP
909 /* Allocate a writable empty string since parse_monitor_columns()
910 * is going to strtok() it and that's risky with literal "". */
20aa445d 911 char empty[] = "";
c383f3bf
LS
912
913 mr = parse_monitor_columns(empty, server, database,
914 table, &mt->columns);
915 if (condition) {
916 json_object_put(mr, "where", condition);
917 }
918 json_array_add(monitor_request_array, mr);
4227b221
BP
919 }
920
921 json_object_put(monitor_requests, table->name, monitor_request_array);
922}
923
12f554b0
WT
924static void
925destroy_monitored_table(struct monitored_table *mts, size_t n)
926{
927 int i;
928
929 for (i = 0; i < n; i++) {
930 struct monitored_table *mt = &mts[i];
931 ovsdb_column_set_destroy(&mt->columns);
932 }
933
934 free(mts);
935}
936
4227b221 937static void
85226894
AZ
938do_monitor__(struct jsonrpc *rpc, const char *database,
939 enum ovsdb_monitor_version version,
c383f3bf 940 int argc, char *argv[], struct json *condition)
4227b221
BP
941{
942 const char *server = jsonrpc_get_name(rpc);
943 const char *table_name = argv[0];
944 struct unixctl_server *unixctl;
945 struct ovsdb_schema *schema;
946 struct jsonrpc_msg *request;
947 struct json *monitor, *monitor_requests, *request_id;
948 bool exiting = false;
949 bool blocked = false;
950
951 struct monitored_table *mts;
952 size_t n_mts, allocated_mts;
953
85226894
AZ
954 ovs_assert(version < OVSDB_MONITOR_VERSION_MAX);
955
4227b221 956 daemon_save_fd(STDOUT_FILENO);
e91b927d 957 daemonize_start(false);
4227b221
BP
958 if (get_detach()) {
959 int error;
960
961 error = unixctl_server_create(NULL, &unixctl);
962 if (error) {
963 ovs_fatal(error, "failed to create unixctl server");
964 }
965
966 unixctl_command_register("exit", "", 0, 0,
967 ovsdb_client_exit, &exiting);
968 unixctl_command_register("ovsdb-client/block", "", 0, 0,
969 ovsdb_client_block, &blocked);
970 unixctl_command_register("ovsdb-client/unblock", "", 0, 0,
971 ovsdb_client_unblock, &blocked);
c383f3bf
LS
972 unixctl_command_register("ovsdb-client/cond_change", "TABLE COND", 2, 2,
973 ovsdb_client_cond_change, rpc);
4227b221
BP
974 } else {
975 unixctl = NULL;
a8425c53
BP
976 }
977
4227b221
BP
978 schema = fetch_schema(rpc, database);
979
a8425c53 980 monitor_requests = json_object_create();
4227b221
BP
981
982 mts = NULL;
983 n_mts = allocated_mts = 0;
984 if (strcmp(table_name, "ALL")) {
985 struct ovsdb_table_schema *table;
986
987 table = shash_find_data(&schema->tables, table_name);
988 if (!table) {
989 ovs_fatal(0, "%s: %s does not have a table named \"%s\"",
990 server, database, table_name);
991 }
992
c383f3bf 993 add_monitored_table(argc, argv, server, database, condition, table,
4227b221
BP
994 monitor_requests, &mts, &n_mts, &allocated_mts);
995 } else {
996 size_t n = shash_count(&schema->tables);
997 const struct shash_node **nodes = shash_sort(&schema->tables);
998 size_t i;
999
c383f3bf
LS
1000 if (condition) {
1001 ovs_fatal(0, "ALL tables are not allowed with condition");
1002 }
1003
4227b221
BP
1004 for (i = 0; i < n; i++) {
1005 struct ovsdb_table_schema *table = nodes[i]->data;
1006
c383f3bf 1007 add_monitored_table(argc, argv, server, database, NULL, table,
4227b221
BP
1008 monitor_requests,
1009 &mts, &n_mts, &allocated_mts);
1010 }
1011 free(nodes);
1012 }
a8425c53 1013
9cb53f26
BP
1014 monitor = json_array_create_3(json_string_create(database),
1015 json_null_create(), monitor_requests);
c383f3bf 1016 const char *method = version == OVSDB_MONITOR_V2 ? "monitor_cond"
85226894
AZ
1017 : "monitor";
1018
1019 request = jsonrpc_create_request(method, monitor, NULL);
a8425c53
BP
1020 request_id = json_clone(request->id);
1021 jsonrpc_send(rpc, request);
a8425c53 1022
4227b221
BP
1023 for (;;) {
1024 unixctl_server_run(unixctl);
1025 while (!blocked) {
1026 struct jsonrpc_msg *msg;
1027 int error;
1028
1029 error = jsonrpc_recv(rpc, &msg);
1030 if (error == EAGAIN) {
1031 break;
1032 } else if (error) {
1033 ovs_fatal(error, "%s: receive failed", server);
eb8d3ed6 1034 }
4227b221
BP
1035
1036 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1037 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1038 msg->id));
1039 } else if (msg->type == JSONRPC_REPLY
1040 && json_equal(msg->id, request_id)) {
85226894
AZ
1041 switch(version) {
1042 case OVSDB_MONITOR_V1:
1043 monitor_print(msg->result, mts, n_mts, true);
1044 break;
1045 case OVSDB_MONITOR_V2:
1046 monitor2_print(msg->result, mts, n_mts);
1047 break;
1048 case OVSDB_MONITOR_VERSION_MAX:
1049 default:
1050 OVS_NOT_REACHED();
1051 }
3f262d7d 1052 fflush(stdout);
4227b221
BP
1053 daemonize_complete();
1054 } else if (msg->type == JSONRPC_NOTIFY
1055 && !strcmp(msg->method, "update")) {
1056 struct json *params = msg->params;
1057 if (params->type == JSON_ARRAY
1058 && params->u.array.n == 2
1059 && params->u.array.elems[0]->type == JSON_NULL) {
1060 monitor_print(params->u.array.elems[1], mts, n_mts, false);
1061 fflush(stdout);
1062 }
85226894
AZ
1063 } else if (msg->type == JSONRPC_NOTIFY
1064 && version == OVSDB_MONITOR_V2
1065 && !strcmp(msg->method, "update2")) {
1066 struct json *params = msg->params;
1067 if (params->type == JSON_ARRAY
1068 && params->u.array.n == 2
1069 && params->u.array.elems[0]->type == JSON_NULL) {
1070 monitor2_print(params->u.array.elems[1], mts, n_mts);
1071 fflush(stdout);
1072 }
a8425c53 1073 }
4227b221
BP
1074 jsonrpc_msg_destroy(msg);
1075 }
1076
1077 if (exiting) {
1078 break;
1079 }
1080
1081 jsonrpc_run(rpc);
1082 jsonrpc_wait(rpc);
1083 if (!blocked) {
1084 jsonrpc_recv_wait(rpc);
a8425c53 1085 }
4227b221
BP
1086 unixctl_server_wait(unixctl);
1087 poll_block();
a8425c53 1088 }
c7edc921
WT
1089
1090 json_destroy(request_id);
1091 unixctl_server_destroy(unixctl);
0ea4fd89 1092 ovsdb_schema_destroy(schema);
12f554b0 1093 destroy_monitored_table(mts, n_mts);
a8425c53
BP
1094}
1095
85226894
AZ
1096static void
1097do_monitor(struct jsonrpc *rpc, const char *database,
1098 int argc, char *argv[])
1099{
c383f3bf 1100 do_monitor__(rpc, database, OVSDB_MONITOR_V1, argc, argv, NULL);
85226894
AZ
1101}
1102
1103static void
c383f3bf 1104do_monitor_cond(struct jsonrpc *rpc, const char *database,
85226894
AZ
1105 int argc, char *argv[])
1106{
c383f3bf
LS
1107 struct ovsdb_condition cnd;
1108 struct json *condition = NULL;
1109 struct ovsdb_schema *schema;
1110 struct ovsdb_table_schema *table;
1111 const char *table_name = argv[1];
1112
1113 ovs_assert(argc > 1);
1114 schema = fetch_schema(rpc, database);
1115 table = shash_find_data(&schema->tables, table_name);
1116 if (!table) {
1117 ovs_fatal(0, "%s does not have a table named \"%s\"",
1118 database, table_name);
1119 }
1120 condition = parse_json(argv[0]);
1121 check_ovsdb_error(ovsdb_condition_from_json(table, condition,
1122 NULL, &cnd));
1123 ovsdb_condition_destroy(&cnd);
1124 do_monitor__(rpc, database, OVSDB_MONITOR_V2, --argc, ++argv, condition);
9b2cc0c3 1125 ovsdb_schema_destroy(schema);
85226894
AZ
1126}
1127
25c269ef
BP
1128struct dump_table_aux {
1129 struct ovsdb_datum **data;
1130 const struct ovsdb_column **columns;
1131 size_t n_columns;
1132};
1133
1134static int
1135compare_data(size_t a_y, size_t b_y, size_t x,
1136 const struct dump_table_aux *aux)
1137{
1138 return ovsdb_datum_compare_3way(&aux->data[a_y][x],
1139 &aux->data[b_y][x],
1140 &aux->columns[x]->type);
1141}
1142
1143static int
1144compare_rows(size_t a_y, size_t b_y, void *aux_)
1145{
1146 struct dump_table_aux *aux = aux_;
1147 size_t x;
1148
1149 /* Skip UUID columns on the first pass, since their values tend to be
1150 * random and make our results less reproducible. */
1151 for (x = 0; x < aux->n_columns; x++) {
1152 if (aux->columns[x]->type.key.type != OVSDB_TYPE_UUID) {
1153 int cmp = compare_data(a_y, b_y, x, aux);
1154 if (cmp) {
1155 return cmp;
1156 }
1157 }
1158 }
1159
1160 /* Use UUID columns as tie-breakers. */
1161 for (x = 0; x < aux->n_columns; x++) {
1162 if (aux->columns[x]->type.key.type == OVSDB_TYPE_UUID) {
1163 int cmp = compare_data(a_y, b_y, x, aux);
1164 if (cmp) {
1165 return cmp;
1166 }
1167 }
1168 }
1169
1170 return 0;
1171}
1172
1173static void
1174swap_rows(size_t a_y, size_t b_y, void *aux_)
1175{
1176 struct dump_table_aux *aux = aux_;
1177 struct ovsdb_datum *tmp = aux->data[a_y];
1178 aux->data[a_y] = aux->data[b_y];
1179 aux->data[b_y] = tmp;
1180}
1181
25c269ef
BP
1182static int
1183compare_columns(const void *a_, const void *b_)
1184{
1185 const struct ovsdb_column *const *ap = a_;
1186 const struct ovsdb_column *const *bp = b_;
1187 const struct ovsdb_column *a = *ap;
1188 const struct ovsdb_column *b = *bp;
1189
1190 return strcmp(a->name, b->name);
1191}
1192
1193static void
b30aa413
BV
1194dump_table(const char *table_name, const struct shash *cols,
1195 struct json_array *rows)
25c269ef
BP
1196{
1197 const struct ovsdb_column **columns;
1198 size_t n_columns;
1199
1200 struct ovsdb_datum **data;
1201
1202 struct dump_table_aux aux;
1203 struct shash_node *node;
1204 struct table t;
1205 size_t x, y;
1206
1207 /* Sort columns by name, for reproducibility. */
b30aa413 1208 columns = xmalloc(shash_count(cols) * sizeof *columns);
25c269ef 1209 n_columns = 0;
b30aa413 1210 SHASH_FOR_EACH (node, cols) {
25c269ef
BP
1211 struct ovsdb_column *column = node->data;
1212 if (strcmp(column->name, "_version")) {
1213 columns[n_columns++] = column;
1214 }
1215 }
1216 qsort(columns, n_columns, sizeof *columns, compare_columns);
1217
1218 /* Extract data from table. */
1219 data = xmalloc(rows->n * sizeof *data);
1220 for (y = 0; y < rows->n; y++) {
1221 struct shash *row;
1222
1223 if (rows->elems[y]->type != JSON_OBJECT) {
34582733 1224 ovs_fatal(0, "row %"PRIuSIZE" in table %s response is not a JSON object: "
b30aa413 1225 "%s", y, table_name, json_to_string(rows->elems[y], 0));
25c269ef
BP
1226 }
1227 row = json_object(rows->elems[y]);
1228
1229 data[y] = xmalloc(n_columns * sizeof **data);
1230 for (x = 0; x < n_columns; x++) {
1231 const struct json *json = shash_find_data(row, columns[x]->name);
1232 if (!json) {
34582733 1233 ovs_fatal(0, "row %"PRIuSIZE" in table %s response lacks %s column",
b30aa413 1234 y, table_name, columns[x]->name);
25c269ef
BP
1235 }
1236
1237 check_ovsdb_error(ovsdb_datum_from_json(&data[y][x],
1238 &columns[x]->type,
1239 json, NULL));
1240 }
1241 }
1242
1243 /* Sort rows by column values, for reproducibility. */
1244 aux.data = data;
1245 aux.columns = columns;
1246 aux.n_columns = n_columns;
1247 sort(rows->n, compare_rows, swap_rows, &aux);
1248
1249 /* Add column headings. */
1250 table_init(&t);
b30aa413 1251 table_set_caption(&t, xasprintf("%s table", table_name));
25c269ef
BP
1252 for (x = 0; x < n_columns; x++) {
1253 table_add_column(&t, "%s", columns[x]->name);
1254 }
1255
1256 /* Print rows. */
1257 for (y = 0; y < rows->n; y++) {
1258 table_add_row(&t);
1259 for (x = 0; x < n_columns; x++) {
772387d5
BP
1260 struct cell *cell = table_add_cell(&t);
1261 cell->json = ovsdb_datum_to_json(&data[y][x], &columns[x]->type);
1262 cell->type = &columns[x]->type;
e49190c4 1263 ovsdb_datum_destroy(&data[y][x], &columns[x]->type);
25c269ef 1264 }
e49190c4 1265 free(data[y]);
25c269ef 1266 }
3a3eb9da 1267 table_print(&t, &table_style);
25c269ef 1268 table_destroy(&t);
e49190c4
BP
1269
1270 free(data);
1271 free(columns);
25c269ef
BP
1272}
1273
1274static void
53ffefe9 1275do_dump(struct jsonrpc *rpc, const char *database,
b30aa413 1276 int argc, char *argv[])
25c269ef 1277{
25c269ef
BP
1278 struct jsonrpc_msg *request, *reply;
1279 struct ovsdb_schema *schema;
1280 struct json *transaction;
25c269ef 1281
b30aa413 1282 const struct shash_node *node, **tables;
25c269ef 1283 size_t n_tables;
b30aa413
BV
1284 struct ovsdb_table_schema *tschema;
1285 const struct shash *columns;
1286 struct shash custom_columns;
25c269ef
BP
1287
1288 size_t i;
1289
b30aa413 1290 shash_init(&custom_columns);
53ffefe9 1291 schema = fetch_schema(rpc, database);
b30aa413
BV
1292 if (argc) {
1293 node = shash_find(&schema->tables, argv[0]);
1294 if (!node) {
1295 ovs_fatal(0, "No table \"%s\" found.", argv[0]);
1296 }
1297 tables = xmemdup(&node, sizeof(&node));
1298 n_tables = 1;
1299 tschema = tables[0]->data;
1300 for (i = 1; i < argc; i++) {
1301 node = shash_find(&tschema->columns, argv[i]);
1302 if (!node) {
1303 ovs_fatal(0, "Table \"%s\" has no column %s.", argv[0], argv[1]);
1304 }
1305 shash_add(&custom_columns, argv[1], node->data);
1306 }
1307 } else {
1308 tables = shash_sort(&schema->tables);
1309 n_tables = shash_count(&schema->tables);
1310 }
25c269ef
BP
1311
1312 /* Construct transaction to retrieve entire database. */
1313 transaction = json_array_create_1(json_string_create(database));
1314 for (i = 0; i < n_tables; i++) {
1315 const struct ovsdb_table_schema *ts = tables[i]->data;
b30aa413 1316 struct json *op, *jcolumns;
25c269ef 1317
b30aa413
BV
1318 if (argc > 1) {
1319 columns = &custom_columns;
1320 } else {
1321 columns = &ts->columns;
1322 }
1323 jcolumns = json_array_create_empty();
1324 SHASH_FOR_EACH (node, columns) {
25c269ef
BP
1325 const struct ovsdb_column *column = node->data;
1326
1327 if (strcmp(column->name, "_version")) {
b30aa413 1328 json_array_add(jcolumns, json_string_create(column->name));
25c269ef
BP
1329 }
1330 }
1331
1332 op = json_object_create();
1333 json_object_put_string(op, "op", "select");
1334 json_object_put_string(op, "table", tables[i]->name);
1335 json_object_put(op, "where", json_array_create_empty());
b30aa413 1336 json_object_put(op, "columns", jcolumns);
25c269ef
BP
1337 json_array_add(transaction, op);
1338 }
1339
1340 /* Send request, get reply. */
1341 request = jsonrpc_create_request("transact", transaction, NULL);
d35f8e72 1342 check_txn(jsonrpc_transact_block(rpc, request, &reply), &reply);
25c269ef
BP
1343
1344 /* Print database contents. */
1345 if (reply->result->type != JSON_ARRAY
1346 || reply->result->u.array.n != n_tables) {
34582733 1347 ovs_fatal(0, "reply is not array of %"PRIuSIZE" elements: %s",
25c269ef
BP
1348 n_tables, json_to_string(reply->result, 0));
1349 }
1350 for (i = 0; i < n_tables; i++) {
1351 const struct ovsdb_table_schema *ts = tables[i]->data;
1352 const struct json *op_result = reply->result->u.array.elems[i];
1353 struct json *rows;
1354
1355 if (op_result->type != JSON_OBJECT
1356 || !(rows = shash_find_data(json_object(op_result), "rows"))
1357 || rows->type != JSON_ARRAY) {
1358 ovs_fatal(0, "%s table reply is not an object with a \"rows\" "
1359 "member array: %s",
1360 ts->name, json_to_string(op_result, 0));
1361 }
1362
b30aa413
BV
1363 if (argc > 1) {
1364 dump_table(tables[i]->name, &custom_columns, &rows->u.array);
1365 } else {
1366 dump_table(tables[i]->name, &ts->columns, &rows->u.array);
1367 }
25c269ef 1368 }
e49190c4
BP
1369
1370 jsonrpc_msg_destroy(reply);
b30aa413 1371 shash_destroy(&custom_columns);
e49190c4
BP
1372 free(tables);
1373 ovsdb_schema_destroy(schema);
25c269ef
BP
1374}
1375
d0632593 1376static void
53ffefe9
BP
1377do_help(struct jsonrpc *rpc OVS_UNUSED, const char *database OVS_UNUSED,
1378 int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
d0632593
BP
1379{
1380 usage();
1381}
1382
9aeba3f4
AZ
1383\f
1384/* "lock" command. */
1385
1386struct ovsdb_client_lock_req {
1387 const char *method;
1388 char *lock;
1389};
1390
1391static void
1392lock_req_init(struct ovsdb_client_lock_req *lock_req,
1393 const char *method, const char *lock_name)
1394{
1395 if (lock_req->method || lock_req->lock) {
1396 return;
1397 }
1398 lock_req->method = method;
1399 lock_req->lock = xstrdup(lock_name);
1400}
1401
1402static bool
1403lock_req_is_set(struct ovsdb_client_lock_req *lock_req)
1404{
1405 return lock_req->method;
1406}
1407
1408static void
1409lock_req_destroy(struct ovsdb_client_lock_req *lock_req)
1410{
1411 free(lock_req->lock);
1412 lock_req->method = NULL;
1413 lock_req->lock = NULL;
1414}
1415
1416/* Create a lock class request. Caller is responsible for free
1417 * the 'request' message. */
1418static struct jsonrpc_msg *
1419create_lock_request(struct ovsdb_client_lock_req *lock_req)
1420{
1421 struct json *locks, *lock;
1422
1423 locks = json_array_create_empty();
1424 lock = json_string_create(lock_req->lock);
1425 json_array_add(locks, lock);
1426
1427 return jsonrpc_create_request(lock_req->method, locks, NULL);
1428}
1429
1430static void
1431ovsdb_client_lock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1432 const char *argv[], void *lock_req_)
1433{
1434 struct ovsdb_client_lock_req *lock_req = lock_req_;
1435 lock_req_init(lock_req, "lock", argv[1]);
1436 unixctl_command_reply(conn, NULL);
1437}
1438
1439static void
1440ovsdb_client_unlock(struct unixctl_conn *conn, int argc OVS_UNUSED,
1441 const char *argv[], void *lock_req_)
1442{
1443 struct ovsdb_client_lock_req *lock_req = lock_req_;
1444 lock_req_init(lock_req, "unlock", argv[1]);
1445 unixctl_command_reply(conn, NULL);
1446}
1447
1448static void
1449ovsdb_client_steal(struct unixctl_conn *conn, int argc OVS_UNUSED,
1450 const char *argv[], void *lock_req_)
1451{
1452 struct ovsdb_client_lock_req *lock_req = lock_req_;
1453 lock_req_init(lock_req, "steal", argv[1]);
1454 unixctl_command_reply(conn, NULL);
1455}
1456
1457static void
1458do_lock(struct jsonrpc *rpc, const char *method, const char *lock)
1459{
1460 struct ovsdb_client_lock_req lock_req = {NULL, NULL};
1461 struct unixctl_server *unixctl;
1462 struct jsonrpc_msg *request;
1463 struct json *request_id = NULL;
1464 bool exiting = false;
1465 bool enable_lock_request = true; /* Don't send another request before
1466 getting a reply of the previous
1467 request. */
1468 daemon_save_fd(STDOUT_FILENO);
1469 daemonize_start(false);
1470 lock_req_init(&lock_req, method, lock);
1471
1472 if (get_detach()) {
1473 int error;
1474
1475 error = unixctl_server_create(NULL, &unixctl);
1476 if (error) {
1477 ovs_fatal(error, "failed to create unixctl server");
1478 }
1479
1480 unixctl_command_register("unlock", "LOCK", 1, 1,
1481 ovsdb_client_unlock, &lock_req);
1482 unixctl_command_register("steal", "LOCK", 1, 1,
1483 ovsdb_client_steal, &lock_req);
1484 unixctl_command_register("lock", "LOCK", 1, 1,
1485 ovsdb_client_lock, &lock_req);
1486 unixctl_command_register("exit", "", 0, 0,
1487 ovsdb_client_exit, &exiting);
1488 } else {
1489 unixctl = NULL;
1490 }
1491
1492 for (;;) {
1493 struct jsonrpc_msg *msg;
1494 int error;
1495
1496 unixctl_server_run(unixctl);
1497 if (enable_lock_request && lock_req_is_set(&lock_req)) {
1498 request = create_lock_request(&lock_req);
1499 request_id = json_clone(request->id);
1500 jsonrpc_send(rpc, request);
1501 lock_req_destroy(&lock_req);
1502 }
1503
1504 error = jsonrpc_recv(rpc, &msg);
1505 if (error == EAGAIN) {
1506 goto no_msg;
1507 } else if (error) {
1508 ovs_fatal(error, "%s: receive failed", jsonrpc_get_name(rpc));
1509 }
1510
1511 if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) {
1512 jsonrpc_send(rpc, jsonrpc_create_reply(json_clone(msg->params),
1513 msg->id));
1514 } else if (msg->type == JSONRPC_REPLY
1515 && json_equal(msg->id, request_id)) {
1516 print_json(msg->result);
1517 putchar('\n');
1518 fflush(stdout);
1519 enable_lock_request = true;
1520 json_destroy(request_id);
1521 request_id = NULL;
1522 daemonize_complete();
1523 } else if (msg->type == JSONRPC_NOTIFY) {
1524 puts(msg->method);
1525 print_json(msg->params);
1526 putchar('\n');
1527 fflush(stdout);
1528 }
1529
1530 jsonrpc_msg_destroy(msg);
1531
1532no_msg:
1533 if (exiting) {
1534 break;
1535 }
1536
1537 jsonrpc_run(rpc);
1538 jsonrpc_wait(rpc);
1539 jsonrpc_recv_wait(rpc);
1540
1541 unixctl_server_wait(unixctl);
1542 poll_block();
1543 }
1544
1545 json_destroy(request_id);
1546 unixctl_server_destroy(unixctl);
1547}
1548
1549static void
1550do_lock_create(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1551 int argc OVS_UNUSED, char *argv[])
1552{
1553 do_lock(rpc, "lock", argv[0]);
1554}
1555
1556static void
1557do_lock_steal(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1558 int argc OVS_UNUSED, char *argv[])
1559{
1560 do_lock(rpc, "steal", argv[0]);
1561}
1562
1563static void
1564do_lock_unlock(struct jsonrpc *rpc, const char *database OVS_UNUSED,
1565 int argc OVS_UNUSED, char *argv[])
1566{
1567 do_lock(rpc, "unlock", argv[0]);
1568}
1569
53ffefe9
BP
1570/* All command handlers (except for "help") are expected to take an optional
1571 * server socket name (e.g. "unix:...") as their first argument. The socket
1572 * name argument must be included in max_args (but left out of min_args). The
1573 * command name and socket name are not included in the arguments passed to the
1574 * handler: the argv[0] passed to the handler is the first argument after the
1575 * optional server socket name. The connection to the server is available as
1576 * global variable 'rpc'. */
1577static const struct ovsdb_client_command all_commands[] = {
1578 { "list-dbs", NEED_RPC, 0, 0, do_list_dbs },
1579 { "get-schema", NEED_DATABASE, 0, 0, do_get_schema },
1580 { "get-schema-version", NEED_DATABASE, 0, 0, do_get_schema_version },
1581 { "list-tables", NEED_DATABASE, 0, 0, do_list_tables },
1582 { "list-columns", NEED_DATABASE, 0, 1, do_list_columns },
1583 { "transact", NEED_RPC, 1, 1, do_transact },
1584 { "monitor", NEED_DATABASE, 1, INT_MAX, do_monitor },
c383f3bf 1585 { "monitor-cond", NEED_DATABASE, 2, 3, do_monitor_cond },
b30aa413 1586 { "dump", NEED_DATABASE, 0, INT_MAX, do_dump },
9aeba3f4
AZ
1587 { "lock", NEED_RPC, 1, 1, do_lock_create },
1588 { "steal", NEED_RPC, 1, 1, do_lock_steal },
1589 { "unlock", NEED_RPC, 1, 1, do_lock_unlock },
53ffefe9
BP
1590 { "help", NEED_NONE, 0, INT_MAX, do_help },
1591
1592 { NULL, 0, 0, 0, NULL },
d0632593 1593};
3815d6c2
LS
1594
1595static const struct ovsdb_client_command *get_all_commands(void)
1596{
1597 return all_commands;
1598}