LCOV - code coverage report
Current view: top level - ovsdb - ovsdb-server.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 624 753 82.9 %
Date: 2016-09-14 01:02:56 Functions: 47 54 87.0 %
Branches: 276 422 65.4 %

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

Generated by: LCOV version 1.12