leak-checker: Remove because it cannot be made thread-safe.
[sliver-openvswitch.git] / ovsdb / ovsdb-server.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013 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 <unistd.h>
23
24 #include "column.h"
25 #include "command-line.h"
26 #include "daemon.h"
27 #include "dirs.h"
28 #include "dummy.h"
29 #include "dynamic-string.h"
30 #include "file.h"
31 #include "hash.h"
32 #include "json.h"
33 #include "jsonrpc.h"
34 #include "jsonrpc-server.h"
35 #include "list.h"
36 #include "memory.h"
37 #include "ovsdb.h"
38 #include "ovsdb-data.h"
39 #include "ovsdb-types.h"
40 #include "ovsdb-error.h"
41 #include "poll-loop.h"
42 #include "process.h"
43 #include "row.h"
44 #include "simap.h"
45 #include "stream-ssl.h"
46 #include "stream.h"
47 #include "stress.h"
48 #include "sset.h"
49 #include "table.h"
50 #include "timeval.h"
51 #include "transaction.h"
52 #include "trigger.h"
53 #include "util.h"
54 #include "unixctl.h"
55 #include "vlog.h"
56
57 VLOG_DEFINE_THIS_MODULE(ovsdb_server);
58
59 struct db {
60     /* Initialized in main(). */
61     char *filename;
62     struct ovsdb_file *file;
63     struct ovsdb *db;
64
65     /* Only used by update_remote_status(). */
66     struct ovsdb_txn *txn;
67 };
68
69 /* SSL configuration. */
70 static char *private_key_file;
71 static char *certificate_file;
72 static char *ca_cert_file;
73 static bool bootstrap_ca_cert;
74
75 static unixctl_cb_func ovsdb_server_exit;
76 static unixctl_cb_func ovsdb_server_compact;
77 static unixctl_cb_func ovsdb_server_reconnect;
78
79 struct add_remote_aux {
80     struct sset *remotes;
81     struct db *dbs;
82     size_t n_dbs;
83     FILE *config_tmpfile;
84 };
85 static unixctl_cb_func ovsdb_server_add_remote;
86
87 struct remove_remote_aux {
88     struct sset *remotes;
89     FILE *config_tmpfile;
90 };
91 static unixctl_cb_func ovsdb_server_remove_remote;
92 static unixctl_cb_func ovsdb_server_list_remotes;
93
94 static void parse_options(int *argc, char **argvp[],
95                           struct sset *remotes, char **unixctl_pathp,
96                           char **run_command);
97 static void usage(void) NO_RETURN;
98
99 static void reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
100                                 const struct db dbs[], size_t n_dbs,
101                                 struct sset *remotes);
102
103 static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
104                                  const struct sset *remotes,
105                                  struct db dbs[], size_t n_dbs);
106
107 static void save_config(FILE *config_file, const struct sset *);
108 static void load_config(FILE *config_file, struct sset *);
109
110 int
111 main(int argc, char *argv[])
112 {
113     char *unixctl_path = NULL;
114     char *run_command = NULL;
115     struct unixctl_server *unixctl;
116     struct ovsdb_jsonrpc_server *jsonrpc;
117     struct sset remotes;
118     struct process *run_process;
119     bool exiting;
120     int retval;
121     long long int status_timer = LLONG_MIN;
122     struct add_remote_aux add_remote_aux;
123     struct remove_remote_aux remove_remote_aux;
124     FILE *config_tmpfile;
125
126     struct db *dbs;
127     int n_dbs;
128     int i;
129
130     proctitle_init(argc, argv);
131     set_program_name(argv[0]);
132     stress_init_command();
133     signal(SIGPIPE, SIG_IGN);
134     process_init();
135
136     parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
137
138     /* Create and initialize 'config_tmpfile' as a temporary file to hold
139      * ovsdb-server's most basic configuration, and then save our initial
140      * configuration to it.  When --monitor is used, this preserves the effects
141      * of ovs-appctl commands such as ovsdb-server/add-remote (which saves the
142      * new configuration) across crashes. */
143     config_tmpfile = tmpfile();
144     if (!config_tmpfile) {
145         ovs_fatal(errno, "failed to create temporary file");
146     }
147     save_config(config_tmpfile, &remotes);
148
149     daemonize_start();
150
151     /* Load the saved config. */
152     load_config(config_tmpfile, &remotes);
153
154     n_dbs = MAX(1, argc);
155     dbs = xcalloc(n_dbs + 1, sizeof *dbs);
156     if (argc > 0) {
157         for (i = 0; i < argc; i++) {
158             dbs[i].filename = argv[i];
159         }
160     } else {
161         dbs[0].filename = xasprintf("%s/conf.db", ovs_dbdir());
162     }
163
164     for (i = 0; i < n_dbs; i++) {
165         struct ovsdb_error *error;
166
167         error = ovsdb_file_open(dbs[i].filename, false,
168                                 &dbs[i].db, &dbs[i].file);
169         if (error) {
170             ovs_fatal(0, "%s", ovsdb_error_to_string(error));
171         }
172     }
173
174     jsonrpc = ovsdb_jsonrpc_server_create();
175     for (i = 0; i < n_dbs; i++) {
176         if (!ovsdb_jsonrpc_server_add_db(jsonrpc, dbs[i].db)) {
177             ovs_fatal(0, "%s: duplicate database name",
178                       dbs[i].db->schema->name);
179         }
180     }
181     reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes);
182
183     retval = unixctl_server_create(unixctl_path, &unixctl);
184     if (retval) {
185         exit(EXIT_FAILURE);
186     }
187
188     if (run_command) {
189         char *run_argv[4];
190
191         run_argv[0] = "/bin/sh";
192         run_argv[1] = "-c";
193         run_argv[2] = run_command;
194         run_argv[3] = NULL;
195
196         retval = process_start(run_argv, &run_process);
197         if (retval) {
198             ovs_fatal(retval, "%s: process failed to start", run_command);
199         }
200     } else {
201         run_process = NULL;
202     }
203
204     daemonize_complete();
205
206     if (!run_command) {
207         /* ovsdb-server is usually a long-running process, in which case it
208          * makes plenty of sense to log the version, but --run makes
209          * ovsdb-server more like a command-line tool, so skip it.  */
210         VLOG_INFO("%s (Open vSwitch) %s", program_name, VERSION);
211     }
212
213     unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting);
214     unixctl_command_register("ovsdb-server/compact", "", 0, 1,
215                              ovsdb_server_compact, dbs);
216     unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
217                              ovsdb_server_reconnect, jsonrpc);
218
219     add_remote_aux.remotes = &remotes;
220     add_remote_aux.dbs = dbs;
221     add_remote_aux.n_dbs = n_dbs;
222     add_remote_aux.config_tmpfile = config_tmpfile;
223     unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1,
224                              ovsdb_server_add_remote, &add_remote_aux);
225
226     remove_remote_aux.remotes = &remotes;
227     remove_remote_aux.config_tmpfile = config_tmpfile;
228     unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1,
229                              ovsdb_server_remove_remote, &remove_remote_aux);
230
231     unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0,
232                              ovsdb_server_list_remotes, &remotes);
233
234     exiting = false;
235     while (!exiting) {
236         int i;
237
238         memory_run();
239         if (memory_should_report()) {
240             struct simap usage;
241
242             simap_init(&usage);
243             ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
244             for (i = 0; i < n_dbs; i++) {
245                 ovsdb_get_memory_usage(dbs[i].db, &usage);
246             }
247             memory_report(&usage);
248             simap_destroy(&usage);
249         }
250
251         /* Run unixctl_server_run() before reconfigure_from_db() because
252          * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
253          * the set of remotes that reconfigure_from_db() uses. */
254         unixctl_server_run(unixctl);
255
256         reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes);
257         ovsdb_jsonrpc_server_run(jsonrpc);
258
259         for (i = 0; i < n_dbs; i++) {
260             ovsdb_trigger_run(dbs[i].db, time_msec());
261         }
262         if (run_process) {
263             process_run();
264             if (process_exited(run_process)) {
265                 exiting = true;
266             }
267         }
268
269         /* update Manager status(es) every 5 seconds */
270         if (time_msec() >= status_timer) {
271             status_timer = time_msec() + 5000;
272             update_remote_status(jsonrpc, &remotes, dbs, n_dbs);
273         }
274
275         memory_wait();
276         ovsdb_jsonrpc_server_wait(jsonrpc);
277         unixctl_server_wait(unixctl);
278         for (i = 0; i < n_dbs; i++) {
279             ovsdb_trigger_wait(dbs[i].db, time_msec());
280         }
281         if (run_process) {
282             process_wait(run_process);
283         }
284         if (exiting) {
285             poll_immediate_wake();
286         }
287         poll_timer_wait_until(status_timer);
288         poll_block();
289     }
290     ovsdb_jsonrpc_server_destroy(jsonrpc);
291     for (i = 0; i < n_dbs; i++) {
292         ovsdb_destroy(dbs[i].db);
293     }
294     sset_destroy(&remotes);
295     unixctl_server_destroy(unixctl);
296
297     if (run_process && process_exited(run_process)) {
298         int status = process_status(run_process);
299         if (status) {
300             ovs_fatal(0, "%s: child exited, %s",
301                       run_command, process_status_msg(status));
302         }
303     }
304
305     return 0;
306 }
307
308 static const struct db *
309 find_db(const struct db dbs[], size_t n_dbs, const char *db_name)
310 {
311     size_t i;
312
313     for (i = 0; i < n_dbs; i++) {
314         if (!strcmp(dbs[i].db->schema->name, db_name)) {
315             return &dbs[i];
316         }
317     }
318
319     return NULL;
320 }
321
322 static char * WARN_UNUSED_RESULT
323 parse_db_column__(const struct db dbs[], size_t n_dbs,
324                   const char *name_, char *name,
325                   const struct db **dbp,
326                   const struct ovsdb_table **tablep,
327                   const struct ovsdb_column **columnp)
328 {
329     const char *table_name, *column_name;
330     const struct ovsdb_column *column;
331     const struct ovsdb_table *table;
332     const char *tokens[3];
333     char *save_ptr = NULL;
334     const struct db *db;
335
336     *dbp = NULL;
337     *tablep = NULL;
338     *columnp = NULL;
339
340     strtok_r(name, ":", &save_ptr); /* "db:" */
341     tokens[0] = strtok_r(NULL, ",", &save_ptr);
342     tokens[1] = strtok_r(NULL, ",", &save_ptr);
343     tokens[2] = strtok_r(NULL, ",", &save_ptr);
344     if (!tokens[0] || !tokens[1]) {
345         return xasprintf("\"%s\": invalid syntax", name_);
346     }
347     if (tokens[2]) {
348         const char *db_name = tokens[0];
349         table_name = tokens[1];
350         column_name = tokens[2];
351
352         db = find_db(dbs, n_dbs, tokens[0]);
353         if (!db) {
354             return xasprintf("\"%s\": no database named %s", name_, db_name);
355         }
356     } else {
357         if (n_dbs > 1) {
358             return xasprintf("\"%s\": database name must be specified "
359                              "(because multiple databases are configured)",
360                              name_);
361         }
362
363         table_name = tokens[0];
364         column_name = tokens[1];
365         db = &dbs[0];
366     }
367
368     table = ovsdb_get_table(db->db, table_name);
369     if (!table) {
370         return xasprintf("\"%s\": no table named %s", name_, table_name);
371     }
372
373     column = ovsdb_table_schema_get_column(table->schema, column_name);
374     if (!column) {
375         return xasprintf("\"%s\": table \"%s\" has no column \"%s\"",
376                          name_, table_name, column_name);
377     }
378
379     *dbp = db;
380     *columnp = column;
381     *tablep = table;
382     return NULL;
383 }
384
385 /* Returns NULL if successful, otherwise a malloc()'d string describing the
386  * error. */
387 static char * WARN_UNUSED_RESULT
388 parse_db_column(const struct db dbs[], size_t n_dbs,
389                 const char *name_,
390                 const struct db **dbp,
391                 const struct ovsdb_table **tablep,
392                 const struct ovsdb_column **columnp)
393 {
394     char *name = xstrdup(name_);
395     char *retval = parse_db_column__(dbs, n_dbs, name_, name,
396                                      dbp, tablep, columnp);
397     free(name);
398     return retval;
399 }
400
401 /* Returns NULL if successful, otherwise a malloc()'d string describing the
402  * error. */
403 static char * WARN_UNUSED_RESULT
404 parse_db_string_column(const struct db dbs[], size_t n_dbs,
405                        const char *name,
406                        const struct db **dbp,
407                        const struct ovsdb_table **tablep,
408                        const struct ovsdb_column **columnp)
409 {
410     char *retval;
411
412     retval = parse_db_column(dbs, n_dbs, name, dbp, tablep, columnp);
413     if (retval) {
414         return retval;
415     }
416
417     if ((*columnp)->type.key.type != OVSDB_TYPE_STRING
418         || (*columnp)->type.value.type != OVSDB_TYPE_VOID) {
419         return xasprintf("\"%s\": table \"%s\" column \"%s\" is "
420                          "not string or set of strings",
421                          name, (*tablep)->schema->name, (*columnp)->name);
422     }
423
424     return NULL;
425 }
426
427 static OVS_UNUSED const char *
428 query_db_string(const struct db dbs[], size_t n_dbs, const char *name)
429 {
430     if (!name || strncmp(name, "db:", 3)) {
431         return name;
432     } else {
433         const struct ovsdb_column *column;
434         const struct ovsdb_table *table;
435         const struct ovsdb_row *row;
436         const struct db *db;
437         char *retval;
438
439         retval = parse_db_string_column(dbs, n_dbs, name,
440                                         &db, &table, &column);
441         if (retval) {
442             ovs_fatal(0, "%s", retval);
443         }
444
445         HMAP_FOR_EACH (row, hmap_node, &table->rows) {
446             const struct ovsdb_datum *datum;
447             size_t i;
448
449             datum = &row->fields[column->index];
450             for (i = 0; i < datum->n; i++) {
451                 if (datum->keys[i].string[0]) {
452                     return datum->keys[i].string;
453                 }
454             }
455         }
456         return NULL;
457     }
458 }
459
460 static struct ovsdb_jsonrpc_options *
461 add_remote(struct shash *remotes, const char *target)
462 {
463     struct ovsdb_jsonrpc_options *options;
464
465     options = shash_find_data(remotes, target);
466     if (!options) {
467         options = ovsdb_jsonrpc_default_options(target);
468         shash_add(remotes, target, options);
469     }
470
471     return options;
472 }
473
474 static struct ovsdb_datum *
475 get_datum(struct ovsdb_row *row, const char *column_name,
476           const enum ovsdb_atomic_type key_type,
477           const enum ovsdb_atomic_type value_type,
478           const size_t n_max)
479 {
480     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
481     const struct ovsdb_table_schema *schema = row->table->schema;
482     const struct ovsdb_column *column;
483
484     column = ovsdb_table_schema_get_column(schema, column_name);
485     if (!column) {
486         VLOG_DBG_RL(&rl, "Table `%s' has no `%s' column",
487                     schema->name, column_name);
488         return NULL;
489     }
490
491     if (column->type.key.type != key_type
492         || column->type.value.type != value_type
493         || column->type.n_max != n_max) {
494         if (!VLOG_DROP_DBG(&rl)) {
495             char *type_name = ovsdb_type_to_english(&column->type);
496             VLOG_DBG("Table `%s' column `%s' has type %s, not expected "
497                      "key type %s, value type %s, max elements %zd.",
498                      schema->name, column_name, type_name,
499                      ovsdb_atomic_type_to_string(key_type),
500                      ovsdb_atomic_type_to_string(value_type),
501                      n_max);
502             free(type_name);
503         }
504         return NULL;
505     }
506
507     return &row->fields[column->index];
508 }
509
510 /* Read string-string key-values from a map.  Returns the value associated with
511  * 'key', if found, or NULL */
512 static const char *
513 read_map_string_column(const struct ovsdb_row *row, const char *column_name,
514                        const char *key)
515 {
516     const struct ovsdb_datum *datum;
517     union ovsdb_atom *atom_key = NULL, *atom_value = NULL;
518     size_t i;
519
520     datum = get_datum(CONST_CAST(struct ovsdb_row *, row), column_name,
521                       OVSDB_TYPE_STRING, OVSDB_TYPE_STRING, UINT_MAX);
522
523     if (!datum) {
524         return NULL;
525     }
526
527     for (i = 0; i < datum->n; i++) {
528         atom_key = &datum->keys[i];
529         if (!strcmp(atom_key->string, key)){
530             atom_value = &datum->values[i];
531             break;
532         }
533     }
534
535     return atom_value ? atom_value->string : NULL;
536 }
537
538 static const union ovsdb_atom *
539 read_column(const struct ovsdb_row *row, const char *column_name,
540             enum ovsdb_atomic_type type)
541 {
542     const struct ovsdb_datum *datum;
543
544     datum = get_datum(CONST_CAST(struct ovsdb_row *, row), column_name, type,
545                       OVSDB_TYPE_VOID, 1);
546     return datum && datum->n ? datum->keys : NULL;
547 }
548
549 static bool
550 read_integer_column(const struct ovsdb_row *row, const char *column_name,
551                     long long int *integerp)
552 {
553     const union ovsdb_atom *atom;
554
555     atom = read_column(row, column_name, OVSDB_TYPE_INTEGER);
556     *integerp = atom ? atom->integer : 0;
557     return atom != NULL;
558 }
559
560 static bool
561 read_string_column(const struct ovsdb_row *row, const char *column_name,
562                    const char **stringp)
563 {
564     const union ovsdb_atom *atom;
565
566     atom = read_column(row, column_name, OVSDB_TYPE_STRING);
567     *stringp = atom ? atom->string : NULL;
568     return atom != NULL;
569 }
570
571 static void
572 write_bool_column(struct ovsdb_row *row, const char *column_name, bool value)
573 {
574     const struct ovsdb_column *column;
575     struct ovsdb_datum *datum;
576
577     column = ovsdb_table_schema_get_column(row->table->schema, column_name);
578     datum = get_datum(row, column_name, OVSDB_TYPE_BOOLEAN,
579                       OVSDB_TYPE_VOID, 1);
580     if (!datum) {
581         return;
582     }
583
584     if (datum->n != 1) {
585         ovsdb_datum_destroy(datum, &column->type);
586
587         datum->n = 1;
588         datum->keys = xmalloc(sizeof *datum->keys);
589         datum->values = NULL;
590     }
591
592     datum->keys[0].boolean = value;
593 }
594
595 static void
596 write_string_string_column(struct ovsdb_row *row, const char *column_name,
597                            char **keys, char **values, size_t n)
598 {
599     const struct ovsdb_column *column;
600     struct ovsdb_datum *datum;
601     size_t i;
602
603     column = ovsdb_table_schema_get_column(row->table->schema, column_name);
604     datum = get_datum(row, column_name, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING,
605                       UINT_MAX);
606     if (!datum) {
607         for (i = 0; i < n; i++) {
608             free(keys[i]);
609             free(values[i]);
610         }
611         return;
612     }
613
614     /* Free existing data. */
615     ovsdb_datum_destroy(datum, &column->type);
616
617     /* Allocate space for new values. */
618     datum->n = n;
619     datum->keys = xmalloc(n * sizeof *datum->keys);
620     datum->values = xmalloc(n * sizeof *datum->values);
621
622     for (i = 0; i < n; ++i) {
623         datum->keys[i].string = keys[i];
624         datum->values[i].string = values[i];
625     }
626
627     /* Sort and check constraints. */
628     ovsdb_datum_sort_assert(datum, column->type.key.type);
629 }
630
631 /* Adds a remote and options to 'remotes', based on the Manager table row in
632  * 'row'. */
633 static void
634 add_manager_options(struct shash *remotes, const struct ovsdb_row *row)
635 {
636     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
637     struct ovsdb_jsonrpc_options *options;
638     long long int max_backoff, probe_interval;
639     const char *target, *dscp_string;
640
641     if (!read_string_column(row, "target", &target) || !target) {
642         VLOG_INFO_RL(&rl, "Table `%s' has missing or invalid `target' column",
643                      row->table->schema->name);
644         return;
645     }
646
647     options = add_remote(remotes, target);
648     if (read_integer_column(row, "max_backoff", &max_backoff)) {
649         options->max_backoff = max_backoff;
650     }
651     if (read_integer_column(row, "inactivity_probe", &probe_interval)) {
652         options->probe_interval = probe_interval;
653     }
654
655     options->dscp = DSCP_DEFAULT;
656     dscp_string = read_map_string_column(row, "other_config", "dscp");
657     if (dscp_string) {
658         int dscp = atoi(dscp_string);
659         if (dscp >= 0 && dscp <= 63) {
660             options->dscp = dscp;
661         }
662     }
663 }
664
665 static void
666 query_db_remotes(const char *name, const struct db dbs[], size_t n_dbs,
667                  struct shash *remotes)
668 {
669     const struct ovsdb_column *column;
670     const struct ovsdb_table *table;
671     const struct ovsdb_row *row;
672     const struct db *db;
673     char *retval;
674
675     retval = parse_db_column(dbs, n_dbs, name, &db, &table, &column);
676     if (retval) {
677         ovs_fatal(0, "%s", retval);
678     }
679
680     if (column->type.key.type == OVSDB_TYPE_STRING
681         && column->type.value.type == OVSDB_TYPE_VOID) {
682         HMAP_FOR_EACH (row, hmap_node, &table->rows) {
683             const struct ovsdb_datum *datum;
684             size_t i;
685
686             datum = &row->fields[column->index];
687             for (i = 0; i < datum->n; i++) {
688                 add_remote(remotes, datum->keys[i].string);
689             }
690         }
691     } else if (column->type.key.type == OVSDB_TYPE_UUID
692                && column->type.key.u.uuid.refTable
693                && column->type.value.type == OVSDB_TYPE_VOID) {
694         const struct ovsdb_table *ref_table = column->type.key.u.uuid.refTable;
695         HMAP_FOR_EACH (row, hmap_node, &table->rows) {
696             const struct ovsdb_datum *datum;
697             size_t i;
698
699             datum = &row->fields[column->index];
700             for (i = 0; i < datum->n; i++) {
701                 const struct ovsdb_row *ref_row;
702
703                 ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
704                 if (ref_row) {
705                     add_manager_options(remotes, ref_row);
706                 }
707             }
708         }
709     }
710 }
711
712 static void
713 update_remote_row(const struct ovsdb_row *row, struct ovsdb_txn *txn,
714                   const struct ovsdb_jsonrpc_server *jsonrpc)
715 {
716     struct ovsdb_jsonrpc_remote_status status;
717     struct ovsdb_row *rw_row;
718     const char *target;
719     char *keys[9], *values[9];
720     size_t n = 0;
721
722     /* Get the "target" (protocol/host/port) spec. */
723     if (!read_string_column(row, "target", &target)) {
724         /* Bad remote spec or incorrect schema. */
725         return;
726     }
727     rw_row = ovsdb_txn_row_modify(txn, row);
728     ovsdb_jsonrpc_server_get_remote_status(jsonrpc, target, &status);
729
730     /* Update status information columns. */
731     write_bool_column(rw_row, "is_connected", status.is_connected);
732
733     if (status.state) {
734         keys[n] = xstrdup("state");
735         values[n++] = xstrdup(status.state);
736     }
737     if (status.sec_since_connect != UINT_MAX) {
738         keys[n] = xstrdup("sec_since_connect");
739         values[n++] = xasprintf("%u", status.sec_since_connect);
740     }
741     if (status.sec_since_disconnect != UINT_MAX) {
742         keys[n] = xstrdup("sec_since_disconnect");
743         values[n++] = xasprintf("%u", status.sec_since_disconnect);
744     }
745     if (status.last_error) {
746         keys[n] = xstrdup("last_error");
747         values[n++] =
748             xstrdup(ovs_retval_to_string(status.last_error));
749     }
750     if (status.locks_held && status.locks_held[0]) {
751         keys[n] = xstrdup("locks_held");
752         values[n++] = xstrdup(status.locks_held);
753     }
754     if (status.locks_waiting && status.locks_waiting[0]) {
755         keys[n] = xstrdup("locks_waiting");
756         values[n++] = xstrdup(status.locks_waiting);
757     }
758     if (status.locks_lost && status.locks_lost[0]) {
759         keys[n] = xstrdup("locks_lost");
760         values[n++] = xstrdup(status.locks_lost);
761     }
762     if (status.n_connections > 1) {
763         keys[n] = xstrdup("n_connections");
764         values[n++] = xasprintf("%d", status.n_connections);
765     }
766     if (status.bound_port != htons(0)) {
767         keys[n] = xstrdup("bound_port");
768         values[n++] = xasprintf("%"PRIu16, ntohs(status.bound_port));
769     }
770     write_string_string_column(rw_row, "status", keys, values, n);
771
772     ovsdb_jsonrpc_server_free_remote_status(&status);
773 }
774
775 static void
776 update_remote_rows(const struct db dbs[], size_t n_dbs,
777                    const char *remote_name,
778                    const struct ovsdb_jsonrpc_server *jsonrpc)
779 {
780     const struct ovsdb_table *table, *ref_table;
781     const struct ovsdb_column *column;
782     const struct ovsdb_row *row;
783     const struct db *db;
784     char *retval;
785
786     if (strncmp("db:", remote_name, 3)) {
787         return;
788     }
789
790     retval = parse_db_column(dbs, n_dbs, remote_name, &db, &table, &column);
791     if (retval) {
792         ovs_fatal(0, "%s", retval);
793     }
794
795     if (column->type.key.type != OVSDB_TYPE_UUID
796         || !column->type.key.u.uuid.refTable
797         || column->type.value.type != OVSDB_TYPE_VOID) {
798         return;
799     }
800
801     ref_table = column->type.key.u.uuid.refTable;
802
803     HMAP_FOR_EACH (row, hmap_node, &table->rows) {
804         const struct ovsdb_datum *datum;
805         size_t i;
806
807         datum = &row->fields[column->index];
808         for (i = 0; i < datum->n; i++) {
809             const struct ovsdb_row *ref_row;
810
811             ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
812             if (ref_row) {
813                 update_remote_row(ref_row, db->txn, jsonrpc);
814             }
815         }
816     }
817 }
818
819 static void
820 update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
821                      const struct sset *remotes,
822                      struct db dbs[], size_t n_dbs)
823 {
824     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
825     const char *remote;
826     size_t i;
827
828     for (i = 0; i < n_dbs; i++) {
829         dbs[i].txn = ovsdb_txn_create(dbs[i].db);
830     }
831
832     /* Iterate over --remote arguments given on command line. */
833     SSET_FOR_EACH (remote, remotes) {
834         update_remote_rows(dbs, n_dbs, remote, jsonrpc);
835     }
836
837     for (i = 0; i < n_dbs; i++) {
838         struct ovsdb_error *error = ovsdb_txn_commit(dbs[i].txn, false);
839         if (error) {
840             VLOG_ERR_RL(&rl, "Failed to update remote status: %s",
841                         ovsdb_error_to_string(error));
842             ovsdb_error_destroy(error);
843         }
844     }
845 }
846
847 /* Reconfigures ovsdb-server based on information in the database. */
848 static void
849 reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
850                     const struct db dbs[], size_t n_dbs, struct sset *remotes)
851 {
852     struct shash resolved_remotes;
853     const char *name;
854
855     /* Configure remotes. */
856     shash_init(&resolved_remotes);
857     SSET_FOR_EACH (name, remotes) {
858         if (!strncmp(name, "db:", 3)) {
859             query_db_remotes(name, dbs, n_dbs, &resolved_remotes);
860         } else {
861             add_remote(&resolved_remotes, name);
862         }
863     }
864     ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes);
865     shash_destroy_free_data(&resolved_remotes);
866
867     /* Configure SSL. */
868     stream_ssl_set_key_and_cert(query_db_string(dbs, n_dbs, private_key_file),
869                                 query_db_string(dbs, n_dbs, certificate_file));
870     stream_ssl_set_ca_cert_file(query_db_string(dbs, n_dbs, ca_cert_file),
871                                 bootstrap_ca_cert);
872 }
873
874 static void
875 ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
876                   const char *argv[] OVS_UNUSED,
877                   void *exiting_)
878 {
879     bool *exiting = exiting_;
880     *exiting = true;
881     unixctl_command_reply(conn, NULL);
882 }
883
884 static void
885 ovsdb_server_compact(struct unixctl_conn *conn, int argc,
886                      const char *argv[], void *dbs_)
887 {
888     struct db *dbs = dbs_;
889     struct ds reply;
890     struct db *db;
891     int n = 0;
892
893     ds_init(&reply);
894     for (db = dbs; db->filename != NULL; db++) {
895         const char *name = db->db->schema->name;
896
897         if (argc < 2 || !strcmp(argv[1], name)) {
898             struct ovsdb_error *error;
899
900             VLOG_INFO("compacting %s database by user request", name);
901
902             error = ovsdb_file_compact(db->file);
903             if (error) {
904                 char *s = ovsdb_error_to_string(error);
905                 ds_put_format(&reply, "%s\n", s);
906                 free(s);
907             }
908
909             n++;
910         }
911     }
912
913     if (!n) {
914         unixctl_command_reply_error(conn, "no database by that name");
915     } else if (reply.length) {
916         unixctl_command_reply_error(conn, ds_cstr(&reply));
917     } else {
918         unixctl_command_reply(conn, NULL);
919     }
920     ds_destroy(&reply);
921 }
922
923 /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC
924  * connections and reconnect. */
925 static void
926 ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED,
927                        const char *argv[] OVS_UNUSED, void *jsonrpc_)
928 {
929     struct ovsdb_jsonrpc_server *jsonrpc = jsonrpc_;
930
931     ovsdb_jsonrpc_server_reconnect(jsonrpc);
932     unixctl_command_reply(conn, NULL);
933 }
934
935 /* "ovsdb-server/add-remote REMOTE": adds REMOTE to the set of remotes that
936  * ovsdb-server services. */
937 static void
938 ovsdb_server_add_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
939                         const char *argv[], void *aux_)
940 {
941     struct add_remote_aux *aux = aux_;
942     const char *remote = argv[1];
943
944     const struct ovsdb_column *column;
945     const struct ovsdb_table *table;
946     const struct db *db;
947     char *retval;
948
949     retval = (strncmp("db:", remote, 3)
950               ? NULL
951               : parse_db_column(aux->dbs, aux->n_dbs, remote,
952                                 &db, &table, &column));
953     if (!retval) {
954         if (sset_add(aux->remotes, remote)) {
955             save_config(aux->config_tmpfile, aux->remotes);
956         }
957         unixctl_command_reply(conn, NULL);
958     } else {
959         unixctl_command_reply_error(conn, retval);
960         free(retval);
961     }
962 }
963
964 /* "ovsdb-server/remove-remote REMOTE": removes REMOTE frmo the set of remotes
965  * that ovsdb-server services. */
966 static void
967 ovsdb_server_remove_remote(struct unixctl_conn *conn, int argc OVS_UNUSED,
968                            const char *argv[], void *aux_)
969 {
970     struct remove_remote_aux *aux = aux_;
971     struct sset_node *node;
972
973     node = sset_find(aux->remotes, argv[1]);
974     if (node) {
975         sset_delete(aux->remotes, node);
976         save_config(aux->config_tmpfile, aux->remotes);
977         unixctl_command_reply(conn, NULL);
978     } else {
979         unixctl_command_reply_error(conn, "no such remote");
980     }
981 }
982
983 /* "ovsdb-server/list-remotes": outputs a list of configured rmeotes. */
984 static void
985 ovsdb_server_list_remotes(struct unixctl_conn *conn, int argc OVS_UNUSED,
986                           const char *argv[] OVS_UNUSED, void *remotes_)
987 {
988     struct sset *remotes = remotes_;
989     const char **list, **p;
990     struct ds s;
991
992     ds_init(&s);
993
994     list = sset_sort(remotes);
995     for (p = list; *p; p++) {
996         ds_put_format(&s, "%s\n", *p);
997     }
998     free(list);
999
1000     unixctl_command_reply(conn, ds_cstr(&s));
1001     ds_destroy(&s);
1002 }
1003
1004 static void
1005 parse_options(int *argcp, char **argvp[],
1006               struct sset *remotes, char **unixctl_pathp, char **run_command)
1007 {
1008     enum {
1009         OPT_REMOTE = UCHAR_MAX + 1,
1010         OPT_UNIXCTL,
1011         OPT_RUN,
1012         OPT_BOOTSTRAP_CA_CERT,
1013         OPT_ENABLE_DUMMY,
1014         VLOG_OPTION_ENUMS,
1015         DAEMON_OPTION_ENUMS
1016     };
1017     static const struct option long_options[] = {
1018         {"remote",      required_argument, NULL, OPT_REMOTE},
1019         {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
1020         {"run",         required_argument, NULL, OPT_RUN},
1021         {"help",        no_argument, NULL, 'h'},
1022         {"version",     no_argument, NULL, 'V'},
1023         DAEMON_LONG_OPTIONS,
1024         VLOG_LONG_OPTIONS,
1025         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
1026         {"private-key", required_argument, NULL, 'p'},
1027         {"certificate", required_argument, NULL, 'c'},
1028         {"ca-cert",     required_argument, NULL, 'C'},
1029         {"enable-dummy", optional_argument, NULL, OPT_ENABLE_DUMMY},
1030         {NULL, 0, NULL, 0},
1031     };
1032     char *short_options = long_options_to_short_options(long_options);
1033     int argc = *argcp;
1034     char **argv = *argvp;
1035
1036     sset_init(remotes);
1037     for (;;) {
1038         int c;
1039
1040         c = getopt_long(argc, argv, short_options, long_options, NULL);
1041         if (c == -1) {
1042             break;
1043         }
1044
1045         switch (c) {
1046         case OPT_REMOTE:
1047             sset_add(remotes, optarg);
1048             break;
1049
1050         case OPT_UNIXCTL:
1051             *unixctl_pathp = optarg;
1052             break;
1053
1054         case OPT_RUN:
1055             *run_command = optarg;
1056             break;
1057
1058         case 'h':
1059             usage();
1060
1061         case 'V':
1062             ovs_print_version(0, 0);
1063             exit(EXIT_SUCCESS);
1064
1065         VLOG_OPTION_HANDLERS
1066         DAEMON_OPTION_HANDLERS
1067
1068         case 'p':
1069             private_key_file = optarg;
1070             break;
1071
1072         case 'c':
1073             certificate_file = optarg;
1074             break;
1075
1076         case 'C':
1077             ca_cert_file = optarg;
1078             bootstrap_ca_cert = false;
1079             break;
1080
1081         case OPT_BOOTSTRAP_CA_CERT:
1082             ca_cert_file = optarg;
1083             bootstrap_ca_cert = true;
1084             break;
1085
1086         case OPT_ENABLE_DUMMY:
1087             dummy_enable(optarg && !strcmp(optarg, "override"));
1088             break;
1089
1090         case '?':
1091             exit(EXIT_FAILURE);
1092
1093         default:
1094             abort();
1095         }
1096     }
1097     free(short_options);
1098
1099     *argcp -= optind;
1100     *argvp += optind;
1101 }
1102
1103 static void
1104 usage(void)
1105 {
1106     printf("%s: Open vSwitch database server\n"
1107            "usage: %s [OPTIONS] [DATABASE...]\n"
1108            "where each DATABASE is a database file in ovsdb format.\n"
1109            "The default DATABASE, if none is given, is\n%s/conf.db.\n",
1110            program_name, program_name, ovs_dbdir());
1111     printf("\nJSON-RPC options (may be specified any number of times):\n"
1112            "  --remote=REMOTE         connect or listen to REMOTE\n");
1113     stream_usage("JSON-RPC", true, true, true);
1114     daemon_usage();
1115     vlog_usage();
1116     printf("\nOther options:\n"
1117            "  --run COMMAND           run COMMAND as subprocess then exit\n"
1118            "  --unixctl=SOCKET        override default control socket name\n"
1119            "  -h, --help              display this help message\n"
1120            "  -V, --version           display version information\n");
1121     exit(EXIT_SUCCESS);
1122 }
1123 \f
1124 /* Truncates and replaces the contents of 'config_file' by a representation
1125  * of 'remotes'. */
1126 static void
1127 save_config(FILE *config_file, const struct sset *remotes)
1128 {
1129     const char *remote;
1130     struct json *json;
1131     char *s;
1132
1133     if (ftruncate(fileno(config_file), 0) == -1) {
1134         VLOG_FATAL("failed to truncate temporary file (%s)", strerror(errno));
1135     }
1136
1137     json = json_array_create_empty();
1138     SSET_FOR_EACH (remote, remotes) {
1139         json_array_add(json, json_string_create(remote));
1140     }
1141     s = json_to_string(json, 0);
1142     json_destroy(json);
1143
1144     if (fseek(config_file, 0, SEEK_SET) != 0
1145         || fputs(s, config_file) == EOF
1146         || fflush(config_file) == EOF) {
1147         VLOG_FATAL("failed to write temporary file (%s)", strerror(errno));
1148     }
1149     free(s);
1150 }
1151
1152 /* Clears and replaces 'remotes' by a configuration read from 'config_file',
1153  * which must have been previously written by save_config(). */
1154 static void
1155 load_config(FILE *config_file, struct sset *remotes)
1156 {
1157     struct json *json;
1158     size_t i;
1159
1160     sset_clear(remotes);
1161
1162     if (fseek(config_file, 0, SEEK_SET) != 0) {
1163         VLOG_FATAL("seek failed in temporary file (%s)", strerror(errno));
1164     }
1165     json = json_from_stream(config_file);
1166     if (json->type == JSON_STRING) {
1167         VLOG_FATAL("reading json failed (%s)", json_string(json));
1168     }
1169     ovs_assert(json->type == JSON_ARRAY);
1170     for (i = 0; i < json->u.array.n; i++) {
1171         const struct json *remote = json->u.array.elems[i];
1172         sset_add(remotes, json_string(remote));
1173     }
1174     json_destroy(json);
1175 }