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