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