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