]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/ovsdb-server.c
ovsdb-server: Transaction history tracking.
[mirror_ovs.git] / ovsdb / ovsdb-server.c
CommitLineData
474339e2 1/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Nicira, Inc.
f85f8ebb
BP
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
f85f8ebb
BP
18#include <errno.h>
19#include <getopt.h>
798e1352 20#include <inttypes.h>
f85f8ebb 21#include <signal.h>
ebed9f78 22#include <sys/stat.h>
eb077b26 23#include <unistd.h>
f85f8ebb 24
0b1fae1b 25#include "column.h"
f85f8ebb
BP
26#include "command-line.h"
27#include "daemon.h"
29701194 28#include "dirs.h"
3e8a2ad1 29#include "openvswitch/dynamic-string.h"
8a777cf6 30#include "fatal-signal.h"
bd06962a 31#include "file.h"
da897f41 32#include "hash.h"
ee89ea7b 33#include "openvswitch/json.h"
f85f8ebb
BP
34#include "jsonrpc.h"
35#include "jsonrpc-server.h"
b19bab5b 36#include "openvswitch/list.h"
0d085684 37#include "memory.h"
e0c73ed1 38#include "monitor.h"
da897f41 39#include "ovsdb.h"
0b1fae1b
BP
40#include "ovsdb-data.h"
41#include "ovsdb-types.h"
f85f8ebb 42#include "ovsdb-error.h"
fd016ae3 43#include "openvswitch/poll-loop.h"
f85f8ebb 44#include "process.h"
ae671c5f 45#include "replication.h"
0b1fae1b 46#include "row.h"
0d085684 47#include "simap.h"
ee89ea7b 48#include "openvswitch/shash.h"
9467fe62 49#include "stream-ssl.h"
f85f8ebb 50#include "stream.h"
b3c01ed3 51#include "sset.h"
1b1d2e6d 52#include "storage.h"
0b1fae1b 53#include "table.h"
f85f8ebb 54#include "timeval.h"
0b3e7a8b 55#include "transaction.h"
f85f8ebb
BP
56#include "trigger.h"
57#include "util.h"
58#include "unixctl.h"
97a3c435 59#include "perf-counter.h"
40e66ba7 60#include "ovsdb-util.h"
e6211adc 61#include "openvswitch/vlog.h"
5136ce49 62
d98e6007 63VLOG_DEFINE_THIS_MODULE(ovsdb_server);
f85f8ebb 64
6ab3dd96 65struct db {
6ab3dd96 66 char *filename;
6ab3dd96 67 struct ovsdb *db;
6bb9b060 68 struct uuid row_uuid;
6ab3dd96 69};
b4e8d170 70
78876719
BP
71/* SSL configuration. */
72static char *private_key_file;
73static char *certificate_file;
74static char *ca_cert_file;
e18a1d08
ER
75static char *ssl_protocols;
76static char *ssl_ciphers;
78876719
BP
77static bool bootstrap_ca_cert;
78
aa78de9d 79static unixctl_cb_func ovsdb_server_exit;
ada496b5 80static unixctl_cb_func ovsdb_server_compact;
31d0b6c9 81static unixctl_cb_func ovsdb_server_reconnect;
97a3c435
AZ
82static unixctl_cb_func ovsdb_server_perf_counters_clear;
83static unixctl_cb_func ovsdb_server_perf_counters_show;
c383f3bf 84static unixctl_cb_func ovsdb_server_disable_monitor_cond;
f53d7518
AZ
85static unixctl_cb_func ovsdb_server_set_active_ovsdb_server;
86static unixctl_cb_func ovsdb_server_get_active_ovsdb_server;
87static unixctl_cb_func ovsdb_server_connect_active_ovsdb_server;
88static unixctl_cb_func ovsdb_server_disconnect_active_ovsdb_server;
60e0cd04
AZ
89static unixctl_cb_func ovsdb_server_set_sync_exclude_tables;
90static unixctl_cb_func ovsdb_server_get_sync_exclude_tables;
91static unixctl_cb_func ovsdb_server_get_sync_status;
aa78de9d 92
0a3b723b 93struct server_config {
b421d2af 94 struct sset *remotes;
eeb36a52 95 struct shash *all_dbs;
5f36127e 96 FILE *config_tmpfile;
60e0cd04
AZ
97 char **sync_from;
98 char **sync_exclude;
99 bool *is_backup;
0a3b723b 100 struct ovsdb_jsonrpc_server *jsonrpc;
b421d2af
BP
101};
102static unixctl_cb_func ovsdb_server_add_remote;
103static unixctl_cb_func ovsdb_server_remove_remote;
104static unixctl_cb_func ovsdb_server_list_remotes;
105
0a3b723b
BP
106static unixctl_cb_func ovsdb_server_add_database;
107static unixctl_cb_func ovsdb_server_remove_database;
108static unixctl_cb_func ovsdb_server_list_databases;
109
1b1d2e6d
BP
110static void read_db(struct server_config *, struct db *);
111static struct ovsdb_error *open_db(struct server_config *,
112 const char *filename)
113 OVS_WARN_UNUSED_RESULT;
6bb9b060 114static void add_server_db(struct server_config *);
1b1d2e6d
BP
115static void remove_db(struct server_config *, struct shash_node *db, char *);
116static void close_db(struct server_config *, struct db *, char *);
eeb36a52 117
53178986
BP
118static void parse_options(int argc, char *argvp[],
119 struct sset *db_filenames, struct sset *remotes,
120 char **unixctl_pathp, char **run_command,
121 char **sync_from, char **sync_exclude,
122 bool *is_backup);
cab50449 123OVS_NO_RETURN static void usage(void);
f85f8ebb 124
0a3b723b
BP
125static char *reconfigure_remotes(struct ovsdb_jsonrpc_server *,
126 const struct shash *all_dbs,
127 struct sset *remotes);
128static char *reconfigure_ssl(const struct shash *all_dbs);
129static void report_error_if_changed(char *error, char **last_errorp);
0b1fae1b 130
0b3e7a8b 131static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
b3c01ed3 132 const struct sset *remotes,
eeb36a52 133 struct shash *all_dbs);
6bb9b060 134static void update_server_status(struct shash *all_dbs);
0b3e7a8b 135
0a3b723b 136static void save_config__(FILE *config_file, const struct sset *remotes,
60e0cd04
AZ
137 const struct sset *db_filenames,
138 const char *sync_from, const char *sync_exclude,
139 bool is_backup);
0a3b723b
BP
140static void save_config(struct server_config *);
141static void load_config(FILE *config_file, struct sset *remotes,
60e0cd04
AZ
142 struct sset *db_filenames, char **sync_from,
143 char **sync_exclude, bool *is_backup);
5f36127e 144
6ab3dd96 145static void
60e0cd04 146ovsdb_replication_init(const char *sync_from, const char *exclude,
05ac209a 147 struct shash *all_dbs, const struct uuid *server_uuid)
6ab3dd96 148{
05ac209a 149 replication_init(sync_from, exclude, server_uuid);
6ab3dd96
AZ
150 struct shash_node *node;
151 SHASH_FOR_EACH (node, all_dbs) {
152 struct db *db = node->data;
bc7bcc40
BP
153 if (node->name[0] != '_' && db->db) {
154 replication_add_local_db(node->name, db->db);
155 }
6ab3dd96
AZ
156 }
157}
158
513a3f64 159static void
1b1d2e6d
BP
160log_and_free_error(struct ovsdb_error *error)
161{
162 if (error) {
163 char *s = ovsdb_error_to_string_free(error);
164 VLOG_INFO("%s", s);
165 free(s);
166 }
167}
168
169static void
170main_loop(struct server_config *config,
171 struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
513a3f64 172 struct unixctl_server *unixctl, struct sset *remotes,
60e0cd04 173 struct process *run_process, bool *exiting, bool *is_backup)
513a3f64
ES
174{
175 char *remotes_error, *ssl_error;
176 struct shash_node *node;
177 long long int status_timer = LLONG_MIN;
178
179 *exiting = false;
180 ssl_error = NULL;
181 remotes_error = NULL;
182 while (!*exiting) {
183 memory_run();
184 if (memory_should_report()) {
185 struct simap usage;
186
187 simap_init(&usage);
188 ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
e0c73ed1 189 ovsdb_monitor_get_memory_usage(&usage);
513a3f64
ES
190 SHASH_FOR_EACH(node, all_dbs) {
191 struct db *db = node->data;
192 ovsdb_get_memory_usage(db->db, &usage);
193 }
194 memory_report(&usage);
195 simap_destroy(&usage);
196 }
197
198 /* Run unixctl_server_run() before reconfigure_remotes() because
199 * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
200 * the set of remotes that reconfigure_remotes() uses. */
201 unixctl_server_run(unixctl);
202
077f0302 203 ovsdb_jsonrpc_server_set_read_only(jsonrpc, *is_backup);
e51879e9 204
513a3f64
ES
205 report_error_if_changed(
206 reconfigure_remotes(jsonrpc, all_dbs, remotes),
207 &remotes_error);
208 report_error_if_changed(reconfigure_ssl(all_dbs), &ssl_error);
209 ovsdb_jsonrpc_server_run(jsonrpc);
210
60e0cd04 211 if (*is_backup) {
23c16b51
AZ
212 replication_run();
213 if (!replication_is_alive()) {
ac5d315c
AZ
214 disconnect_active_server();
215 *is_backup = false;
23c16b51 216 }
ae671c5f
MC
217 }
218
1b1d2e6d
BP
219 struct shash_node *next;
220 SHASH_FOR_EACH_SAFE (node, next, all_dbs) {
513a3f64 221 struct db *db = node->data;
695e8150 222 ovsdb_txn_history_run(db->db);
53178986 223 if (ovsdb_trigger_run(db->db, time_msec())) {
1b1d2e6d
BP
224 /* The message below is currently the only reason to disconnect
225 * all clients. */
226 ovsdb_jsonrpc_server_reconnect(
227 jsonrpc, false,
228 xasprintf("committed %s database schema conversion",
229 db->db->name));
230 }
231 ovsdb_storage_run(db->db->storage);
232 read_db(config, db);
233 if (ovsdb_storage_is_dead(db->db->storage)) {
234 VLOG_INFO("%s: removing database because storage disconnected "
235 "permanently", node->name);
236 remove_db(config, node,
237 xasprintf("removing database %s because storage "
238 "disconnected permanently", node->name));
239 } else if (ovsdb_storage_should_snapshot(db->db->storage)) {
240 log_and_free_error(ovsdb_snapshot(db->db));
53178986 241 }
513a3f64
ES
242 }
243 if (run_process) {
244 process_run();
245 if (process_exited(run_process)) {
246 *exiting = true;
247 }
248 }
249
ae671c5f 250 /* update Manager status(es) every 2.5 seconds */
513a3f64 251 if (time_msec() >= status_timer) {
ae671c5f 252 status_timer = time_msec() + 2500;
513a3f64
ES
253 update_remote_status(jsonrpc, remotes, all_dbs);
254 }
255
6bb9b060
BP
256 update_server_status(all_dbs);
257
513a3f64 258 memory_wait();
60e0cd04 259 if (*is_backup) {
8c945cec
AZ
260 replication_wait();
261 }
23c16b51 262
513a3f64
ES
263 ovsdb_jsonrpc_server_wait(jsonrpc);
264 unixctl_server_wait(unixctl);
265 SHASH_FOR_EACH(node, all_dbs) {
266 struct db *db = node->data;
267 ovsdb_trigger_wait(db->db, time_msec());
1b1d2e6d
BP
268 ovsdb_storage_wait(db->db->storage);
269 ovsdb_storage_read_wait(db->db->storage);
513a3f64
ES
270 }
271 if (run_process) {
272 process_wait(run_process);
273 }
274 if (*exiting) {
275 poll_immediate_wake();
276 }
277 poll_timer_wait_until(status_timer);
278 poll_block();
279 if (should_service_stop()) {
280 *exiting = true;
281 }
282 }
283
b396293a 284 free(remotes_error);
513a3f64
ES
285}
286
f85f8ebb
BP
287int
288main(int argc, char *argv[])
289{
aa78de9d 290 char *unixctl_path = NULL;
475afa1b 291 char *run_command = NULL;
f85f8ebb
BP
292 struct unixctl_server *unixctl;
293 struct ovsdb_jsonrpc_server *jsonrpc;
0a3b723b 294 struct sset remotes, db_filenames;
60e0cd04
AZ
295 char *sync_from, *sync_exclude;
296 bool is_backup;
0a3b723b 297 const char *db_filename;
475afa1b 298 struct process *run_process;
aa78de9d 299 bool exiting;
f85f8ebb 300 int retval;
5f36127e 301 FILE *config_tmpfile;
0a3b723b 302 struct server_config server_config;
eeb36a52 303 struct shash all_dbs;
03093a4f 304 struct shash_node *node, *next;
b4e8d170 305
5f383751 306 ovs_cmdl_proctitle_init(argc, argv);
f85f8ebb 307 set_program_name(argv[0]);
42dd41ef 308 service_start(&argc, &argv);
8a777cf6 309 fatal_ignore_sigpipe();
f85f8ebb
BP
310 process_init();
311
60e0cd04 312 bool active = false;
53178986
BP
313 parse_options(argc, argv, &db_filenames, &remotes, &unixctl_path,
314 &run_command, &sync_from, &sync_exclude, &active);
60e0cd04
AZ
315 is_backup = sync_from && !active;
316
e91b927d 317 daemon_become_new_user(false);
f85f8ebb 318
5f36127e
BP
319 /* Create and initialize 'config_tmpfile' as a temporary file to hold
320 * ovsdb-server's most basic configuration, and then save our initial
321 * configuration to it. When --monitor is used, this preserves the effects
322 * of ovs-appctl commands such as ovsdb-server/add-remote (which saves the
323 * new configuration) across crashes. */
324 config_tmpfile = tmpfile();
325 if (!config_tmpfile) {
326 ovs_fatal(errno, "failed to create temporary file");
327 }
0a3b723b 328
0a3b723b
BP
329 server_config.remotes = &remotes;
330 server_config.config_tmpfile = config_tmpfile;
331
60e0cd04
AZ
332 save_config__(config_tmpfile, &remotes, &db_filenames, sync_from,
333 sync_exclude, is_backup);
5f36127e 334
e91b927d 335 daemonize_start(false);
eb077b26 336
5f36127e 337 /* Load the saved config. */
60e0cd04
AZ
338 load_config(config_tmpfile, &remotes, &db_filenames, &sync_from,
339 &sync_exclude, &is_backup);
340
341 /* Start ovsdb jsonrpc server. When running as a backup server,
342 * jsonrpc connections are read only. Otherwise, both read
343 * and write transactions are allowed. */
344 jsonrpc = ovsdb_jsonrpc_server_create(is_backup);
eeb36a52 345
0a3b723b
BP
346 shash_init(&all_dbs);
347 server_config.all_dbs = &all_dbs;
348 server_config.jsonrpc = jsonrpc;
60e0cd04
AZ
349 server_config.sync_from = &sync_from;
350 server_config.sync_exclude = &sync_exclude;
351 server_config.is_backup = &is_backup;
7ef28119
WT
352
353 perf_counters_init();
354
0a3b723b 355 SSET_FOR_EACH (db_filename, &db_filenames) {
1b1d2e6d 356 struct ovsdb_error *error = open_db(&server_config, db_filename);
0a3b723b 357 if (error) {
1b1d2e6d
BP
358 char *s = ovsdb_error_to_string_free(error);
359 ovs_fatal(0, "%s", s);
0a3b723b 360 }
b4e8d170 361 }
6bb9b060 362 add_server_db(&server_config);
b4e8d170 363
1b1d2e6d 364 char *error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes);
0a3b723b
BP
365 if (!error) {
366 error = reconfigure_ssl(&all_dbs);
367 }
368 if (error) {
369 ovs_fatal(0, "%s", error);
370 }
f85f8ebb 371
aa78de9d 372 retval = unixctl_server_create(unixctl_path, &unixctl);
f85f8ebb 373 if (retval) {
4d12270a 374 exit(EXIT_FAILURE);
f85f8ebb
BP
375 }
376
475afa1b
BP
377 if (run_command) {
378 char *run_argv[4];
379
380 run_argv[0] = "/bin/sh";
381 run_argv[1] = "-c";
382 run_argv[2] = run_command;
383 run_argv[3] = NULL;
384
e1208bc4 385 retval = process_start(run_argv, &run_process);
475afa1b
BP
386 if (retval) {
387 ovs_fatal(retval, "%s: process failed to start", run_command);
388 }
389 } else {
390 run_process = NULL;
391 }
392
95440284 393 daemonize_complete();
aa78de9d 394
08b9b190
EJ
395 if (!run_command) {
396 /* ovsdb-server is usually a long-running process, in which case it
397 * makes plenty of sense to log the version, but --run makes
398 * ovsdb-server more like a command-line tool, so skip it. */
399 VLOG_INFO("%s (Open vSwitch) %s", program_name, VERSION);
400 }
9dbc190c 401
0e15264f 402 unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting);
b4e8d170 403 unixctl_command_register("ovsdb-server/compact", "", 0, 1,
eeb36a52 404 ovsdb_server_compact, &all_dbs);
0e15264f 405 unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
7ff2009a 406 ovsdb_server_reconnect, jsonrpc);
aa78de9d 407
b421d2af 408 unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1,
0a3b723b 409 ovsdb_server_add_remote, &server_config);
b421d2af 410 unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1,
0a3b723b 411 ovsdb_server_remove_remote, &server_config);
b421d2af
BP
412 unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0,
413 ovsdb_server_list_remotes, &remotes);
414
0a3b723b
BP
415 unixctl_command_register("ovsdb-server/add-db", "DB", 1, 1,
416 ovsdb_server_add_database, &server_config);
417 unixctl_command_register("ovsdb-server/remove-db", "DB", 1, 1,
418 ovsdb_server_remove_database, &server_config);
419 unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
420 ovsdb_server_list_databases, &all_dbs);
97a3c435
AZ
421 unixctl_command_register("ovsdb-server/perf-counters-show", "", 0, 0,
422 ovsdb_server_perf_counters_show, NULL);
423 unixctl_command_register("ovsdb-server/perf-counters-clear", "", 0, 0,
424 ovsdb_server_perf_counters_clear, NULL);
60e0cd04
AZ
425 unixctl_command_register("ovsdb-server/set-active-ovsdb-server", "", 1, 1,
426 ovsdb_server_set_active_ovsdb_server,
427 &server_config);
f53d7518 428 unixctl_command_register("ovsdb-server/get-active-ovsdb-server", "", 0, 0,
60e0cd04
AZ
429 ovsdb_server_get_active_ovsdb_server,
430 &server_config);
e51879e9
AZ
431 unixctl_command_register("ovsdb-server/connect-active-ovsdb-server", "",
432 0, 0, ovsdb_server_connect_active_ovsdb_server,
60e0cd04 433 &server_config);
e51879e9
AZ
434 unixctl_command_register("ovsdb-server/disconnect-active-ovsdb-server", "",
435 0, 0, ovsdb_server_disconnect_active_ovsdb_server,
60e0cd04
AZ
436 &server_config);
437 unixctl_command_register("ovsdb-server/set-sync-exclude-tables", "",
438 0, 1, ovsdb_server_set_sync_exclude_tables,
439 &server_config);
440 unixctl_command_register("ovsdb-server/get-sync-exclude-tables", "",
441 0, 0, ovsdb_server_get_sync_exclude_tables,
e51879e9 442 NULL);
60e0cd04
AZ
443 unixctl_command_register("ovsdb-server/sync-status", "",
444 0, 0, ovsdb_server_get_sync_status,
445 &server_config);
9dc05cdc 446
e47cb14c 447 /* Simulate the behavior of OVS release prior to version 2.5 that
c383f3bf
LS
448 * does not support the monitor_cond method. */
449 unixctl_command_register("ovsdb-server/disable-monitor-cond", "", 0, 0,
450 ovsdb_server_disable_monitor_cond, jsonrpc);
e47cb14c 451
60e0cd04 452 if (is_backup) {
05ac209a
AZ
453 const struct uuid *server_uuid;
454 server_uuid = ovsdb_jsonrpc_server_get_uuid(jsonrpc);
455 ovsdb_replication_init(sync_from, sync_exclude, &all_dbs, server_uuid);
6ab3dd96
AZ
456 }
457
1b1d2e6d
BP
458 main_loop(&server_config, jsonrpc, &all_dbs, unixctl, &remotes,
459 run_process, &exiting, &is_backup);
0d085684 460
03093a4f 461 SHASH_FOR_EACH_SAFE(node, next, &all_dbs) {
eeb36a52 462 struct db *db = node->data;
aa02ac64 463 close_db(&server_config, db, NULL);
03093a4f 464 shash_delete(&all_dbs, node);
b4e8d170 465 }
1b1d2e6d 466 ovsdb_jsonrpc_server_destroy(jsonrpc);
d557df96 467 shash_destroy(&all_dbs);
b3c01ed3 468 sset_destroy(&remotes);
03093a4f 469 sset_destroy(&db_filenames);
60e0cd04
AZ
470 free(sync_from);
471 free(sync_exclude);
23935e8b 472 unixctl_server_destroy(unixctl);
3109b4e1 473 replication_destroy();
f85f8ebb 474
475afa1b
BP
475 if (run_process && process_exited(run_process)) {
476 int status = process_status(run_process);
477 if (status) {
478 ovs_fatal(0, "%s: child exited, %s",
479 run_command, process_status_msg(status));
480 }
481 }
97a3c435 482 perf_counters_destroy();
42dd41ef 483 service_stop();
f85f8ebb
BP
484 return 0;
485}
486
ebed9f78
BP
487/* Returns true if 'filename' is known to be already open as a database,
488 * false if not.
489 *
490 * "False negatives" are possible. */
491static bool
492is_already_open(struct server_config *config OVS_UNUSED,
493 const char *filename OVS_UNUSED)
494{
495#ifndef _WIN32
496 struct stat s;
497
498 if (!stat(filename, &s)) {
499 struct shash_node *node;
500
501 SHASH_FOR_EACH (node, config->all_dbs) {
502 struct db *db = node->data;
503 struct stat s2;
504
505 if (!stat(db->filename, &s2)
506 && s.st_dev == s2.st_dev
507 && s.st_ino == s2.st_ino) {
508 return true;
509 }
510 }
511 }
512#endif /* !_WIN32 */
513
514 return false;
515}
516
03093a4f 517static void
1b1d2e6d
BP
518close_db(struct server_config *config, struct db *db, char *comment)
519{
520 if (db) {
521 ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db, comment);
522 ovsdb_destroy(db->db);
523 free(db->filename);
524 free(db);
525 } else {
526 free(comment);
527 }
528}
529
530static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
531parse_txn(struct server_config *config, struct db *db,
532 struct ovsdb_schema *schema, const struct json *txn_json,
533 const struct uuid *txnid)
534{
535 if (schema) {
536 /* We're replacing the schema (and the data). Destroy the database
537 * (first grabbing its storage), then replace it with the new schema.
538 * The transaction must also include the replacement data.
539 *
540 * Only clustered database schema changes go through this path. */
541 ovs_assert(txn_json);
542 ovs_assert(ovsdb_storage_is_clustered(db->db->storage));
543
544 struct ovsdb_error *error = ovsdb_schema_check_for_ephemeral_columns(
545 schema);
546 if (error) {
547 return error;
548 }
549
550 ovsdb_jsonrpc_server_reconnect(
551 config->jsonrpc, false,
552 (db->db->schema
553 ? xasprintf("database %s schema changed", db->db->name)
554 : xasprintf("database %s connected to storage", db->db->name)));
555
556 ovsdb_replace(db->db, ovsdb_create(schema, NULL));
557
558 /* Force update to schema in _Server database. */
559 db->row_uuid = UUID_ZERO;
560 }
561
562 if (txn_json) {
563 if (!db->db->schema) {
564 return ovsdb_error(NULL, "%s: data without schema", db->filename);
565 }
566
567 struct ovsdb_txn *txn;
568 struct ovsdb_error *error;
569
570 error = ovsdb_file_txn_from_json(db->db, txn_json, false, &txn);
571 if (!error) {
695e8150 572 ovsdb_txn_set_txnid(txnid, txn);
1b1d2e6d
BP
573 log_and_free_error(ovsdb_txn_replay_commit(txn));
574 }
575 if (!error && !uuid_is_zero(txnid)) {
576 db->db->prereq = *txnid;
577 }
578 if (error) {
579 ovsdb_storage_unread(db->db->storage);
580 return error;
581 }
582 }
583
584 return NULL;
585}
586
587static void
588read_db(struct server_config *config, struct db *db)
03093a4f 589{
1b1d2e6d
BP
590 struct ovsdb_error *error;
591 for (;;) {
592 struct ovsdb_schema *schema;
593 struct json *txn_json;
594 struct uuid txnid;
595 error = ovsdb_storage_read(db->db->storage, &schema, &txn_json,
596 &txnid);
597 if (error) {
598 break;
599 } else if (!schema && !txn_json) {
600 /* End of file. */
601 return;
602 } else {
603 error = parse_txn(config, db, schema, txn_json, &txnid);
604 json_destroy(txn_json);
605 if (error) {
606 break;
607 }
608 }
609 }
610
611 /* Log error but otherwise ignore it. Probably the database just
612 * got truncated due to power failure etc. and we should use its
613 * current contents. */
614 char *msg = ovsdb_error_to_string_free(error);
615 VLOG_ERR("%s", msg);
616 free(msg);
03093a4f
RW
617}
618
6bb9b060 619static void
1b1d2e6d 620add_db(struct server_config *config, struct db *db)
6bb9b060
BP
621{
622 db->row_uuid = UUID_ZERO;
1b1d2e6d 623 shash_add_assert(config->all_dbs, db->db->name, db);
6bb9b060
BP
624}
625
1b1d2e6d 626static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
0a3b723b 627open_db(struct server_config *config, const char *filename)
eeb36a52 628{
0a3b723b 629 struct db *db;
eeb36a52 630
ebed9f78
BP
631 /* If we know that the file is already open, return a good error message.
632 * Otherwise, if the file is open, we'll fail later on with a harder to
633 * interpret file locking error. */
634 if (is_already_open(config, filename)) {
1b1d2e6d
BP
635 return ovsdb_error(NULL, "%s: already open", filename);
636 }
637
638 struct ovsdb_storage *storage;
639 struct ovsdb_error *error;
640 error = ovsdb_storage_open(filename, true, &storage);
641 if (error) {
642 return error;
ebed9f78
BP
643 }
644
0a3b723b
BP
645 db = xzalloc(sizeof *db);
646 db->filename = xstrdup(filename);
eeb36a52 647
1b1d2e6d
BP
648 struct ovsdb_schema *schema;
649 if (ovsdb_storage_is_clustered(storage)) {
650 schema = NULL;
0a3b723b 651 } else {
1b1d2e6d
BP
652 struct json *txn_json;
653 error = ovsdb_storage_read(storage, &schema, &txn_json, NULL);
654 if (error) {
655 ovsdb_storage_close(storage);
656 return error;
657 }
658 ovs_assert(schema && !txn_json);
eeb36a52 659 }
1b1d2e6d
BP
660 db->db = ovsdb_create(schema, storage);
661 ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db);
eeb36a52 662
695e8150
HZ
663 /* Enable txn history for clustered mode. It is not enabled for other mode
664 * for now, since txn id is available for clustered mode only. */
665 if (ovsdb_storage_is_clustered(storage)) {
666 ovsdb_txn_history_init(db->db);
667 }
1b1d2e6d
BP
668 read_db(config, db);
669
670 error = (db->db->name[0] == '_'
671 ? ovsdb_error(NULL, "%s: names beginning with \"_\" are reserved",
672 db->db->name)
673 : shash_find(config->all_dbs, db->db->name)
674 ? ovsdb_error(NULL, "%s: duplicate database name", db->db->name)
675 : NULL);
676 if (error) {
677 char *error_s = ovsdb_error_to_string(error);
678 close_db(config, db,
679 xasprintf("cannot complete opening %s database (%s)",
680 db->db->name, error_s));
681 free(error_s);
682 return error;
683 }
684
685 add_db(config, db);
686 return NULL;
eeb36a52
GS
687}
688
6bb9b060
BP
689/* Add the internal _Server database to the server configuration. */
690static void
691add_server_db(struct server_config *config)
692{
693 struct json *schema_json = json_from_string(
694#include "ovsdb/_server.ovsschema.inc"
695 );
696 ovs_assert(schema_json->type == JSON_OBJECT);
697
698 struct ovsdb_schema *schema;
699 struct ovsdb_error *error OVS_UNUSED = ovsdb_schema_from_json(schema_json,
700 &schema);
701 ovs_assert(!error);
702 json_destroy(schema_json);
703
704 struct db *db = xzalloc(sizeof *db);
695e8150
HZ
705 /* We don't need txn_history for server_db. */
706
6bb9b060 707 db->filename = xstrdup("<internal>");
1b1d2e6d
BP
708 db->db = ovsdb_create(schema, ovsdb_storage_create_unbacked());
709 bool ok OVS_UNUSED = ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db);
710 ovs_assert(ok);
711 add_db(config, db);
6bb9b060
BP
712}
713
cab50449 714static char * OVS_WARN_UNUSED_RESULT
eeb36a52 715parse_db_column__(const struct shash *all_dbs,
c02cf07b
BP
716 const char *name_, char *name,
717 const struct db **dbp,
718 const struct ovsdb_table **tablep,
719 const struct ovsdb_column **columnp)
0b1fae1b 720{
fb6de52c 721 const char *db_name, *table_name, *column_name;
b4e8d170 722 const char *tokens[3];
0b1fae1b
BP
723 char *save_ptr = NULL;
724
c02cf07b
BP
725 *dbp = NULL;
726 *tablep = NULL;
727 *columnp = NULL;
728
b0ef0551 729 strtok_r(name, ":", &save_ptr); /* "db:" */
b4e8d170
BP
730 tokens[0] = strtok_r(NULL, ",", &save_ptr);
731 tokens[1] = strtok_r(NULL, ",", &save_ptr);
732 tokens[2] = strtok_r(NULL, ",", &save_ptr);
fb6de52c 733 if (!tokens[0] || !tokens[1] || !tokens[2]) {
c02cf07b 734 return xasprintf("\"%s\": invalid syntax", name_);
0b1fae1b 735 }
b4e8d170 736
fb6de52c
GS
737 db_name = tokens[0];
738 table_name = tokens[1];
739 column_name = tokens[2];
740
1b1d2e6d
BP
741 *dbp = shash_find_data(all_dbs, tokens[0]);
742 if (!*dbp) {
fb6de52c 743 return xasprintf("\"%s\": no database named %s", name_, db_name);
b4e8d170 744 }
0b1fae1b 745
1b1d2e6d
BP
746 *tablep = ovsdb_get_table((*dbp)->db, table_name);
747 if (!*tablep) {
c02cf07b 748 return xasprintf("\"%s\": no table named %s", name_, table_name);
0b1fae1b
BP
749 }
750
1b1d2e6d
BP
751 *columnp = ovsdb_table_schema_get_column((*tablep)->schema, column_name);
752 if (!*columnp) {
c02cf07b
BP
753 return xasprintf("\"%s\": table \"%s\" has no column \"%s\"",
754 name_, table_name, column_name);
0b1fae1b
BP
755 }
756
c02cf07b 757 return NULL;
94db5407
BP
758}
759
c02cf07b
BP
760/* Returns NULL if successful, otherwise a malloc()'d string describing the
761 * error. */
cab50449 762static char * OVS_WARN_UNUSED_RESULT
eeb36a52 763parse_db_column(const struct shash *all_dbs,
c02cf07b
BP
764 const char *name_,
765 const struct db **dbp,
766 const struct ovsdb_table **tablep,
767 const struct ovsdb_column **columnp)
768{
769 char *name = xstrdup(name_);
eeb36a52 770 char *retval = parse_db_column__(all_dbs, name_, name,
c02cf07b
BP
771 dbp, tablep, columnp);
772 free(name);
773 return retval;
774}
775
776/* Returns NULL if successful, otherwise a malloc()'d string describing the
777 * error. */
cab50449 778static char * OVS_WARN_UNUSED_RESULT
eeb36a52 779parse_db_string_column(const struct shash *all_dbs,
94db5407 780 const char *name,
b4e8d170 781 const struct db **dbp,
94db5407
BP
782 const struct ovsdb_table **tablep,
783 const struct ovsdb_column **columnp)
784{
c02cf07b 785 char *retval;
94db5407 786
eeb36a52 787 retval = parse_db_column(all_dbs, name, dbp, tablep, columnp);
c02cf07b
BP
788 if (retval) {
789 return retval;
790 }
94db5407 791
c02cf07b
BP
792 if ((*columnp)->type.key.type != OVSDB_TYPE_STRING
793 || (*columnp)->type.value.type != OVSDB_TYPE_VOID) {
794 return xasprintf("\"%s\": table \"%s\" column \"%s\" is "
795 "not string or set of strings",
796 name, (*tablep)->schema->name, (*columnp)->name);
78876719
BP
797 }
798
c02cf07b 799 return NULL;
78876719
BP
800}
801
0a3b723b
BP
802static const char *
803query_db_string(const struct shash *all_dbs, const char *name,
804 struct ds *errors)
78876719
BP
805{
806 if (!name || strncmp(name, "db:", 3)) {
807 return name;
808 } else {
809 const struct ovsdb_column *column;
810 const struct ovsdb_table *table;
811 const struct ovsdb_row *row;
b4e8d170 812 const struct db *db;
c02cf07b 813 char *retval;
78876719 814
eeb36a52 815 retval = parse_db_string_column(all_dbs, name,
c02cf07b
BP
816 &db, &table, &column);
817 if (retval) {
1b1d2e6d
BP
818 if (db && !db->db->schema) {
819 /* 'db' is a clustered database but it hasn't connected to the
820 * cluster yet, so we can't get anything out of it, not even a
821 * schema. Not really an error. */
822 } else {
823 ds_put_format(errors, "%s\n", retval);
824 }
0ded15d4 825 free(retval);
0a3b723b 826 return NULL;
c02cf07b 827 }
78876719 828
4e8e4213 829 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
78876719
BP
830 const struct ovsdb_datum *datum;
831 size_t i;
832
833 datum = &row->fields[column->index];
834 for (i = 0; i < datum->n; i++) {
835 if (datum->keys[i].string[0]) {
836 return datum->keys[i].string;
837 }
838 }
839 }
840 return NULL;
0b1fae1b 841 }
78876719
BP
842}
843
94db5407
BP
844static struct ovsdb_jsonrpc_options *
845add_remote(struct shash *remotes, const char *target)
846{
847 struct ovsdb_jsonrpc_options *options;
848
849 options = shash_find_data(remotes, target);
850 if (!options) {
f1936eb6 851 options = ovsdb_jsonrpc_default_options(target);
94db5407
BP
852 shash_add(remotes, target, options);
853 }
854
855 return options;
856}
857
ed9d4380
YS
858static void
859free_remotes(struct shash *remotes)
860{
861 if (remotes) {
862 struct shash_node *node;
863
864 SHASH_FOR_EACH (node, remotes) {
865 struct ovsdb_jsonrpc_options *options = node->data;
866 free(options->role);
867 }
868 shash_destroy_free_data(remotes);
869 }
870}
871
94db5407
BP
872/* Adds a remote and options to 'remotes', based on the Manager table row in
873 * 'row'. */
874static void
875add_manager_options(struct shash *remotes, const struct ovsdb_row *row)
876{
877 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
878 struct ovsdb_jsonrpc_options *options;
879 long long int max_backoff, probe_interval;
9c1a1182 880 bool read_only;
d6db7b3c 881 const char *target, *dscp_string, *role;
94db5407 882
40e66ba7 883 if (!ovsdb_util_read_string_column(row, "target", &target) || !target) {
94db5407
BP
884 VLOG_INFO_RL(&rl, "Table `%s' has missing or invalid `target' column",
885 row->table->schema->name);
886 return;
887 }
888
889 options = add_remote(remotes, target);
40e66ba7 890 if (ovsdb_util_read_integer_column(row, "max_backoff", &max_backoff)) {
94db5407
BP
891 options->max_backoff = max_backoff;
892 }
40e66ba7
LR
893 if (ovsdb_util_read_integer_column(row, "inactivity_probe",
894 &probe_interval)) {
94db5407
BP
895 options->probe_interval = probe_interval;
896 }
40e66ba7 897 if (ovsdb_util_read_bool_column(row, "read_only", &read_only)) {
9c1a1182
LR
898 options->read_only = read_only;
899 }
f125905c 900
d6db7b3c
LR
901 free(options->role);
902 options->role = NULL;
903 if (ovsdb_util_read_string_column(row, "role", &role) && role) {
904 options->role = xstrdup(role);
905 }
906
cea15768 907 options->dscp = DSCP_DEFAULT;
40e66ba7
LR
908 dscp_string = ovsdb_util_read_map_string_column(row, "other_config",
909 "dscp");
cea15768
EJ
910 if (dscp_string) {
911 int dscp = atoi(dscp_string);
912 if (dscp >= 0 && dscp <= 63) {
913 options->dscp = dscp;
914 }
915 }
94db5407
BP
916}
917
78876719 918static void
eeb36a52 919query_db_remotes(const char *name, const struct shash *all_dbs,
0a3b723b 920 struct shash *remotes, struct ds *errors)
78876719
BP
921{
922 const struct ovsdb_column *column;
923 const struct ovsdb_table *table;
924 const struct ovsdb_row *row;
b4e8d170 925 const struct db *db;
c02cf07b 926 char *retval;
78876719 927
eeb36a52 928 retval = parse_db_column(all_dbs, name, &db, &table, &column);
c02cf07b 929 if (retval) {
1b1d2e6d
BP
930 if (db && !db->db->schema) {
931 /* 'db' is a clustered database but it hasn't connected to the
932 * cluster yet, so we can't get anything out of it, not even a
933 * schema. Not really an error. */
934 } else {
935 ds_put_format(errors, "%s\n", retval);
936 }
0a3b723b
BP
937 free(retval);
938 return;
c02cf07b 939 }
0b1fae1b 940
94db5407
BP
941 if (column->type.key.type == OVSDB_TYPE_STRING
942 && column->type.value.type == OVSDB_TYPE_VOID) {
943 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
944 const struct ovsdb_datum *datum;
945 size_t i;
946
947 datum = &row->fields[column->index];
948 for (i = 0; i < datum->n; i++) {
949 add_remote(remotes, datum->keys[i].string);
950 }
951 }
952 } else if (column->type.key.type == OVSDB_TYPE_UUID
fa37affa 953 && column->type.key.uuid.refTable
94db5407 954 && column->type.value.type == OVSDB_TYPE_VOID) {
fa37affa 955 const struct ovsdb_table *ref_table = column->type.key.uuid.refTable;
94db5407
BP
956 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
957 const struct ovsdb_datum *datum;
958 size_t i;
959
960 datum = &row->fields[column->index];
961 for (i = 0; i < datum->n; i++) {
962 const struct ovsdb_row *ref_row;
0b1fae1b 963
94db5407
BP
964 ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
965 if (ref_row) {
966 add_manager_options(remotes, ref_row);
967 }
968 }
0b1fae1b
BP
969 }
970 }
971}
972
0b3e7a8b
AE
973static void
974update_remote_row(const struct ovsdb_row *row, struct ovsdb_txn *txn,
87fcbc60 975 const struct ovsdb_jsonrpc_server *jsonrpc)
0b3e7a8b 976{
87fcbc60 977 struct ovsdb_jsonrpc_remote_status status;
0b3e7a8b
AE
978 struct ovsdb_row *rw_row;
979 const char *target;
798e1352 980 char *keys[9], *values[9];
0b3e7a8b
AE
981 size_t n = 0;
982
983 /* Get the "target" (protocol/host/port) spec. */
40e66ba7 984 if (!ovsdb_util_read_string_column(row, "target", &target)) {
0b3e7a8b
AE
985 /* Bad remote spec or incorrect schema. */
986 return;
987 }
0b3e7a8b 988 rw_row = ovsdb_txn_row_modify(txn, row);
87fcbc60 989 ovsdb_jsonrpc_server_get_remote_status(jsonrpc, target, &status);
0b3e7a8b
AE
990
991 /* Update status information columns. */
40e66ba7 992 ovsdb_util_write_bool_column(rw_row, "is_connected", status.is_connected);
0b3e7a8b 993
87fcbc60
BP
994 if (status.state) {
995 keys[n] = xstrdup("state");
996 values[n++] = xstrdup(status.state);
997 }
998 if (status.sec_since_connect != UINT_MAX) {
5eda645e 999 keys[n] = xstrdup("sec_since_connect");
87fcbc60 1000 values[n++] = xasprintf("%u", status.sec_since_connect);
5eda645e 1001 }
87fcbc60 1002 if (status.sec_since_disconnect != UINT_MAX) {
5eda645e 1003 keys[n] = xstrdup("sec_since_disconnect");
87fcbc60 1004 values[n++] = xasprintf("%u", status.sec_since_disconnect);
5eda645e 1005 }
87fcbc60 1006 if (status.last_error) {
0b3e7a8b
AE
1007 keys[n] = xstrdup("last_error");
1008 values[n++] =
87fcbc60 1009 xstrdup(ovs_retval_to_string(status.last_error));
0b3e7a8b 1010 }
da897f41
BP
1011 if (status.locks_held && status.locks_held[0]) {
1012 keys[n] = xstrdup("locks_held");
1013 values[n++] = xstrdup(status.locks_held);
1014 }
1015 if (status.locks_waiting && status.locks_waiting[0]) {
1016 keys[n] = xstrdup("locks_waiting");
1017 values[n++] = xstrdup(status.locks_waiting);
1018 }
1019 if (status.locks_lost && status.locks_lost[0]) {
1020 keys[n] = xstrdup("locks_lost");
1021 values[n++] = xstrdup(status.locks_lost);
1022 }
a11f6164
BP
1023 if (status.n_connections > 1) {
1024 keys[n] = xstrdup("n_connections");
1025 values[n++] = xasprintf("%d", status.n_connections);
1026 }
798e1352
BP
1027 if (status.bound_port != htons(0)) {
1028 keys[n] = xstrdup("bound_port");
1029 values[n++] = xasprintf("%"PRIu16, ntohs(status.bound_port));
1030 }
40e66ba7 1031 ovsdb_util_write_string_string_column(rw_row, "status", keys, values, n);
da897f41
BP
1032
1033 ovsdb_jsonrpc_server_free_remote_status(&status);
0b3e7a8b
AE
1034}
1035
1036static void
99b09c63 1037update_remote_rows(const struct shash *all_dbs, const struct db *db_,
87fcbc60 1038 const char *remote_name,
99b09c63
BP
1039 const struct ovsdb_jsonrpc_server *jsonrpc,
1040 struct ovsdb_txn *txn)
0b3e7a8b
AE
1041{
1042 const struct ovsdb_table *table, *ref_table;
1043 const struct ovsdb_column *column;
1044 const struct ovsdb_row *row;
b4e8d170 1045 const struct db *db;
c02cf07b 1046 char *retval;
0b3e7a8b
AE
1047
1048 if (strncmp("db:", remote_name, 3)) {
1049 return;
1050 }
1051
eeb36a52 1052 retval = parse_db_column(all_dbs, remote_name, &db, &table, &column);
c02cf07b 1053 if (retval) {
0a3b723b
BP
1054 free(retval);
1055 return;
c02cf07b 1056 }
0b3e7a8b 1057
99b09c63
BP
1058 if (db != db_
1059 || column->type.key.type != OVSDB_TYPE_UUID
fa37affa 1060 || !column->type.key.uuid.refTable
0b3e7a8b
AE
1061 || column->type.value.type != OVSDB_TYPE_VOID) {
1062 return;
1063 }
1064
fa37affa 1065 ref_table = column->type.key.uuid.refTable;
0b3e7a8b
AE
1066
1067 HMAP_FOR_EACH (row, hmap_node, &table->rows) {
1068 const struct ovsdb_datum *datum;
1069 size_t i;
1070
1071 datum = &row->fields[column->index];
1072 for (i = 0; i < datum->n; i++) {
1073 const struct ovsdb_row *ref_row;
1074
1075 ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
1076 if (ref_row) {
99b09c63 1077 update_remote_row(ref_row, txn, jsonrpc);
0b3e7a8b
AE
1078 }
1079 }
1080 }
1081}
1082
6bb9b060
BP
1083static void
1084commit_txn(struct ovsdb_txn *txn, const char *name)
1085{
1b1d2e6d 1086 struct ovsdb_error *error = ovsdb_txn_propose_commit_block(txn, false);
6bb9b060
BP
1087 if (error) {
1088 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
1089 char *msg = ovsdb_error_to_string_free(error);
1090 VLOG_ERR_RL(&rl, "Failed to update %s: %s", name, msg);
1091 free(msg);
1092 }
1093}
1094
0b3e7a8b
AE
1095static void
1096update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
b4e8d170 1097 const struct sset *remotes,
eeb36a52 1098 struct shash *all_dbs)
0b3e7a8b 1099{
eeb36a52 1100 struct shash_node *node;
99b09c63
BP
1101 SHASH_FOR_EACH (node, all_dbs) {
1102 struct db *db = node->data;
1b1d2e6d
BP
1103 if (!db->db || ovsdb_storage_is_clustered(db->db->storage)) {
1104 continue;
1105 }
0b3e7a8b 1106
1b1d2e6d 1107 struct ovsdb_txn *txn = ovsdb_txn_create(db->db);
99b09c63
BP
1108 const char *remote;
1109 SSET_FOR_EACH (remote, remotes) {
1110 update_remote_rows(all_dbs, db, remote, jsonrpc, txn);
1111 }
1b1d2e6d 1112 commit_txn(txn, "remote status");
6bb9b060
BP
1113 }
1114}
1115
1116/* Updates 'row', a row in the _Server database's Database table, to match
1117 * 'db'. */
1118static void
1119update_database_status(struct ovsdb_row *row, struct db *db)
1120{
1b1d2e6d
BP
1121 ovsdb_util_write_string_column(row, "name", db->db->name);
1122 ovsdb_util_write_string_column(row, "model",
1123 ovsdb_storage_get_model(db->db->storage));
1124 ovsdb_util_write_bool_column(row, "connected",
1125 ovsdb_storage_is_connected(db->db->storage));
1126 ovsdb_util_write_bool_column(row, "leader",
1127 ovsdb_storage_is_leader(db->db->storage));
1128 ovsdb_util_write_uuid_column(row, "cid",
1129 ovsdb_storage_get_cid(db->db->storage));
1130 ovsdb_util_write_uuid_column(row, "sid",
1131 ovsdb_storage_get_sid(db->db->storage));
1132
1133 uint64_t index = ovsdb_storage_get_applied_index(db->db->storage);
1134 if (index) {
1135 ovsdb_util_write_integer_column(row, "index", index);
1136 } else {
1137 ovsdb_util_clear_column(row, "index");
1138 }
6bb9b060
BP
1139
1140 const struct uuid *row_uuid = ovsdb_row_get_uuid(row);
1141 if (!uuid_equals(row_uuid, &db->row_uuid)) {
1142 db->row_uuid = *row_uuid;
1143
1144 /* The schema can only change if the row UUID changes, so only update
1145 * it in that case. Presumably, this is worth optimizing because
1146 * schemas are often kilobytes in size and nontrivial to serialize. */
1b1d2e6d
BP
1147 char *schema = NULL;
1148 if (db->db->schema) {
1149 struct json *json_schema = ovsdb_schema_to_json(db->db->schema);
1150 schema = json_to_string(json_schema, JSSF_SORT);
1151 json_destroy(json_schema);
1152 }
6bb9b060
BP
1153 ovsdb_util_write_string_column(row, "schema", schema);
1154 free(schema);
6bb9b060
BP
1155 }
1156}
1157
1158/* Updates the Database table in the _Server database. */
1159static void
1160update_server_status(struct shash *all_dbs)
1161{
1162 struct db *server_db = shash_find_data(all_dbs, "_Server");
1163 struct ovsdb_table *database_table = shash_find_data(
1164 &server_db->db->tables, "Database");
1165 struct ovsdb_txn *txn = ovsdb_txn_create(server_db->db);
1166
1167 /* Update rows for databases that still exist.
1168 * Delete rows for databases that no longer exist. */
1169 const struct ovsdb_row *row, *next_row;
1170 HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &database_table->rows) {
1171 const char *name;
1172 ovsdb_util_read_string_column(row, "name", &name);
1173 struct db *db = shash_find_data(all_dbs, name);
1174 if (!db || !db->db) {
1175 ovsdb_txn_row_delete(txn, row);
1176 } else {
1177 update_database_status(ovsdb_txn_row_modify(txn, row), db);
b4e8d170 1178 }
0b3e7a8b 1179 }
6bb9b060
BP
1180
1181 /* Add rows for new databases.
1182 *
1183 * This is O(n**2) but usually there are only 2 or 3 databases. */
1184 struct shash_node *node;
1185 SHASH_FOR_EACH (node, all_dbs) {
1186 struct db *db = node->data;
1187
1188 if (!db->db) {
1189 continue;
1190 }
1191
1192 HMAP_FOR_EACH (row, hmap_node, &database_table->rows) {
1193 const char *name;
1194 ovsdb_util_read_string_column(row, "name", &name);
1195 if (!strcmp(name, node->name)) {
1196 goto next;
1197 }
1198 }
1199
1200 /* Add row. */
1b1d2e6d
BP
1201 struct ovsdb_row *new_row = ovsdb_row_create(database_table);
1202 uuid_generate(ovsdb_row_get_uuid_rw(new_row));
1203 update_database_status(new_row, db);
1204 ovsdb_txn_row_insert(txn, new_row);
6bb9b060
BP
1205
1206 next:;
1207 }
1208
1209 commit_txn(txn, "_Server");
0b3e7a8b
AE
1210}
1211
0a3b723b
BP
1212/* Reconfigures ovsdb-server's remotes based on information in the database. */
1213static char *
1214reconfigure_remotes(struct ovsdb_jsonrpc_server *jsonrpc,
eeb36a52 1215 const struct shash *all_dbs, struct sset *remotes)
0b1fae1b 1216{
0a3b723b 1217 struct ds errors = DS_EMPTY_INITIALIZER;
0b1fae1b 1218 struct shash resolved_remotes;
b3c01ed3 1219 const char *name;
0b1fae1b 1220
78876719 1221 /* Configure remotes. */
0b1fae1b 1222 shash_init(&resolved_remotes);
b3c01ed3 1223 SSET_FOR_EACH (name, remotes) {
0b1fae1b 1224 if (!strncmp(name, "db:", 3)) {
0a3b723b 1225 query_db_remotes(name, all_dbs, &resolved_remotes, &errors);
0b1fae1b 1226 } else {
94db5407 1227 add_remote(&resolved_remotes, name);
0b1fae1b
BP
1228 }
1229 }
1230 ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
ed9d4380 1231 free_remotes(&resolved_remotes);
0b1fae1b 1232
0a3b723b
BP
1233 return errors.string;
1234}
1235
1236static char *
1237reconfigure_ssl(const struct shash *all_dbs)
1238{
1239 struct ds errors = DS_EMPTY_INITIALIZER;
1240 const char *resolved_private_key;
1241 const char *resolved_certificate;
1242 const char *resolved_ca_cert;
e18a1d08
ER
1243 const char *resolved_ssl_protocols;
1244 const char *resolved_ssl_ciphers;
0a3b723b
BP
1245
1246 resolved_private_key = query_db_string(all_dbs, private_key_file, &errors);
1247 resolved_certificate = query_db_string(all_dbs, certificate_file, &errors);
1248 resolved_ca_cert = query_db_string(all_dbs, ca_cert_file, &errors);
e18a1d08
ER
1249 resolved_ssl_protocols = query_db_string(all_dbs, ssl_protocols, &errors);
1250 resolved_ssl_ciphers = query_db_string(all_dbs, ssl_ciphers, &errors);
0a3b723b
BP
1251
1252 stream_ssl_set_key_and_cert(resolved_private_key, resolved_certificate);
1253 stream_ssl_set_ca_cert_file(resolved_ca_cert, bootstrap_ca_cert);
e18a1d08
ER
1254 stream_ssl_set_protocols(resolved_ssl_protocols);
1255 stream_ssl_set_ciphers(resolved_ssl_ciphers);
0a3b723b
BP
1256
1257 return errors.string;
1258}
1259
1260static void
1261report_error_if_changed(char *error, char **last_errorp)
1262{
1263 if (error) {
1264 if (!*last_errorp || strcmp(error, *last_errorp)) {
1265 VLOG_WARN("%s", error);
1266 free(*last_errorp);
1267 *last_errorp = error;
1268 return;
1269 }
1270 free(error);
1271 } else {
1272 free(*last_errorp);
1273 *last_errorp = NULL;
1274 }
78876719 1275}
0b1fae1b 1276
9dc05cdc 1277static void
f53d7518 1278ovsdb_server_set_active_ovsdb_server(struct unixctl_conn *conn,
9dc05cdc 1279 int argc OVS_UNUSED, const char *argv[],
60e0cd04 1280 void *config_)
9dc05cdc 1281{
60e0cd04
AZ
1282 struct server_config *config = config_;
1283
1284 if (*config->sync_from) {
1285 free(*config->sync_from);
1286 }
1287 *config->sync_from = xstrdup(argv[1]);
1288 save_config(config);
1289
9dc05cdc
MC
1290 unixctl_command_reply(conn, NULL);
1291}
1292
1293static void
f53d7518 1294ovsdb_server_get_active_ovsdb_server(struct unixctl_conn *conn,
9dc05cdc
MC
1295 int argc OVS_UNUSED,
1296 const char *argv[] OVS_UNUSED,
60e0cd04 1297 void *config_ )
9dc05cdc 1298{
60e0cd04
AZ
1299 struct server_config *config = config_;
1300
1301 unixctl_command_reply(conn, *config->sync_from);
9dc05cdc
MC
1302}
1303
1304static void
f53d7518 1305ovsdb_server_connect_active_ovsdb_server(struct unixctl_conn *conn,
9dc05cdc
MC
1306 int argc OVS_UNUSED,
1307 const char *argv[] OVS_UNUSED,
60e0cd04 1308 void *config_)
9dc05cdc 1309{
60e0cd04
AZ
1310 struct server_config *config = config_;
1311 char *msg = NULL;
6ab3dd96 1312
60e0cd04
AZ
1313 if ( !*config->sync_from) {
1314 msg = "Unable to connect: active server is not specified.\n";
1315 } else {
05ac209a
AZ
1316 const struct uuid *server_uuid;
1317 server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc);
60e0cd04 1318 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
05ac209a 1319 config->all_dbs, server_uuid);
60e0cd04
AZ
1320 if (!*config->is_backup) {
1321 *config->is_backup = true;
1322 save_config(config);
1323 }
9dc05cdc 1324 }
60e0cd04 1325 unixctl_command_reply(conn, msg);
9dc05cdc
MC
1326}
1327
1328static void
f53d7518 1329ovsdb_server_disconnect_active_ovsdb_server(struct unixctl_conn *conn,
9dc05cdc
MC
1330 int argc OVS_UNUSED,
1331 const char *argv[] OVS_UNUSED,
60e0cd04 1332 void *config_)
9dc05cdc 1333{
60e0cd04
AZ
1334 struct server_config *config = config_;
1335
f53d7518 1336 disconnect_active_server();
60e0cd04
AZ
1337 *config->is_backup = false;
1338 save_config(config);
9dc05cdc
MC
1339 unixctl_command_reply(conn, NULL);
1340}
1341
1342static void
60e0cd04
AZ
1343ovsdb_server_set_sync_exclude_tables(struct unixctl_conn *conn,
1344 int argc OVS_UNUSED,
1345 const char *argv[],
1346 void *config_)
9dc05cdc 1347{
60e0cd04 1348 struct server_config *config = config_;
3109b4e1 1349
60e0cd04 1350 char *err = set_blacklist_tables(argv[1], true);
3109b4e1 1351 if (!err) {
60e0cd04
AZ
1352 free(*config->sync_exclude);
1353 *config->sync_exclude = xstrdup(argv[1]);
1354 save_config(config);
1355 if (*config->is_backup) {
05ac209a
AZ
1356 const struct uuid *server_uuid;
1357 server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc);
60e0cd04 1358 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
05ac209a 1359 config->all_dbs, server_uuid);
3109b4e1
AZ
1360 }
1361 err = set_blacklist_tables(argv[1], false);
1362 }
1363 unixctl_command_reply(conn, err);
1364 free(err);
9dc05cdc
MC
1365}
1366
1367static void
60e0cd04
AZ
1368ovsdb_server_get_sync_exclude_tables(struct unixctl_conn *conn,
1369 int argc OVS_UNUSED,
1370 const char *argv[] OVS_UNUSED,
1371 void *arg_ OVS_UNUSED)
9dc05cdc 1372{
5975d1fc
BP
1373 char *reply = get_blacklist_tables();
1374 unixctl_command_reply(conn, reply);
1375 free(reply);
9dc05cdc
MC
1376}
1377
aa78de9d 1378static void
0e15264f
BP
1379ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1380 const char *argv[] OVS_UNUSED,
aa78de9d
BP
1381 void *exiting_)
1382{
1383 bool *exiting = exiting_;
1384 *exiting = true;
bde9f75d 1385 unixctl_command_reply(conn, NULL);
97a3c435
AZ
1386}
1387
1388static void
1389ovsdb_server_perf_counters_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
1390 const char *argv[] OVS_UNUSED,
1391 void *arg_ OVS_UNUSED)
1392{
1393 char *s = perf_counters_to_string();
1394
1395 unixctl_command_reply(conn, s);
1396 free(s);
1397}
1398
1399static void
1400ovsdb_server_perf_counters_clear(struct unixctl_conn *conn, int argc OVS_UNUSED,
1401 const char *argv[] OVS_UNUSED,
1402 void *arg_ OVS_UNUSED)
1403{
1404 perf_counters_clear();
1405 unixctl_command_reply(conn, NULL);
aa78de9d
BP
1406}
1407
c383f3bf 1408/* "ovsdb-server/disable-monitor-cond": makes ovsdb-server drop all of its
e47cb14c 1409 * JSON-RPC connections and reconnect. New sessions will not recognize
c383f3bf 1410 * the 'monitor_cond' method. */
e47cb14c 1411static void
c383f3bf
LS
1412ovsdb_server_disable_monitor_cond(struct unixctl_conn *conn,
1413 int argc OVS_UNUSED,
1414 const char *argv[] OVS_UNUSED,
1415 void *jsonrpc_)
e47cb14c
AZ
1416{
1417 struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
1418
c383f3bf 1419 ovsdb_jsonrpc_disable_monitor_cond();
1b1d2e6d 1420 ovsdb_jsonrpc_server_reconnect(
ab662236 1421 jsonrpc, true, xstrdup("user ran ovsdb-server/disable-monitor-cond"));
e47cb14c
AZ
1422 unixctl_command_reply(conn, NULL);
1423}
1424
ada496b5 1425static void
b4e8d170
BP
1426ovsdb_server_compact(struct unixctl_conn *conn, int argc,
1427 const char *argv[], void *dbs_)
ada496b5 1428{
bc7bcc40 1429 const char *db_name = argc < 2 ? NULL : argv[1];
eeb36a52 1430 struct shash *all_dbs = dbs_;
b4e8d170 1431 struct ds reply;
eeb36a52 1432 struct shash_node *node;
b4e8d170 1433 int n = 0;
ada496b5 1434
bc7bcc40
BP
1435 if (db_name && db_name[0] == '_') {
1436 unixctl_command_reply_error(conn, "cannot compact built-in databases");
1437 return;
1438 }
1439
b4e8d170 1440 ds_init(&reply);
eeb36a52 1441 SHASH_FOR_EACH(node, all_dbs) {
1b1d2e6d 1442 struct db *db = node->data;
bc7bcc40
BP
1443 if (db_name
1444 ? !strcmp(node->name, db_name)
1445 : node->name[0] != '_') {
1b1d2e6d
BP
1446 if (db->db) {
1447 VLOG_INFO("compacting %s database by user request",
1448 node->name);
1449
1450 struct ovsdb_error *error = ovsdb_snapshot(db->db);
1451 if (error) {
1452 char *s = ovsdb_error_to_string(error);
1453 ds_put_format(&reply, "%s\n", s);
1454 free(s);
1455 ovsdb_error_destroy(error);
1456 }
b4e8d170 1457
1b1d2e6d 1458 n++;
b4e8d170 1459 }
b4e8d170
BP
1460 }
1461 }
1462
1463 if (!n) {
1464 unixctl_command_reply_error(conn, "no database by that name");
1465 } else if (reply.length) {
1466 unixctl_command_reply_error(conn, ds_cstr(&reply));
ada496b5 1467 } else {
b4e8d170 1468 unixctl_command_reply(conn, NULL);
ada496b5 1469 }
b4e8d170 1470 ds_destroy(&reply);
ada496b5
BP
1471}
1472
31d0b6c9
BP
1473/* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC
1474 * connections and reconnect. */
1475static void
0e15264f
BP
1476ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED,
1477 const char *argv[] OVS_UNUSED, void *jsonrpc_)
31d0b6c9
BP
1478{
1479 struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
1b1d2e6d
BP
1480 ovsdb_jsonrpc_server_reconnect(
1481 jsonrpc, true, xstrdup("user ran ovsdb-server/reconnect"));
bde9f75d 1482 unixctl_command_reply(conn, NULL);
31d0b6c9
BP
1483}
1484
b421d2af
BP
1485/* "ovsdb-server/add-remote REMOTE": adds REMOTE to the set of remotes that
1486 * ovsdb-server services. */
1487static void
1488ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
0a3b723b 1489 const char *argv[], void *config_)
b421d2af 1490{
0a3b723b 1491 struct server_config *config = config_;
b421d2af
BP
1492 const char *remote = argv[1];
1493
1494 const struct ovsdb_column *column;
1495 const struct ovsdb_table *table;
1496 const struct db *db;
1497 char *retval;
1498
1499 retval = (strncmp("db:", remote, 3)
1500 ? NULL
0a3b723b 1501 : parse_db_column(config->all_dbs, remote,
b421d2af
BP
1502 &db, &table, &column));
1503 if (!retval) {
0a3b723b
BP
1504 if (sset_add(config->remotes, remote)) {
1505 save_config(config);
5f36127e 1506 }
b421d2af
BP
1507 unixctl_command_reply(conn, NULL);
1508 } else {
1509 unixctl_command_reply_error(conn, retval);
1510 free(retval);
1511 }
1512}
1513
1514/* "ovsdb-server/remove-remote REMOTE": removes REMOTE frmo the set of remotes
1515 * that ovsdb-server services. */
1516static void
1517ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
0a3b723b 1518 const char *argv[], void *config_)
b421d2af 1519{
0a3b723b 1520 struct server_config *config = config_;
b421d2af
BP
1521 struct sset_node *node;
1522
0a3b723b 1523 node = sset_find(config->remotes, argv[1]);
b421d2af 1524 if (node) {
0a3b723b
BP
1525 sset_delete(config->remotes, node);
1526 save_config(config);
b421d2af
BP
1527 unixctl_command_reply(conn, NULL);
1528 } else {
1529 unixctl_command_reply_error(conn, "no such remote");
1530 }
1531}
1532
1533/* "ovsdb-server/list-remotes": outputs a list of configured rmeotes. */
1534static void
1535ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED,
1536 const char *argv[] OVS_UNUSED, void *remotes_)
1537{
1538 struct sset *remotes = remotes_;
1539 const char **list, **p;
1540 struct ds s;
1541
1542 ds_init(&s);
1543
1544 list = sset_sort(remotes);
1545 for (p = list; *p; p++) {
1546 ds_put_format(&s, "%s\n", *p);
1547 }
1548 free(list);
1549
1550 unixctl_command_reply(conn, ds_cstr(&s));
1551 ds_destroy(&s);
1552}
1553
0a3b723b
BP
1554
1555/* "ovsdb-server/add-db DB": adds the DB to ovsdb-server. */
1556static void
1557ovsdb_server_add_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
1558 const char *argv[], void *config_)
1559{
1560 struct server_config *config = config_;
1561 const char *filename = argv[1];
0a3b723b 1562
1b1d2e6d 1563 char *error = ovsdb_error_to_string_free(open_db(config, filename));
0a3b723b
BP
1564 if (!error) {
1565 save_config(config);
60e0cd04 1566 if (*config->is_backup) {
05ac209a
AZ
1567 const struct uuid *server_uuid;
1568 server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc);
60e0cd04 1569 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
05ac209a 1570 config->all_dbs, server_uuid);
23c16b51 1571 }
0a3b723b
BP
1572 unixctl_command_reply(conn, NULL);
1573 } else {
1574 unixctl_command_reply_error(conn, error);
1575 free(error);
1576 }
1577}
1578
1579static void
1b1d2e6d 1580remove_db(struct server_config *config, struct shash_node *node, char *comment)
0a3b723b 1581{
10621d79 1582 struct db *db = node->data;
0a3b723b 1583
1b1d2e6d 1584 close_db(config, db, comment);
0a3b723b 1585 shash_delete(config->all_dbs, node);
0a3b723b
BP
1586
1587 save_config(config);
60e0cd04 1588 if (*config->is_backup) {
05ac209a
AZ
1589 const struct uuid *server_uuid;
1590 server_uuid = ovsdb_jsonrpc_server_get_uuid(config->jsonrpc);
60e0cd04 1591 ovsdb_replication_init(*config->sync_from, *config->sync_exclude,
05ac209a 1592 config->all_dbs, server_uuid);
23c16b51 1593 }
bc7bcc40
BP
1594}
1595
1596static void
1597ovsdb_server_remove_database(struct unixctl_conn *conn, int argc OVS_UNUSED,
1598 const char *argv[], void *config_)
1599{
1600 struct server_config *config = config_;
1601 struct shash_node *node;
1602
1603 node = shash_find(config->all_dbs, argv[1]);
1604 if (!node) {
1605 unixctl_command_reply_error(conn, "Failed to find the database.");
1606 return;
1607 }
1608 if (node->name[0] == '_') {
1609 unixctl_command_reply_error(conn, "Cannot remove reserved database.");
1610 return;
1611 }
1612
1b1d2e6d
BP
1613 remove_db(config, node, xasprintf("removing %s database by user request",
1614 node->name));
0a3b723b
BP
1615 unixctl_command_reply(conn, NULL);
1616}
1617
1618static void
1619ovsdb_server_list_databases(struct unixctl_conn *conn, int argc OVS_UNUSED,
1620 const char *argv[] OVS_UNUSED, void *all_dbs_)
1621{
1622 struct shash *all_dbs = all_dbs_;
1623 const struct shash_node **nodes;
1624 struct ds s;
1625 size_t i;
1626
1627 ds_init(&s);
1628
1629 nodes = shash_sort(all_dbs);
1630 for (i = 0; i < shash_count(all_dbs); i++) {
1b1d2e6d
BP
1631 const struct shash_node *node = nodes[i];
1632 struct db *db = node->data;
1633 if (db->db) {
1634 ds_put_format(&s, "%s\n", node->name);
1635 }
0a3b723b
BP
1636 }
1637 free(nodes);
1638
1639 unixctl_command_reply(conn, ds_cstr(&s));
1640 ds_destroy(&s);
1641}
1642
60e0cd04
AZ
1643static void
1644ovsdb_server_get_sync_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
1645 const char *argv[] OVS_UNUSED, void *config_)
1646{
1647 struct server_config *config = config_;
1648 bool is_backup = *config->is_backup;
1649 struct ds ds = DS_EMPTY_INITIALIZER;
1650
1651 ds_put_format(&ds, "state: %s\n", is_backup ? "backup" : "active");
1652
1653 if (is_backup) {
1654 ds_put_and_free_cstr(&ds, replication_status());
1655 }
1656
1657 unixctl_command_reply(conn, ds_cstr(&ds));
1658 ds_destroy(&ds);
1659}
1660
f85f8ebb 1661static void
53178986
BP
1662parse_options(int argc, char *argv[],
1663 struct sset *db_filenames, struct sset *remotes,
1664 char **unixctl_pathp, char **run_command,
60e0cd04 1665 char **sync_from, char **sync_exclude, bool *active)
f85f8ebb
BP
1666{
1667 enum {
06834871 1668 OPT_REMOTE = UCHAR_MAX + 1,
aa78de9d 1669 OPT_UNIXCTL,
475afa1b 1670 OPT_RUN,
9467fe62 1671 OPT_BOOTSTRAP_CA_CERT,
5bf6cbd6 1672 OPT_PEER_CA_CERT,
ae671c5f 1673 OPT_SYNC_FROM,
7a9d65d2 1674 OPT_SYNC_EXCLUDE,
60e0cd04 1675 OPT_ACTIVE,
53178986 1676 OPT_NO_DBS,
f85f8ebb 1677 VLOG_OPTION_ENUMS,
e18a1d08
ER
1678 DAEMON_OPTION_ENUMS,
1679 SSL_OPTION_ENUMS,
f85f8ebb 1680 };
53178986 1681
07fc4ed3 1682 static const struct option long_options[] = {
e3c17733
BP
1683 {"remote", required_argument, NULL, OPT_REMOTE},
1684 {"unixctl", required_argument, NULL, OPT_UNIXCTL},
41064650 1685#ifndef _WIN32
e3c17733 1686 {"run", required_argument, NULL, OPT_RUN},
41064650 1687#endif
e3c17733
BP
1688 {"help", no_argument, NULL, 'h'},
1689 {"version", no_argument, NULL, 'V'},
f85f8ebb
BP
1690 DAEMON_LONG_OPTIONS,
1691 VLOG_LONG_OPTIONS,
e3c17733 1692 {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
5bf6cbd6 1693 {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
e18a1d08 1694 STREAM_SSL_LONG_OPTIONS,
ae671c5f 1695 {"sync-from", required_argument, NULL, OPT_SYNC_FROM},
7a9d65d2 1696 {"sync-exclude-tables", required_argument, NULL, OPT_SYNC_EXCLUDE},
60e0cd04 1697 {"active", no_argument, NULL, OPT_ACTIVE},
53178986 1698 {"no-dbs", no_argument, NULL, OPT_NO_DBS},
e3c17733 1699 {NULL, 0, NULL, 0},
f85f8ebb 1700 };
5f383751 1701 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
53178986 1702 bool add_default_db = true;
f85f8ebb 1703
60e0cd04
AZ
1704 *sync_from = NULL;
1705 *sync_exclude = NULL;
53178986 1706 sset_init(db_filenames);
b3c01ed3 1707 sset_init(remotes);
f85f8ebb
BP
1708 for (;;) {
1709 int c;
1710
1711 c = getopt_long(argc, argv, short_options, long_options, NULL);
1712 if (c == -1) {
1713 break;
1714 }
1715
1716 switch (c) {
0b1fae1b 1717 case OPT_REMOTE:
b3c01ed3 1718 sset_add(remotes, optarg);
f85f8ebb
BP
1719 break;
1720
aa78de9d
BP
1721 case OPT_UNIXCTL:
1722 *unixctl_pathp = optarg;
1723 break;
1724
475afa1b
BP
1725 case OPT_RUN:
1726 *run_command = optarg;
1727 break;
1728
f85f8ebb
BP
1729 case 'h':
1730 usage();
1731
1732 case 'V':
55d5bb44 1733 ovs_print_version(0, 0);
f85f8ebb
BP
1734 exit(EXIT_SUCCESS);
1735
1736 VLOG_OPTION_HANDLERS
1737 DAEMON_OPTION_HANDLERS
f85f8ebb 1738
78876719
BP
1739 case 'p':
1740 private_key_file = optarg;
1741 break;
1742
1743 case 'c':
1744 certificate_file = optarg;
1745 break;
1746
1747 case 'C':
1748 ca_cert_file = optarg;
1749 bootstrap_ca_cert = false;
1750 break;
9467fe62 1751
e18a1d08
ER
1752 case OPT_SSL_PROTOCOLS:
1753 ssl_protocols = optarg;
1754 break;
1755
1756 case OPT_SSL_CIPHERS:
1757 ssl_ciphers = optarg;
1758 break;
1759
9467fe62 1760 case OPT_BOOTSTRAP_CA_CERT:
78876719
BP
1761 ca_cert_file = optarg;
1762 bootstrap_ca_cert = true;
9467fe62 1763 break;
9467fe62 1764
5bf6cbd6
GS
1765 case OPT_PEER_CA_CERT:
1766 stream_ssl_set_peer_ca_cert_file(optarg);
1767 break;
1768
ae671c5f 1769 case OPT_SYNC_FROM:
60e0cd04 1770 *sync_from = xstrdup(optarg);
ae671c5f
MC
1771 break;
1772
3109b4e1
AZ
1773 case OPT_SYNC_EXCLUDE: {
1774 char *err = set_blacklist_tables(optarg, false);
1775 if (err) {
1776 ovs_fatal(0, "%s", err);
1777 }
60e0cd04 1778 *sync_exclude = xstrdup(optarg);
7a9d65d2 1779 break;
3109b4e1 1780 }
60e0cd04
AZ
1781 case OPT_ACTIVE:
1782 *active = true;
1783 break;
7a9d65d2 1784
53178986
BP
1785 case OPT_NO_DBS:
1786 add_default_db = false;
1787 break;
1788
f85f8ebb
BP
1789 case '?':
1790 exit(EXIT_FAILURE);
1791
1792 default:
1793 abort();
1794 }
1795 }
1796 free(short_options);
1797
53178986
BP
1798 argc -= optind;
1799 argv += optind;
1800 if (argc > 0) {
1801 for (int i = 0; i < argc; i++) {
1802 sset_add(db_filenames, argv[i]);
1803 }
1804 } else if (add_default_db) {
1805 sset_add_and_free(db_filenames, xasprintf("%s/conf.db", ovs_dbdir()));
1806 }
f85f8ebb
BP
1807}
1808
1809static void
1810usage(void)
1811{
1812 printf("%s: Open vSwitch database server\n"
b4e8d170
BP
1813 "usage: %s [OPTIONS] [DATABASE...]\n"
1814 "where each DATABASE is a database file in ovsdb format.\n"
1815 "The default DATABASE, if none is given, is\n%s/conf.db.\n",
1816 program_name, program_name, ovs_dbdir());
f85f8ebb 1817 printf("\nJSON-RPC options (may be specified any number of times):\n"
0b1fae1b 1818 " --remote=REMOTE connect or listen to REMOTE\n");
9467fe62 1819 stream_usage("JSON-RPC", true, true, true);
f85f8ebb
BP
1820 daemon_usage();
1821 vlog_usage();
ae671c5f 1822 replication_usage();
f85f8ebb 1823 printf("\nOther options:\n"
475afa1b 1824 " --run COMMAND run COMMAND as subprocess then exit\n"
7b38bdc8 1825 " --unixctl=SOCKET override default control socket name\n"
f85f8ebb
BP
1826 " -h, --help display this help message\n"
1827 " -V, --version display version information\n");
f85f8ebb
BP
1828 exit(EXIT_SUCCESS);
1829}
5f36127e 1830\f
0a3b723b
BP
1831static struct json *
1832sset_to_json(const struct sset *sset)
1833{
1834 struct json *array;
1835 const char *s;
1836
1837 array = json_array_create_empty();
1838 SSET_FOR_EACH (s, sset) {
1839 json_array_add(array, json_string_create(s));
1840 }
1841 return array;
1842}
1843
1844/* Truncates and replaces the contents of 'config_file' by a representation of
1845 * 'remotes' and 'db_filenames'. */
5f36127e 1846static void
0a3b723b 1847save_config__(FILE *config_file, const struct sset *remotes,
60e0cd04
AZ
1848 const struct sset *db_filenames, const char *sync_from,
1849 const char *sync_exclude, bool is_backup)
5f36127e 1850{
0a3b723b 1851 struct json *obj;
5f36127e
BP
1852 char *s;
1853
1854 if (ftruncate(fileno(config_file), 0) == -1) {
10a89ef0
BP
1855 VLOG_FATAL("failed to truncate temporary file (%s)",
1856 ovs_strerror(errno));
5f36127e
BP
1857 }
1858
0a3b723b
BP
1859 obj = json_object_create();
1860 json_object_put(obj, "remotes", sset_to_json(remotes));
1861 json_object_put(obj, "db_filenames", sset_to_json(db_filenames));
60e0cd04
AZ
1862 if (sync_from) {
1863 json_object_put(obj, "sync_from", json_string_create(sync_from));
1864 }
1865 if (sync_exclude) {
1866 json_object_put(obj, "sync_exclude",
1867 json_string_create(sync_exclude));
1868 }
1869 json_object_put(obj, "is_backup", json_boolean_create(is_backup));
1870
0a3b723b
BP
1871 s = json_to_string(obj, 0);
1872 json_destroy(obj);
5f36127e
BP
1873
1874 if (fseek(config_file, 0, SEEK_SET) != 0
1875 || fputs(s, config_file) == EOF
1876 || fflush(config_file) == EOF) {
10a89ef0 1877 VLOG_FATAL("failed to write temporary file (%s)", ovs_strerror(errno));
5f36127e
BP
1878 }
1879 free(s);
1880}
1881
0a3b723b
BP
1882/* Truncates and replaces the contents of 'config_file' by a representation of
1883 * 'config'. */
5f36127e 1884static void
0a3b723b
BP
1885save_config(struct server_config *config)
1886{
1887 struct sset db_filenames;
1888 struct shash_node *node;
1889
1890 sset_init(&db_filenames);
1891 SHASH_FOR_EACH (node, config->all_dbs) {
1892 struct db *db = node->data;
bc7bcc40
BP
1893 if (node->name[0] != '_') {
1894 sset_add(&db_filenames, db->filename);
1895 }
0a3b723b
BP
1896 }
1897
60e0cd04
AZ
1898 save_config__(config->config_tmpfile, config->remotes, &db_filenames,
1899 *config->sync_from, *config->sync_exclude,
1900 *config->is_backup);
0a3b723b
BP
1901
1902 sset_destroy(&db_filenames);
1903}
1904
1905static void
1906sset_from_json(struct sset *sset, const struct json *array)
5f36127e 1907{
5f36127e
BP
1908 size_t i;
1909
0a3b723b
BP
1910 sset_clear(sset);
1911
1912 ovs_assert(array->type == JSON_ARRAY);
fa37affa
BP
1913 for (i = 0; i < array->array.n; i++) {
1914 const struct json *elem = array->array.elems[i];
0a3b723b
BP
1915 sset_add(sset, json_string(elem));
1916 }
1917}
1918
1919/* Clears and replaces 'remotes' and 'dbnames' by a configuration read from
1920 * 'config_file', which must have been previously written by save_config(). */
1921static void
60e0cd04
AZ
1922load_config(FILE *config_file, struct sset *remotes, struct sset *db_filenames,
1923 char **sync_from, char **sync_exclude, bool *is_backup)
0a3b723b
BP
1924{
1925 struct json *json;
5f36127e
BP
1926
1927 if (fseek(config_file, 0, SEEK_SET) != 0) {
10a89ef0 1928 VLOG_FATAL("seek failed in temporary file (%s)", ovs_strerror(errno));
5f36127e
BP
1929 }
1930 json = json_from_stream(config_file);
1931 if (json->type == JSON_STRING) {
1932 VLOG_FATAL("reading json failed (%s)", json_string(json));
1933 }
0a3b723b
BP
1934 ovs_assert(json->type == JSON_OBJECT);
1935
1936 sset_from_json(remotes, shash_find_data(json_object(json), "remotes"));
1937 sset_from_json(db_filenames,
1938 shash_find_data(json_object(json), "db_filenames"));
60e0cd04
AZ
1939
1940 struct json *string;
1941 string = shash_find_data(json_object(json), "sync_from");
1942 free(*sync_from);
1943 *sync_from = string ? xstrdup(json_string(string)) : NULL;
1944
1945 string = shash_find_data(json_object(json), "sync_exclude");
1946 free(*sync_exclude);
1947 *sync_exclude = string ? xstrdup(json_string(string)) : NULL;
1948
1949 *is_backup = json_boolean(shash_find_data(json_object(json), "is_backup"));
1950
5f36127e
BP
1951 json_destroy(json);
1952}