]> git.proxmox.com Git - mirror_ovs.git/blob - ovsdb/ovsdb-server.c
ovsdb-idlc: Make generated references to table classes easier to read.
[mirror_ovs.git] / ovsdb / ovsdb-server.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <config.h>
17
18 #include <errno.h>
19 #include <getopt.h>
20 #include <inttypes.h>
21 #include <signal.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "column.h"
26 #include "command-line.h"
27 #include "daemon.h"
28 #include "dirs.h"
29 #include "openvswitch/dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "file.h"
32 #include "hash.h"
33 #include "openvswitch/json.h"
34 #include "jsonrpc.h"
35 #include "jsonrpc-server.h"
36 #include "openvswitch/list.h"
37 #include "memory.h"
38 #include "monitor.h"
39 #include "ovsdb.h"
40 #include "ovsdb-data.h"
41 #include "ovsdb-types.h"
42 #include "ovsdb-error.h"
43 #include "poll-loop.h"
44 #include "process.h"
45 #include "replication.h"
46 #include "row.h"
47 #include "simap.h"
48 #include "openvswitch/shash.h"
49 #include "stream-ssl.h"
50 #include "stream.h"
51 #include "sset.h"
52 #include "table.h"
53 #include "timeval.h"
54 #include "transaction.h"
55 #include "trigger.h"
56 #include "util.h"
57 #include "unixctl.h"
58 #include "perf-counter.h"
59 #include "openvswitch/vlog.h"
60
61 VLOG_DEFINE_THIS_MODULE(ovsdb_server);
62
63 struct db {
64 /* Initialized in main(). */
65 char *filename;
66 struct ovsdb_file *file;
67 struct ovsdb *db;
68
69 /* Only used by update_remote_status(). */
70 struct ovsdb_txn *txn;
71 };
72
73 /* SSL configuration. */
74 static char *private_key_file;
75 static char *certificate_file;
76 static char *ca_cert_file;
77 static bool bootstrap_ca_cert;
78
79 static unixctl_cb_func ovsdb_server_exit;
80 static unixctl_cb_func ovsdb_server_compact;
81 static unixctl_cb_func ovsdb_server_reconnect;
82 static unixctl_cb_func ovsdb_server_perf_counters_clear;
83 static unixctl_cb_func ovsdb_server_perf_counters_show;
84 static unixctl_cb_func ovsdb_server_disable_monitor_cond;
85 static unixctl_cb_func ovsdb_server_set_active_ovsdb_server;
86 static unixctl_cb_func ovsdb_server_get_active_ovsdb_server;
87 static unixctl_cb_func ovsdb_server_connect_active_ovsdb_server;
88 static unixctl_cb_func ovsdb_server_disconnect_active_ovsdb_server;
89 static unixctl_cb_func ovsdb_server_set_sync_exclude_tables;
90 static unixctl_cb_func ovsdb_server_get_sync_exclude_tables;
91 static unixctl_cb_func ovsdb_server_get_sync_status;
92
93 struct server_config {
94 struct sset *remotes;
95 struct shash *all_dbs;
96 FILE *config_tmpfile;
97 char **sync_from;
98 char **sync_exclude;
99 bool *is_backup;
100 struct ovsdb_jsonrpc_server *jsonrpc;
101 };
102 static unixctl_cb_func ovsdb_server_add_remote;
103 static unixctl_cb_func ovsdb_server_remove_remote;
104 static unixctl_cb_func ovsdb_server_list_remotes;
105
106 static unixctl_cb_func ovsdb_server_add_database;
107 static unixctl_cb_func ovsdb_server_remove_database;
108 static unixctl_cb_func ovsdb_server_list_databases;
109
110 static char *open_db(struct server_config *config, const char *filename);
111 static void close_db(struct db *db);
112
113 static void parse_options(int *argc, char **argvp[],
114 struct sset *remotes, char **unixctl_pathp,
115 char **run_command, char **sync_from,
116 char **sync_exclude, bool *is_backup);
117 OVS_NO_RETURN static void usage(void);
118
119 static char *reconfigure_remotes(struct ovsdb_jsonrpc_server *,
120 const struct shash *all_dbs,
121 struct sset *remotes);
122 static char *reconfigure_ssl(const struct shash *all_dbs);
123 static void report_error_if_changed(char *error, char **last_errorp);
124
125 static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
126 const struct sset *remotes,
127 struct shash *all_dbs);
128
129 static void save_config__(FILE *config_file, const struct sset *remotes,
130 const struct sset *db_filenames,
131 const char *sync_from, const char *sync_exclude,
132 bool is_backup);
133 static void save_config(struct server_config *);
134 static void load_config(FILE *config_file, struct sset *remotes,
135 struct sset *db_filenames, char **sync_from,
136 char **sync_exclude, bool *is_backup);
137
138 static void
139 ovsdb_replication_init(const char *sync_from, const char *exclude,
140 struct shash *all_dbs)
141 {
142 replication_init(sync_from, exclude);
143 struct shash_node *node;
144 SHASH_FOR_EACH (node, all_dbs) {
145 struct db *db = node->data;
146 replication_add_local_db(db->db->schema->name, db->db);
147 }
148 }
149
150 static void
151 main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
152 struct unixctl_server *unixctl, struct sset *remotes,
153 struct process *run_process, bool *exiting, bool *is_backup)
154 {
155 char *remotes_error, *ssl_error;
156 struct shash_node *node;
157 long long int status_timer = LLONG_MIN;
158 bool last_role = *is_backup;
159
160 *exiting = false;
161 ssl_error = NULL;
162 remotes_error = NULL;
163 while (!*exiting) {
164 memory_run();
165 if (memory_should_report()) {
166 struct simap usage;
167
168 simap_init(&usage);
169 ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
170 ovsdb_monitor_get_memory_usage(&usage);
171 SHASH_FOR_EACH(node, all_dbs) {
172 struct db *db = node->data;
173 ovsdb_get_memory_usage(db->db, &usage);
174 }
175 memory_report(&usage);
176 simap_destroy(&usage);
177 }
178
179 /* Run unixctl_server_run() before reconfigure_remotes() because
180 * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
181 * the set of remotes that reconfigure_remotes() uses. */
182 unixctl_server_run(unixctl);
183
184 /* In ovsdb-server's role (active or backup) has changed, restart
185 * the ovsdb jsonrpc server. */
186 if (last_role != *is_backup) {
187 bool read_only = last_role = *is_backup;
188 ovsdb_jsonrpc_server_reconnect(jsonrpc, read_only);
189 }
190
191 report_error_if_changed(
192 reconfigure_remotes(jsonrpc, all_dbs, remotes),
193 &remotes_error);
194 report_error_if_changed(reconfigure_ssl(all_dbs), &ssl_error);
195 ovsdb_jsonrpc_server_run(jsonrpc);
196
197 if (*is_backup) {
198 replication_run();
199 if (!replication_is_alive()) {
200 int retval = replication_get_last_error();
201 ovs_fatal(retval, "replication connection failed");
202 }
203 }
204
205 SHASH_FOR_EACH(node, all_dbs) {
206 struct db *db = node->data;
207 ovsdb_trigger_run(db->db, time_msec());
208 }
209 if (run_process) {
210 process_run();
211 if (process_exited(run_process)) {
212 *exiting = true;
213 }
214 }
215
216 /* update Manager status(es) every 2.5 seconds */
217 if (time_msec() >= status_timer) {
218 status_timer = time_msec() + 2500;
219 update_remote_status(jsonrpc, remotes, all_dbs);
220 }
221
222 memory_wait();
223 if (*is_backup) {
224 replication_wait();
225 }
226
227 ovsdb_jsonrpc_server_wait(jsonrpc);
228 unixctl_server_wait(unixctl);
229 SHASH_FOR_EACH(node, all_dbs) {
230 struct db *db = node->data;
231 ovsdb_trigger_wait(db->db, time_msec());
232 }
233 if (run_process) {
234 process_wait(run_process);
235 }
236 if (*exiting) {
237 poll_immediate_wake();
238 }
239 poll_timer_wait_until(status_timer);
240 poll_block();
241 if (should_service_stop()) {
242 *exiting = true;
243 }
244 }
245
246 free(remotes_error);
247 }
248
249 int
250 main(int argc, char *argv[])
251 {
252 char *unixctl_path = NULL;
253 char *run_command = NULL;
254 struct unixctl_server *unixctl;
255 struct ovsdb_jsonrpc_server *jsonrpc;
256 struct sset remotes, db_filenames;
257 char *sync_from, *sync_exclude;
258 bool is_backup;
259 const char *db_filename;
260 struct process *run_process;
261 bool exiting;
262 int retval;
263 FILE *config_tmpfile;
264 struct server_config server_config;
265 struct shash all_dbs;
266 struct shash_node *node, *next;
267 char *error;
268 int i;
269
270 ovs_cmdl_proctitle_init(argc, argv);
271 set_program_name(argv[0]);
272 service_start(&argc, &argv);
273 fatal_ignore_sigpipe();
274 process_init();
275
276 bool active = false;
277 parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command,
278 &sync_from, &sync_exclude, &active);
279 is_backup = sync_from && !active;
280
281 daemon_become_new_user(false);
282
283 /* Create and initialize 'config_tmpfile' as a temporary file to hold
284 * ovsdb-server's most basic configuration, and then save our initial
285 * configuration to it. When --monitor is used, this preserves the effects
286 * of ovs-appctl commands such as ovsdb-server/add-remote (which saves the
287 * new configuration) across crashes. */
288 config_tmpfile = tmpfile();
289 if (!config_tmpfile) {
290 ovs_fatal(errno, "failed to create temporary file");
291 }
292
293 sset_init(&db_filenames);
294 if (argc > 0) {
295 for (i = 0; i < argc; i++) {
296 sset_add(&db_filenames, argv[i]);
297 }
298 } else {
299 char *default_db = xasprintf("%s/conf.db", ovs_dbdir());
300 sset_add(&db_filenames, default_db);
301 free(default_db);
302 }
303
304 server_config.remotes = &remotes;
305 server_config.config_tmpfile = config_tmpfile;
306
307 save_config__(config_tmpfile, &remotes, &db_filenames, sync_from,
308 sync_exclude, is_backup);
309
310 daemonize_start(false);
311
312 /* Load the saved config. */
313 load_config(config_tmpfile, &remotes, &db_filenames, &sync_from,
314 &sync_exclude, &is_backup);
315
316 /* Start ovsdb jsonrpc server. When running as a backup server,
317 * jsonrpc connections are read only. Otherwise, both read
318 * and write transactions are allowed. */
319 jsonrpc = ovsdb_jsonrpc_server_create(is_backup);
320
321 shash_init(&all_dbs);
322 server_config.all_dbs = &all_dbs;
323 server_config.jsonrpc = jsonrpc;
324 server_config.sync_from = &sync_from;
325 server_config.sync_exclude = &sync_exclude;
326 server_config.is_backup = &is_backup;
327
328 perf_counters_init();
329
330 SSET_FOR_EACH (db_filename, &db_filenames) {
331 error = open_db(&server_config, db_filename);
332 if (error) {
333 ovs_fatal(0, "%s", error);
334 }
335 }
336
337 error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes);
338 if (!error) {
339 error = reconfigure_ssl(&all_dbs);
340 }
341 if (error) {
342 ovs_fatal(0, "%s", error);
343 }
344
345 retval = unixctl_server_create(unixctl_path, &unixctl);
346 if (retval) {
347 exit(EXIT_FAILURE);
348 }
349
350 if (run_command) {
351 char *run_argv[4];
352
353 run_argv[0] = "/bin/sh";
354 run_argv[1] = "-c";
355 run_argv[2] = run_command;
356 run_argv[3] = NULL;
357
358 retval = process_start(run_argv, &run_process);
359 if (retval) {
360 ovs_fatal(retval, "%s: process failed to start", run_command);
361 }
362 } else {
363 run_process = NULL;
364 }
365
366 daemonize_complete();
367
368 if (!run_command) {
369 /* ovsdb-server is usually a long-running process, in which case it
370 * makes plenty of sense to log the version, but --run makes
371 * ovsdb-server more like a command-line tool, so skip it. */
372 VLOG_INFO("%s (Open vSwitch) %s", program_name, VERSION);
373 }
374
375 unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting);
376 unixctl_command_register("ovsdb-server/compact", "", 0, 1,
377 ovsdb_server_compact, &all_dbs);
378 unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
379 ovsdb_server_reconnect, jsonrpc);
380
381 unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1,
382 ovsdb_server_add_remote, &server_config);
383 unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1,
384 ovsdb_server_remove_remote, &server_config);
385 unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0,
386 ovsdb_server_list_remotes, &remotes);
387
388 unixctl_command_register("ovsdb-server/add-db", "DB", 1, 1,
389 ovsdb_server_add_database, &server_config);
390 unixctl_command_register("ovsdb-server/remove-db", "DB", 1, 1,
391 ovsdb_server_remove_database, &server_config);
392 unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
393 ovsdb_server_list_databases, &all_dbs);
394 unixctl_command_register("ovsdb-server/perf-counters-show", "", 0, 0,
395 ovsdb_server_perf_counters_show, NULL);
396 unixctl_command_register("ovsdb-server/perf-counters-clear", "", 0, 0,
397 ovsdb_server_perf_counters_clear, NULL);
398 unixctl_command_register("ovsdb-server/set-active-ovsdb-server", "", 1, 1,
399 ovsdb_server_set_active_ovsdb_server,
400 &server_config);
401 unixctl_command_register("ovsdb-server/get-active-ovsdb-server", "", 0, 0,
402 ovsdb_server_get_active_ovsdb_server,
403 &server_config);
404 unixctl_command_register("ovsdb-server/connect-active-ovsdb-server", "",
405 0, 0, ovsdb_server_connect_active_ovsdb_server,
406 &server_config);
407 unixctl_command_register("ovsdb-server/disconnect-active-ovsdb-server", "",
408 0, 0, ovsdb_server_disconnect_active_ovsdb_server,
409 &server_config);
410 unixctl_command_register("ovsdb-server/set-sync-exclude-tables", "",
411 0, 1, ovsdb_server_set_sync_exclude_tables,
412 &server_config);
413 unixctl_command_register("ovsdb-server/get-sync-exclude-tables", "",
414 0, 0, ovsdb_server_get_sync_exclude_tables,
415 NULL);
416 unixctl_command_register("ovsdb-server/sync-status", "",
417 0, 0, ovsdb_server_get_sync_status,
418 &server_config);
419
420 /* Simulate the behavior of OVS release prior to version 2.5 that
421 * does not support the monitor_cond method. */
422 unixctl_command_register("ovsdb-server/disable-monitor-cond", "", 0, 0,
423 ovsdb_server_disable_monitor_cond, jsonrpc);
424
425 if (is_backup) {
426 ovsdb_replication_init(sync_from, sync_exclude, &all_dbs);
427 }
428
429 main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting,
430 &is_backup);
431
432 ovsdb_jsonrpc_server_destroy(jsonrpc);
433 SHASH_FOR_EACH_SAFE(node, next, &all_dbs) {
434 struct db *db = node->data;
435 close_db(db);
436 shash_delete(&all_dbs, node);
437 }
438 shash_destroy(&all_dbs);
439 sset_destroy(&remotes);
440 sset_destroy(&db_filenames);
441 free(sync_from);
442 free(sync_exclude);
443 unixctl_server_destroy(unixctl);
444 replication_destroy();
445
446 if (run_process && process_exited(run_process)) {
447 int status = process_status(run_process);
448 if (status) {
449 ovs_fatal(0, "%s: child exited, %s",
450 run_command, process_status_msg(status));
451 }
452 }
453 perf_counters_destroy();
454 service_stop();
455 return 0;
456 }
457
458 /* Returns true if 'filename' is known to be already open as a database,
459 * false if not.
460 *
461 * "False negatives" are possible. */
462 static bool
463 is_already_open(struct server_config *config OVS_UNUSED,
464 const char *filename OVS_UNUSED)
465 {
466 #ifndef _WIN32
467 struct stat s;
468
469 if (!stat(filename, &s)) {
470 struct shash_node *node;
471
472 SHASH_FOR_EACH (node, config->all_dbs) {
473 struct db *db = node->data;
474 struct stat s2;
475
476 if (!stat(db->filename, &s2)
477 && s.st_dev == s2.st_dev
478 && s.st_ino == s2.st_ino) {
479 return true;
480 }
481 }
482 }
483 #endif /* !_WIN32 */
484
485 return false;
486 }
487
488 static void
489 close_db(struct db *db)
490 {
491 ovsdb_destroy(db->db);
492 free(db->filename);
493 free(db);
494 }
495
496 static char *
497 open_db(struct server_config *config, const char *filename)
498 {
499 struct ovsdb_error *db_error;
500 struct db *db;
501 char *error;
502
503 /* If we know that the file is already open, return a good error message.
504 * Otherwise, if the file is open, we'll fail later on with a harder to
505 * interpret file locking error. */
506 if (is_already_open(config, filename)) {
507 return xasprintf("%s: already open", filename);
508 }
509
510 db = xzalloc(sizeof *db);
511 db->filename = xstrdup(filename);
512
513 db_error = ovsdb_file_open(db->filename, false, &db->db, &db->file);
514 if (db_error) {
515 error = ovsdb_error_to_string(db_error);
516 } else if (!ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db)) {
517 error = xasprintf("%s: duplicate database name", db->db->schema->name);
518 } else {
519 shash_add_assert(config->all_dbs, db->db->schema->name, db);
520 return NULL;
521 }
522
523 ovsdb_error_destroy(db_error);
524 close_db(db);
525 return error;
526 }
527
528 static const struct db *
529 find_db(const struct shash *all_dbs, const char *db_name)
530 {
531 struct shash_node *node;
532
533 SHASH_FOR_EACH (node, all_dbs) {
534 struct db *db = node->data;
535 if (!strcmp(db->db->schema->name, db_name)) {
536 return db;
537 }
538 }
539
540 return NULL;
541 }
542
543 static char * OVS_WARN_UNUSED_RESULT
544 parse_db_column__(const struct shash *all_dbs,
545 const char *name_, char *name,
546 const struct db **dbp,
547 const struct ovsdb_table **tablep,
548 const struct ovsdb_column **columnp)
549 {
550 const char *db_name, *table_name, *column_name;
551 const struct ovsdb_column *column;
552 const struct ovsdb_table *table;
553 const char *tokens[3];
554 char *save_ptr = NULL;
555 const struct db *db;
556
557 *dbp = NULL;
558 *tablep = NULL;
559 *columnp = NULL;
560
561 strtok_r(name, ":", &save_ptr); /* "db:" */
562 tokens[0] = strtok_r(NULL, ",", &save_ptr);
563 tokens[1] = strtok_r(NULL, ",", &save_ptr);
564 tokens[2] = strtok_r(NULL, ",", &save_ptr);
565 if (!tokens[0] || !tokens[1] || !tokens[2]) {
566 return xasprintf("\"%s\": invalid syntax", name_);
567 }
568
569 db_name = tokens[0];
570 table_name = tokens[1];
571 column_name = tokens[2];
572
573 db = find_db(all_dbs, tokens[0]);
574 if (!db) {
575 return xasprintf("\"%s\": no database named %s", name_, db_name);
576 }
577
578 table = ovsdb_get_table(db->db, table_name);
579 if (!table) {
580 return xasprintf("\"%s\": no table named %s", name_, table_name);
581 }
582
583 column = ovsdb_table_schema_get_column(table->schema, column_name);
584 if (!column) {
585 return xasprintf("\"%s\": table \"%s\" has no column \"%s\"",
586 name_, table_name, column_name);
587 }
588
589 *dbp = db;
590 *columnp = column;
591 *tablep = table;
592 return NULL;
593 }
594
595 /* Returns NULL if successful, otherwise a malloc()'d string describing the
596 * error. */
597 static char * OVS_WARN_UNUSED_RESULT
598 parse_db_column(const struct shash *all_dbs,
599 const char *name_,
600 const struct db **dbp,
601 const struct ovsdb_table **tablep,
602 const struct ovsdb_column **columnp)
603 {
604 char *name = xstrdup(name_);
605 char *retval = parse_db_column__(all_dbs, name_, name,
606 dbp, tablep, columnp);
607 free(name);
608 return retval;
609 }
610
611 /* Returns NULL if successful, otherwise a malloc()'d string describing the
612 * error. */
613 static char * OVS_WARN_UNUSED_RESULT
614 parse_db_string_column(const struct shash *all_dbs,
615 const char *name,
616 const struct db **dbp,
617 const struct ovsdb_table **tablep,
618 const struct ovsdb_column **columnp)
619 {
620 char *retval;
621
622 retval = parse_db_column(all_dbs, name, dbp, tablep, columnp);
623 if (retval) {
624 return retval;
625 }
626
627 if ((*columnp)->type.key.type != OVSDB_TYPE_STRING
628 || (*columnp)->type.value.type != OVSDB_TYPE_VOID) {
629 return xasprintf("\"%s\": table \"%s\" column \"%s\" is "
630 "not string or set of strings",
631 name, (*tablep)->schema->name, (*columnp)->name);
632 }
633
634 return NULL;
635 }
636
637 static const char *
638 query_db_string(const struct shash *all_dbs, const char *name,
639 struct ds *errors)
640 {
641 if (!name || strncmp(name, "db:", 3)) {
642 return name;
643 } else {
644 const struct ovsdb_column *column;
645 const struct ovsdb_table *table;
646 const struct ovsdb_row *row;
647 const struct db *db;
648 char *retval;
649
650 retval = parse_db_string_column(all_dbs, name,
651 &db, &table, &column);
652 if (retval) {
653 ds_put_format(errors, "%s\n", retval);
654 free(retval);
655 return NULL;
656 }
657
658 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
659 const struct ovsdb_datum *datum;
660 size_t i;
661
662 datum = &row->fields[column->index];
663 for (i = 0; i < datum->n; i++) {
664 if (datum->keys[i].string[0]) {
665 return datum->keys[i].string;
666 }
667 }
668 }
669 return NULL;
670 }
671 }
672
673 static struct ovsdb_jsonrpc_options *
674 add_remote(struct shash *remotes, const char *target)
675 {
676 struct ovsdb_jsonrpc_options *options;
677
678 options = shash_find_data(remotes, target);
679 if (!options) {
680 options = ovsdb_jsonrpc_default_options(target);
681 shash_add(remotes, target, options);
682 }
683
684 return options;
685 }
686
687 static struct ovsdb_datum *
688 get_datum(struct ovsdb_row *row, const char *column_name,
689 const enum ovsdb_atomic_type key_type,
690 const enum ovsdb_atomic_type value_type,
691 const size_t n_max)
692 {
693 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
694 const struct ovsdb_table_schema *schema = row->table->schema;
695 const struct ovsdb_column *column;
696
697 column = ovsdb_table_schema_get_column(schema, column_name);
698 if (!column) {
699 VLOG_DBG_RL(&rl, "Table `%s' has no `%s' column",
700 schema->name, column_name);
701 return NULL;
702 }
703
704 if (column->type.key.type != key_type
705 || column->type.value.type != value_type
706 || column->type.n_max != n_max) {
707 if (!VLOG_DROP_DBG(&rl)) {
708 char *type_name = ovsdb_type_to_english(&column->type);
709 VLOG_DBG("Table `%s' column `%s' has type %s, not expected "
710 "key type %s, value type %s, max elements %"PRIuSIZE".",
711 schema->name, column_name, type_name,
712 ovsdb_atomic_type_to_string(key_type),
713 ovsdb_atomic_type_to_string(value_type),
714 n_max);
715 free(type_name);
716 }
717 return NULL;
718 }
719
720 return &row->fields[column->index];
721 }
722
723 /* Read string-string key-values from a map. Returns the value associated with
724 * 'key', if found, or NULL */
725 static const char *
726 read_map_string_column(const struct ovsdb_row *row, const char *column_name,
727 const char *key)
728 {
729 const struct ovsdb_datum *datum;
730 union ovsdb_atom *atom_key = NULL, *atom_value = NULL;
731 size_t i;
732
733 datum = get_datum(CONST_CAST(struct ovsdb_row *, row), column_name,
734 OVSDB_TYPE_STRING, OVSDB_TYPE_STRING, UINT_MAX);
735
736 if (!datum) {
737 return NULL;
738 }
739
740 for (i = 0; i < datum->n; i++) {
741 atom_key = &datum->keys[i];
742 if (!strcmp(atom_key->string, key)){
743 atom_value = &datum->values[i];
744 break;
745 }
746 }
747
748 return atom_value ? atom_value->string : NULL;
749 }
750
751 static const union ovsdb_atom *
752 read_column(const struct ovsdb_row *row, const char *column_name,
753 enum ovsdb_atomic_type type)
754 {
755 const struct ovsdb_datum *datum;
756
757 datum = get_datum(CONST_CAST(struct ovsdb_row *, row), column_name, type,
758 OVSDB_TYPE_VOID, 1);
759 return datum && datum->n ? datum->keys : NULL;
760 }
761
762 static bool
763 read_integer_column(const struct ovsdb_row *row, const char *column_name,
764 long long int *integerp)
765 {
766 const union ovsdb_atom *atom;
767
768 atom = read_column(row, column_name, OVSDB_TYPE_INTEGER);
769 *integerp = atom ? atom->integer : 0;
770 return atom != NULL;
771 }
772
773 static bool
774 read_string_column(const struct ovsdb_row *row, const char *column_name,
775 const char **stringp)
776 {
777 const union ovsdb_atom *atom;
778
779 atom = read_column(row, column_name, OVSDB_TYPE_STRING);
780 *stringp = atom ? atom->string : NULL;
781 return atom != NULL;
782 }
783
784 static void
785 write_bool_column(struct ovsdb_row *row, const char *column_name, bool value)
786 {
787 const struct ovsdb_column *column;
788 struct ovsdb_datum *datum;
789
790 column = ovsdb_table_schema_get_column(row->table->schema, column_name);
791 datum = get_datum(row, column_name, OVSDB_TYPE_BOOLEAN,
792 OVSDB_TYPE_VOID, 1);
793 if (!datum) {
794 return;
795 }
796
797 if (datum->n != 1) {
798 ovsdb_datum_destroy(datum, &column->type);
799
800 datum->n = 1;
801 datum->keys = xmalloc(sizeof *datum->keys);
802 datum->values = NULL;
803 }
804
805 datum->keys[0].boolean = value;
806 }
807
808 static void
809 write_string_string_column(struct ovsdb_row *row, const char *column_name,
810 char **keys, char **values, size_t n)
811 {
812 const struct ovsdb_column *column;
813 struct ovsdb_datum *datum;
814 size_t i;
815
816 column = ovsdb_table_schema_get_column(row->table->schema, column_name);
817 datum = get_datum(row, column_name, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING,
818 UINT_MAX);
819 if (!datum) {
820 for (i = 0; i < n; i++) {
821 free(keys[i]);
822 free(values[i]);
823 }
824 return;
825 }
826
827 /* Free existing data. */
828 ovsdb_datum_destroy(datum, &column->type);
829
830 /* Allocate space for new values. */
831 datum->n = n;
832 datum->keys = xmalloc(n * sizeof *datum->keys);
833 datum->values = xmalloc(n * sizeof *datum->values);
834
835 for (i = 0; i < n; ++i) {
836 datum->keys[i].string = keys[i];
837 datum->values[i].string = values[i];
838 }
839
840 /* Sort and check constraints. */
841 ovsdb_datum_sort_assert(datum, column->type.key.type);
842 }
843
844 /* Adds a remote and options to 'remotes', based on the Manager table row in
845 * 'row'. */
846 static void
847 add_manager_options(struct shash *remotes, const struct ovsdb_row *row)
848 {
849 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
850 struct ovsdb_jsonrpc_options *options;
851 long long int max_backoff, probe_interval;
852 const char *target, *dscp_string;
853
854 if (!read_string_column(row, "target", &target) || !target) {
855 VLOG_INFO_RL(&rl, "Table `%s' has missing or invalid `target' column",
856 row->table->schema->name);
857 return;
858 }
859
860 options = add_remote(remotes, target);
861 if (read_integer_column(row, "max_backoff", &max_backoff)) {
862 options->max_backoff = max_backoff;
863 }
864 if (read_integer_column(row, "inactivity_probe", &probe_interval)) {
865 options->probe_interval = probe_interval;
866 }
867
868 options->dscp = DSCP_DEFAULT;
869 dscp_string = read_map_string_column(row, "other_config", "dscp");
870 if (dscp_string) {
871 int dscp = atoi(dscp_string);
872 if (dscp >= 0 && dscp <= 63) {
873 options->dscp = dscp;
874 }
875 }
876 }
877
878 static void
879 query_db_remotes(const char *name, const struct shash *all_dbs,
880 struct shash *remotes, struct ds *errors)
881 {
882 const struct ovsdb_column *column;
883 const struct ovsdb_table *table;
884 const struct ovsdb_row *row;
885 const struct db *db;
886 char *retval;
887
888 retval = parse_db_column(all_dbs, name, &db, &table, &column);
889 if (retval) {
890 ds_put_format(errors, "%s\n", retval);
891 free(retval);
892 return;
893 }
894
895 if (column->type.key.type == OVSDB_TYPE_STRING
896 && column->type.value.type == OVSDB_TYPE_VOID) {
897 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
898 const struct ovsdb_datum *datum;
899 size_t i;
900
901 datum = &row->fields[column->index];
902 for (i = 0; i < datum->n; i++) {
903 add_remote(remotes, datum->keys[i].string);
904 }
905 }
906 } else if (column->type.key.type == OVSDB_TYPE_UUID
907 && column->type.key.u.uuid.refTable
908 && column->type.value.type == OVSDB_TYPE_VOID) {
909 const struct ovsdb_table *ref_table = column->type.key.u.uuid.refTable;
910 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
911 const struct ovsdb_datum *datum;
912 size_t i;
913
914 datum = &row->fields[column->index];
915 for (i = 0; i < datum->n; i++) {
916 const struct ovsdb_row *ref_row;
917
918 ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
919 if (ref_row) {
920 add_manager_options(remotes, ref_row);
921 }
922 }
923 }
924 }
925 }
926
927 static void
928 update_remote_row(const struct ovsdb_row *row, struct ovsdb_txn *txn,
929 const struct ovsdb_jsonrpc_server *jsonrpc)
930 {
931 struct ovsdb_jsonrpc_remote_status status;
932 struct ovsdb_row *rw_row;
933 const char *target;
934 char *keys[9], *values[9];
935 size_t n = 0;
936
937 /* Get the "target" (protocol/host/port) spec. */
938 if (!read_string_column(row, "target", &target)) {
939 /* Bad remote spec or incorrect schema. */
940 return;
941 }
942 rw_row = ovsdb_txn_row_modify(txn, row);
943 ovsdb_jsonrpc_server_get_remote_status(jsonrpc, target, &status);
944
945 /* Update status information columns. */
946 write_bool_column(rw_row, "is_connected", status.is_connected);
947
948 if (status.state) {
949 keys[n] = xstrdup("state");
950 values[n++] = xstrdup(status.state);
951 }
952 if (status.sec_since_connect != UINT_MAX) {
953 keys[n] = xstrdup("sec_since_connect");
954 values[n++] = xasprintf("%u", status.sec_since_connect);
955 }
956 if (status.sec_since_disconnect != UINT_MAX) {
957 keys[n] = xstrdup("sec_since_disconnect");
958 values[n++] = xasprintf("%u", status.sec_since_disconnect);
959 }
960 if (status.last_error) {
961 keys[n] = xstrdup("last_error");
962 values[n++] =
963 xstrdup(ovs_retval_to_string(status.last_error));
964 }
965 if (status.locks_held && status.locks_held[0]) {
966 keys[n] = xstrdup("locks_held");
967 values[n++] = xstrdup(status.locks_held);
968 }
969 if (status.locks_waiting && status.locks_waiting[0]) {
970 keys[n] = xstrdup("locks_waiting");
971 values[n++] = xstrdup(status.locks_waiting);
972 }
973 if (status.locks_lost && status.locks_lost[0]) {
974 keys[n] = xstrdup("locks_lost");
975 values[n++] = xstrdup(status.locks_lost);
976 }
977 if (status.n_connections > 1) {
978 keys[n] = xstrdup("n_connections");
979 values[n++] = xasprintf("%d", status.n_connections);
980 }
981 if (status.bound_port != htons(0)) {
982 keys[n] = xstrdup("bound_port");
983 values[n++] = xasprintf("%"PRIu16, ntohs(status.bound_port));
984 }
985 write_string_string_column(rw_row, "status", keys, values, n);
986
987 ovsdb_jsonrpc_server_free_remote_status(&status);
988 }
989
990 static void
991 update_remote_rows(const struct shash *all_dbs,
992 const char *remote_name,
993 const struct ovsdb_jsonrpc_server *jsonrpc)
994 {
995 const struct ovsdb_table *table, *ref_table;
996 const struct ovsdb_column *column;
997 const struct ovsdb_row *row;
998 const struct db *db;
999 char *retval;
1000
1001 if (strncmp("db:", remote_name, 3)) {
1002 return;
1003 }
1004
1005 retval = parse_db_column(all_dbs, remote_name, &db, &table, &column);
1006 if (retval) {
1007 free(retval);
1008 return;
1009 }
1010
1011 if (column->type.key.type != OVSDB_TYPE_UUID
1012 || !column->type.key.u.uuid.refTable
1013 || column->type.value.type != OVSDB_TYPE_VOID) {
1014 return;
1015 }
1016
1017 ref_table = column->type.key.u.uuid.refTable;
1018
1019 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
1020 const struct ovsdb_datum *datum;
1021 size_t i;
1022
1023 datum = &row->fields[column->index];
1024 for (i = 0; i < datum->n; i++) {
1025 const struct ovsdb_row *ref_row;
1026
1027 ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
1028 if (ref_row) {
1029 update_remote_row(ref_row, db->txn, jsonrpc);
1030 }
1031 }
1032 }
1033 }
1034
1035 static void
1036 update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
1037 const struct sset *remotes,
1038 struct shash *all_dbs)
1039 {
1040 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
1041 const char *remote;
1042 struct db *db;
1043 struct shash_node *node;
1044
1045 SHASH_FOR_EACH(node, all_dbs) {
1046 db = node->data;
1047 db->txn = ovsdb_txn_create(db->db);
1048 }
1049
1050 /* Iterate over --remote arguments given on command line. */
1051 SSET_FOR_EACH (remote, remotes) {
1052 update_remote_rows(all_dbs, remote, jsonrpc);
1053 }
1054
1055 SHASH_FOR_EACH(node, all_dbs) {
1056 struct ovsdb_error *error;
1057 db = node->data;
1058 error = ovsdb_txn_commit(db->txn, false);
1059 if (error) {
1060 VLOG_ERR_RL(&rl, "Failed to update remote status: %s",
1061 ovsdb_error_to_string(error));
1062 ovsdb_error_destroy(error);
1063 }
1064 }
1065 }
1066
1067 /* Reconfigures ovsdb-server's remotes based on information in the database. */
1068 static char *
1069 reconfigure_remotes(struct ovsdb_jsonrpc_server *jsonrpc,
1070 const struct shash *all_dbs, struct sset *remotes)
1071 {
1072 struct ds errors = DS_EMPTY_INITIALIZER;
1073 struct shash resolved_remotes;
1074 const char *name;
1075
1076 /* Configure remotes. */
1077 shash_init(&resolved_remotes);
1078 SSET_FOR_EACH (name, remotes) {
1079 if (!strncmp(name, "db:", 3)) {
1080 query_db_remotes(name, all_dbs, &resolved_remotes, &errors);
1081 } else {
1082 add_remote(&resolved_remotes, name);
1083 }
1084 }
1085 ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
1086 shash_destroy_free_data(&resolved_remotes);
1087
1088 return errors.string;
1089 }
1090
1091 static char *
1092 reconfigure_ssl(const struct shash *all_dbs)
1093 {
1094 struct ds errors = DS_EMPTY_INITIALIZER;
1095 const char *resolved_private_key;
1096 const char *resolved_certificate;
1097 const char *resolved_ca_cert;
1098
1099 resolved_private_key = query_db_string(all_dbs, private_key_file, &errors);
1100 resolved_certificate = query_db_string(all_dbs, certificate_file, &errors);
1101 resolved_ca_cert = query_db_string(all_dbs, ca_cert_file, &errors);
1102
1103 stream_ssl_set_key_and_cert(resolved_private_key, resolved_certificate);
1104 stream_ssl_set_ca_cert_file(resolved_ca_cert, bootstrap_ca_cert);
1105
1106 return errors.string;
1107 }
1108
1109 static void
1110 report_error_if_changed(char *error, char **last_errorp)
1111 {
1112 if (error) {
1113 if (!*last_errorp || strcmp(error, *last_errorp)) {
1114 VLOG_WARN("%s", error);
1115 free(*last_errorp);
1116 *last_errorp = error;
1117 return;
1118 }
1119 free(error);
1120 } else {
1121 free(*last_errorp);
1122 *last_errorp = NULL;
1123 }
1124 }
1125
1126 static void
1127 ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn,
1128 int argc OVS_UNUSED, const char *argv[],
1129 void *config_)
1130 {
1131 struct server_config *config = config_;
1132
1133 if (*config->sync_from) {
1134 free(*config->sync_from);
1135 }
1136 *config->sync_from = xstrdup(argv[1]);
1137 save_config(config);
1138
1139 unixctl_command_reply(conn, NULL);
1140 }
1141
1142 static void
1143 ovsdb_server_get_active_ovsdb_server(struct unixctl_conn *conn,
1144 int argc OVS_UNUSED,
1145 const char *argv[] OVS_UNUSED,
1146 void *config_ )
1147 {
1148 struct server_config *config = config_;
1149
1150 unixctl_command_reply(conn, *config->sync_from);
1151 }
1152
1153 static void
1154 ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn,
1155 int argc OVS_UNUSED,
1156 const char *argv[] OVS_UNUSED,
1157 void *config_)
1158 {
1159 struct server_config *config = config_;
1160 char *msg = NULL;
1161
1162 if ( !*config->sync_from) {
1163 msg = "Unable to connect: active server is not specified.\n";
1164 } else {
1165 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
1166 config->all_dbs);
1167 if (!*config->is_backup) {
1168 *config->is_backup = true;
1169 save_config(config);
1170 }
1171 }
1172 unixctl_command_reply(conn, msg);
1173 }
1174
1175 static void
1176 ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn,
1177 int argc OVS_UNUSED,
1178 const char *argv[] OVS_UNUSED,
1179 void *config_)
1180 {
1181 struct server_config *config = config_;
1182
1183 disconnect_active_server();
1184 *config->is_backup = false;
1185 save_config(config);
1186 unixctl_command_reply(conn, NULL);
1187 }
1188
1189 static void
1190 ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn,
1191 int argc OVS_UNUSED,
1192 const char *argv[],
1193 void *config_)
1194 {
1195 struct server_config *config = config_;
1196
1197 char *err = set_blacklist_tables(argv[1], true);
1198 if (!err) {
1199 free(*config->sync_exclude);
1200 *config->sync_exclude = xstrdup(argv[1]);
1201 save_config(config);
1202 if (*config->is_backup) {
1203 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
1204 config->all_dbs);
1205 }
1206 err = set_blacklist_tables(argv[1], false);
1207 }
1208 unixctl_command_reply(conn, err);
1209 free(err);
1210 }
1211
1212 static void
1213 ovsdb_server_get_sync_exclude_tables(struct unixctl_conn *conn,
1214 int argc OVS_UNUSED,
1215 const char *argv[] OVS_UNUSED,
1216 void *arg_ OVS_UNUSED)
1217 {
1218 char *reply = get_blacklist_tables();
1219 unixctl_command_reply(conn, reply);
1220 free(reply);
1221 }
1222
1223 static void
1224 ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1225 const char *argv[] OVS_UNUSED,
1226 void *exiting_)
1227 {
1228 bool *exiting = exiting_;
1229 *exiting = true;
1230 unixctl_command_reply(conn, NULL);
1231 }
1232
1233 static void
1234 ovsdb_server_perf_counters_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
1235 const char *argv[] OVS_UNUSED,
1236 void *arg_ OVS_UNUSED)
1237 {
1238 char *s = perf_counters_to_string();
1239
1240 unixctl_command_reply(conn, s);
1241 free(s);
1242 }
1243
1244 static void
1245 ovsdb_server_perf_counters_clear(struct unixctl_conn *conn, int argc OVS_UNUSED,
1246 const char *argv[] OVS_UNUSED,
1247 void *arg_ OVS_UNUSED)
1248 {
1249 perf_counters_clear();
1250 unixctl_command_reply(conn, NULL);
1251 }
1252
1253 /* "ovsdb-server/disable-monitor-cond": makes ovsdb-server drop all of its
1254 * JSON-RPC connections and reconnect. New sessions will not recognize
1255 * the 'monitor_cond' method. */
1256 static void
1257 ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn,
1258 int argc OVS_UNUSED,
1259 const char *argv[] OVS_UNUSED,
1260 void *jsonrpc_)
1261 {
1262 struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
1263 bool read_only = ovsdb_jsonrpc_server_is_read_only(jsonrpc);
1264
1265 ovsdb_jsonrpc_disable_monitor_cond();
1266 ovsdb_jsonrpc_server_reconnect(jsonrpc, read_only);
1267 unixctl_command_reply(conn, NULL);
1268 }
1269
1270 static void
1271 ovsdb_server_compact(struct unixctl_conn *conn, int argc,
1272 const char *argv[], void *dbs_)
1273 {
1274 struct shash *all_dbs = dbs_;
1275 struct ds reply;
1276 struct db *db;
1277 struct shash_node *node;
1278 int n = 0;
1279
1280 ds_init(&reply);
1281 SHASH_FOR_EACH(node, all_dbs) {
1282 const char *name;
1283
1284 db = node->data;
1285 name = db->db->schema->name;
1286
1287 if (argc < 2 || !strcmp(argv[1], name)) {
1288 struct ovsdb_error *error;
1289
1290 VLOG_INFO("compacting %s database by user request", name);
1291
1292 error = ovsdb_file_compact(db->file);
1293 if (error) {
1294 char *s = ovsdb_error_to_string(error);
1295 ds_put_format(&reply, "%s\n", s);
1296 free(s);
1297 ovsdb_error_destroy(error);
1298 }
1299
1300 n++;
1301 }
1302 }
1303
1304 if (!n) {
1305 unixctl_command_reply_error(conn, "no database by that name");
1306 } else if (reply.length) {
1307 unixctl_command_reply_error(conn, ds_cstr(&reply));
1308 } else {
1309 unixctl_command_reply(conn, NULL);
1310 }
1311 ds_destroy(&reply);
1312 }
1313
1314 /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC
1315 * connections and reconnect. */
1316 static void
1317 ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED,
1318 const char *argv[] OVS_UNUSED, void *jsonrpc_)
1319 {
1320 struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
1321 bool read_only = ovsdb_jsonrpc_server_is_read_only(jsonrpc);
1322
1323 ovsdb_jsonrpc_server_reconnect(jsonrpc, read_only);
1324 unixctl_command_reply(conn, NULL);
1325 }
1326
1327 /* "ovsdb-server/add-remote REMOTE": adds REMOTE to the set of remotes that
1328 * ovsdb-server services. */
1329 static void
1330 ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
1331 const char *argv[], void *config_)
1332 {
1333 struct server_config *config = config_;
1334 const char *remote = argv[1];
1335
1336 const struct ovsdb_column *column;
1337 const struct ovsdb_table *table;
1338 const struct db *db;
1339 char *retval;
1340
1341 retval = (strncmp("db:", remote, 3)
1342 ? NULL
1343 : parse_db_column(config->all_dbs, remote,
1344 &db, &table, &column));
1345 if (!retval) {
1346 if (sset_add(config->remotes, remote)) {
1347 save_config(config);
1348 }
1349 unixctl_command_reply(conn, NULL);
1350 } else {
1351 unixctl_command_reply_error(conn, retval);
1352 free(retval);
1353 }
1354 }
1355
1356 /* "ovsdb-server/remove-remote REMOTE": removes REMOTE frmo the set of remotes
1357 * that ovsdb-server services. */
1358 static void
1359 ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
1360 const char *argv[], void *config_)
1361 {
1362 struct server_config *config = config_;
1363 struct sset_node *node;
1364
1365 node = sset_find(config->remotes, argv[1]);
1366 if (node) {
1367 sset_delete(config->remotes, node);
1368 save_config(config);
1369 unixctl_command_reply(conn, NULL);
1370 } else {
1371 unixctl_command_reply_error(conn, "no such remote");
1372 }
1373 }
1374
1375 /* "ovsdb-server/list-remotes": outputs a list of configured rmeotes. */
1376 static void
1377 ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED,
1378 const char *argv[] OVS_UNUSED, void *remotes_)
1379 {
1380 struct sset *remotes = remotes_;
1381 const char **list, **p;
1382 struct ds s;
1383
1384 ds_init(&s);
1385
1386 list = sset_sort(remotes);
1387 for (p = list; *p; p++) {
1388 ds_put_format(&s, "%s\n", *p);
1389 }
1390 free(list);
1391
1392 unixctl_command_reply(conn, ds_cstr(&s));
1393 ds_destroy(&s);
1394 }
1395
1396
1397 /* "ovsdb-server/add-db DB": adds the DB to ovsdb-server. */
1398 static void
1399 ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
1400 const char *argv[], void *config_)
1401 {
1402 struct server_config *config = config_;
1403 const char *filename = argv[1];
1404 char *error;
1405
1406 error = open_db(config, filename);
1407 if (!error) {
1408 save_config(config);
1409 if (*config->is_backup) {
1410 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
1411 config->all_dbs);
1412 }
1413 unixctl_command_reply(conn, NULL);
1414 } else {
1415 unixctl_command_reply_error(conn, error);
1416 free(error);
1417 }
1418 }
1419
1420 static void
1421 ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
1422 const char *argv[], void *config_)
1423 {
1424 struct server_config *config = config_;
1425 struct shash_node *node;
1426 struct db *db;
1427 bool ok;
1428
1429 node = shash_find(config->all_dbs, argv[1]);
1430 if (!node) {
1431 unixctl_command_reply_error(conn, "Failed to find the database.");
1432 return;
1433 }
1434 db = node->data;
1435
1436 ok = ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db);
1437 ovs_assert(ok);
1438
1439 close_db(db);
1440 shash_delete(config->all_dbs, node);
1441
1442 save_config(config);
1443 if (*config->is_backup) {
1444 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
1445 config->all_dbs);
1446 }
1447 unixctl_command_reply(conn, NULL);
1448 }
1449
1450 static void
1451 ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED,
1452 const char *argv[] OVS_UNUSED, void *all_dbs_)
1453 {
1454 struct shash *all_dbs = all_dbs_;
1455 const struct shash_node **nodes;
1456 struct ds s;
1457 size_t i;
1458
1459 ds_init(&s);
1460
1461 nodes = shash_sort(all_dbs);
1462 for (i = 0; i < shash_count(all_dbs); i++) {
1463 struct db *db = nodes[i]->data;
1464 ds_put_format(&s, "%s\n", db->db->schema->name);
1465 }
1466 free(nodes);
1467
1468 unixctl_command_reply(conn, ds_cstr(&s));
1469 ds_destroy(&s);
1470 }
1471
1472 static void
1473 ovsdb_server_get_sync_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
1474 const char *argv[] OVS_UNUSED, void *config_)
1475 {
1476 struct server_config *config = config_;
1477 bool is_backup = *config->is_backup;
1478 struct ds ds = DS_EMPTY_INITIALIZER;
1479
1480 ds_put_format(&ds, "state: %s\n", is_backup ? "backup" : "active");
1481
1482 if (is_backup) {
1483 ds_put_and_free_cstr(&ds, replication_status());
1484 }
1485
1486 unixctl_command_reply(conn, ds_cstr(&ds));
1487 ds_destroy(&ds);
1488 }
1489
1490 static void
1491 parse_options(int *argcp, char **argvp[],
1492 struct sset *remotes, char **unixctl_pathp, char **run_command,
1493 char **sync_from, char **sync_exclude, bool *active)
1494 {
1495 enum {
1496 OPT_REMOTE = UCHAR_MAX + 1,
1497 OPT_UNIXCTL,
1498 OPT_RUN,
1499 OPT_BOOTSTRAP_CA_CERT,
1500 OPT_PEER_CA_CERT,
1501 OPT_SYNC_FROM,
1502 OPT_SYNC_EXCLUDE,
1503 OPT_ACTIVE,
1504 VLOG_OPTION_ENUMS,
1505 DAEMON_OPTION_ENUMS
1506 };
1507 static const struct option long_options[] = {
1508 {"remote", required_argument, NULL, OPT_REMOTE},
1509 {"unixctl", required_argument, NULL, OPT_UNIXCTL},
1510 #ifndef _WIN32
1511 {"run", required_argument, NULL, OPT_RUN},
1512 #endif
1513 {"help", no_argument, NULL, 'h'},
1514 {"version", no_argument, NULL, 'V'},
1515 DAEMON_LONG_OPTIONS,
1516 VLOG_LONG_OPTIONS,
1517 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
1518 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
1519 {"private-key", required_argument, NULL, 'p'},
1520 {"certificate", required_argument, NULL, 'c'},
1521 {"ca-cert", required_argument, NULL, 'C'},
1522 {"sync-from", required_argument, NULL, OPT_SYNC_FROM},
1523 {"sync-exclude-tables", required_argument, NULL, OPT_SYNC_EXCLUDE},
1524 {"active", no_argument, NULL, OPT_ACTIVE},
1525 {NULL, 0, NULL, 0},
1526 };
1527 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
1528 int argc = *argcp;
1529 char **argv = *argvp;
1530
1531 *sync_from = NULL;
1532 *sync_exclude = NULL;
1533 sset_init(remotes);
1534 for (;;) {
1535 int c;
1536
1537 c = getopt_long(argc, argv, short_options, long_options, NULL);
1538 if (c == -1) {
1539 break;
1540 }
1541
1542 switch (c) {
1543 case OPT_REMOTE:
1544 sset_add(remotes, optarg);
1545 break;
1546
1547 case OPT_UNIXCTL:
1548 *unixctl_pathp = optarg;
1549 break;
1550
1551 case OPT_RUN:
1552 *run_command = optarg;
1553 break;
1554
1555 case 'h':
1556 usage();
1557
1558 case 'V':
1559 ovs_print_version(0, 0);
1560 exit(EXIT_SUCCESS);
1561
1562 VLOG_OPTION_HANDLERS
1563 DAEMON_OPTION_HANDLERS
1564
1565 case 'p':
1566 private_key_file = optarg;
1567 break;
1568
1569 case 'c':
1570 certificate_file = optarg;
1571 break;
1572
1573 case 'C':
1574 ca_cert_file = optarg;
1575 bootstrap_ca_cert = false;
1576 break;
1577
1578 case OPT_BOOTSTRAP_CA_CERT:
1579 ca_cert_file = optarg;
1580 bootstrap_ca_cert = true;
1581 break;
1582
1583 case OPT_PEER_CA_CERT:
1584 stream_ssl_set_peer_ca_cert_file(optarg);
1585 break;
1586
1587 case OPT_SYNC_FROM:
1588 *sync_from = xstrdup(optarg);
1589 break;
1590
1591 case OPT_SYNC_EXCLUDE: {
1592 char *err = set_blacklist_tables(optarg, false);
1593 if (err) {
1594 ovs_fatal(0, "%s", err);
1595 }
1596 *sync_exclude = xstrdup(optarg);
1597 break;
1598 }
1599 case OPT_ACTIVE:
1600 *active = true;
1601 break;
1602
1603 case '?':
1604 exit(EXIT_FAILURE);
1605
1606 default:
1607 abort();
1608 }
1609 }
1610 free(short_options);
1611
1612 *argcp -= optind;
1613 *argvp += optind;
1614 }
1615
1616 static void
1617 usage(void)
1618 {
1619 printf("%s: Open vSwitch database server\n"
1620 "usage: %s [OPTIONS] [DATABASE...]\n"
1621 "where each DATABASE is a database file in ovsdb format.\n"
1622 "The default DATABASE, if none is given, is\n%s/conf.db.\n",
1623 program_name, program_name, ovs_dbdir());
1624 printf("\nJSON-RPC options (may be specified any number of times):\n"
1625 " --remote=REMOTE connect or listen to REMOTE\n");
1626 stream_usage("JSON-RPC", true, true, true);
1627 daemon_usage();
1628 vlog_usage();
1629 replication_usage();
1630 printf("\nOther options:\n"
1631 " --run COMMAND run COMMAND as subprocess then exit\n"
1632 " --unixctl=SOCKET override default control socket name\n"
1633 " -h, --help display this help message\n"
1634 " -V, --version display version information\n");
1635 exit(EXIT_SUCCESS);
1636 }
1637 \f
1638 static struct json *
1639 sset_to_json(const struct sset *sset)
1640 {
1641 struct json *array;
1642 const char *s;
1643
1644 array = json_array_create_empty();
1645 SSET_FOR_EACH (s, sset) {
1646 json_array_add(array, json_string_create(s));
1647 }
1648 return array;
1649 }
1650
1651 /* Truncates and replaces the contents of 'config_file' by a representation of
1652 * 'remotes' and 'db_filenames'. */
1653 static void
1654 save_config__(FILE *config_file, const struct sset *remotes,
1655 const struct sset *db_filenames, const char *sync_from,
1656 const char *sync_exclude, bool is_backup)
1657 {
1658 struct json *obj;
1659 char *s;
1660
1661 if (ftruncate(fileno(config_file), 0) == -1) {
1662 VLOG_FATAL("failed to truncate temporary file (%s)",
1663 ovs_strerror(errno));
1664 }
1665
1666 obj = json_object_create();
1667 json_object_put(obj, "remotes", sset_to_json(remotes));
1668 json_object_put(obj, "db_filenames", sset_to_json(db_filenames));
1669 if (sync_from) {
1670 json_object_put(obj, "sync_from", json_string_create(sync_from));
1671 }
1672 if (sync_exclude) {
1673 json_object_put(obj, "sync_exclude",
1674 json_string_create(sync_exclude));
1675 }
1676 json_object_put(obj, "is_backup", json_boolean_create(is_backup));
1677
1678 s = json_to_string(obj, 0);
1679 json_destroy(obj);
1680
1681 if (fseek(config_file, 0, SEEK_SET) != 0
1682 || fputs(s, config_file) == EOF
1683 || fflush(config_file) == EOF) {
1684 VLOG_FATAL("failed to write temporary file (%s)", ovs_strerror(errno));
1685 }
1686 free(s);
1687 }
1688
1689 /* Truncates and replaces the contents of 'config_file' by a representation of
1690 * 'config'. */
1691 static void
1692 save_config(struct server_config *config)
1693 {
1694 struct sset db_filenames;
1695 struct shash_node *node;
1696
1697 sset_init(&db_filenames);
1698 SHASH_FOR_EACH (node, config->all_dbs) {
1699 struct db *db = node->data;
1700 sset_add(&db_filenames, db->filename);
1701 }
1702
1703 save_config__(config->config_tmpfile, config->remotes, &db_filenames,
1704 *config->sync_from, *config->sync_exclude,
1705 *config->is_backup);
1706
1707 sset_destroy(&db_filenames);
1708 }
1709
1710 static void
1711 sset_from_json(struct sset *sset, const struct json *array)
1712 {
1713 size_t i;
1714
1715 sset_clear(sset);
1716
1717 ovs_assert(array->type == JSON_ARRAY);
1718 for (i = 0; i < array->u.array.n; i++) {
1719 const struct json *elem = array->u.array.elems[i];
1720 sset_add(sset, json_string(elem));
1721 }
1722 }
1723
1724 /* Clears and replaces 'remotes' and 'dbnames' by a configuration read from
1725 * 'config_file', which must have been previously written by save_config(). */
1726 static void
1727 load_config(FILE *config_file, struct sset *remotes, struct sset *db_filenames,
1728 char **sync_from, char **sync_exclude, bool *is_backup)
1729 {
1730 struct json *json;
1731
1732 if (fseek(config_file, 0, SEEK_SET) != 0) {
1733 VLOG_FATAL("seek failed in temporary file (%s)", ovs_strerror(errno));
1734 }
1735 json = json_from_stream(config_file);
1736 if (json->type == JSON_STRING) {
1737 VLOG_FATAL("reading json failed (%s)", json_string(json));
1738 }
1739 ovs_assert(json->type == JSON_OBJECT);
1740
1741 sset_from_json(remotes, shash_find_data(json_object(json), "remotes"));
1742 sset_from_json(db_filenames,
1743 shash_find_data(json_object(json), "db_filenames"));
1744
1745 struct json *string;
1746 string = shash_find_data(json_object(json), "sync_from");
1747 free(*sync_from);
1748 *sync_from = string ? xstrdup(json_string(string)) : NULL;
1749
1750 string = shash_find_data(json_object(json), "sync_exclude");
1751 free(*sync_exclude);
1752 *sync_exclude = string ? xstrdup(json_string(string)) : NULL;
1753
1754 *is_backup = json_boolean(shash_find_data(json_object(json), "is_backup"));
1755
1756 json_destroy(json);
1757 }