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