1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "command-line.h"
29 #include "dynamic-string.h"
34 #include "jsonrpc-server.h"
38 #include "ovsdb-data.h"
39 #include "ovsdb-types.h"
40 #include "ovsdb-error.h"
41 #include "poll-loop.h"
46 #include "stream-ssl.h"
51 #include "transaction.h"
57 VLOG_DEFINE_THIS_MODULE(ovsdb_server
);
60 /* Initialized in main(). */
62 struct ovsdb_file
*file
;
65 /* Only used by update_remote_status(). */
66 struct ovsdb_txn
*txn
;
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
;
75 static unixctl_cb_func ovsdb_server_exit
;
76 static unixctl_cb_func ovsdb_server_compact
;
77 static unixctl_cb_func ovsdb_server_reconnect
;
79 struct server_config
{
81 struct shash
*all_dbs
;
83 struct ovsdb_jsonrpc_server
*jsonrpc
;
85 static unixctl_cb_func ovsdb_server_add_remote
;
86 static unixctl_cb_func ovsdb_server_remove_remote
;
87 static unixctl_cb_func ovsdb_server_list_remotes
;
89 static unixctl_cb_func ovsdb_server_add_database
;
90 static unixctl_cb_func ovsdb_server_remove_database
;
91 static unixctl_cb_func ovsdb_server_list_databases
;
93 static char *open_db(struct server_config
*config
, const char *filename
);
95 static void parse_options(int *argc
, char **argvp
[],
96 struct sset
*remotes
, char **unixctl_pathp
,
98 static void usage(void) NO_RETURN
;
100 static char *reconfigure_remotes(struct ovsdb_jsonrpc_server
*,
101 const struct shash
*all_dbs
,
102 struct sset
*remotes
);
103 static char *reconfigure_ssl(const struct shash
*all_dbs
);
104 static void report_error_if_changed(char *error
, char **last_errorp
);
106 static void update_remote_status(const struct ovsdb_jsonrpc_server
*jsonrpc
,
107 const struct sset
*remotes
,
108 struct shash
*all_dbs
);
110 static void save_config__(FILE *config_file
, const struct sset
*remotes
,
111 const struct sset
*db_filenames
);
112 static void save_config(struct server_config
*);
113 static void load_config(FILE *config_file
, struct sset
*remotes
,
114 struct sset
*db_filenames
);
117 main(int argc
, char *argv
[])
119 char *unixctl_path
= NULL
;
120 char *run_command
= NULL
;
121 struct unixctl_server
*unixctl
;
122 struct ovsdb_jsonrpc_server
*jsonrpc
;
123 struct sset remotes
, db_filenames
;
124 const char *db_filename
;
125 struct process
*run_process
;
128 long long int status_timer
= LLONG_MIN
;
129 FILE *config_tmpfile
;
130 struct server_config server_config
;
131 struct shash all_dbs
;
132 struct shash_node
*node
;
133 char *remotes_error
, *ssl_error
;
137 proctitle_init(argc
, argv
);
138 set_program_name(argv
[0]);
139 signal(SIGPIPE
, SIG_IGN
);
142 parse_options(&argc
, &argv
, &remotes
, &unixctl_path
, &run_command
);
144 /* Create and initialize 'config_tmpfile' as a temporary file to hold
145 * ovsdb-server's most basic configuration, and then save our initial
146 * configuration to it. When --monitor is used, this preserves the effects
147 * of ovs-appctl commands such as ovsdb-server/add-remote (which saves the
148 * new configuration) across crashes. */
149 config_tmpfile
= tmpfile();
150 if (!config_tmpfile
) {
151 ovs_fatal(errno
, "failed to create temporary file");
154 sset_init(&db_filenames
);
156 for (i
= 0; i
< argc
; i
++) {
157 sset_add(&db_filenames
, argv
[i
]);
160 char *default_db
= xasprintf("%s/conf.db", ovs_dbdir());
161 sset_add(&db_filenames
, default_db
);
165 server_config
.remotes
= &remotes
;
166 server_config
.config_tmpfile
= config_tmpfile
;
168 save_config__(config_tmpfile
, &remotes
, &db_filenames
);
172 /* Load the saved config. */
173 load_config(config_tmpfile
, &remotes
, &db_filenames
);
174 jsonrpc
= ovsdb_jsonrpc_server_create();
176 shash_init(&all_dbs
);
177 server_config
.all_dbs
= &all_dbs
;
178 server_config
.jsonrpc
= jsonrpc
;
179 SSET_FOR_EACH (db_filename
, &db_filenames
) {
180 error
= open_db(&server_config
, db_filename
);
182 ovs_fatal(0, "%s", error
);
186 error
= reconfigure_remotes(jsonrpc
, &all_dbs
, &remotes
);
188 error
= reconfigure_ssl(&all_dbs
);
191 ovs_fatal(0, "%s", error
);
194 retval
= unixctl_server_create(unixctl_path
, &unixctl
);
202 run_argv
[0] = "/bin/sh";
204 run_argv
[2] = run_command
;
207 retval
= process_start(run_argv
, &run_process
);
209 ovs_fatal(retval
, "%s: process failed to start", run_command
);
215 daemonize_complete();
218 /* ovsdb-server is usually a long-running process, in which case it
219 * makes plenty of sense to log the version, but --run makes
220 * ovsdb-server more like a command-line tool, so skip it. */
221 VLOG_INFO("%s (Open vSwitch) %s", program_name
, VERSION
);
224 unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit
, &exiting
);
225 unixctl_command_register("ovsdb-server/compact", "", 0, 1,
226 ovsdb_server_compact
, &all_dbs
);
227 unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
228 ovsdb_server_reconnect
, jsonrpc
);
230 unixctl_command_register("ovsdb-server/add-remote", "REMOTE", 1, 1,
231 ovsdb_server_add_remote
, &server_config
);
232 unixctl_command_register("ovsdb-server/remove-remote", "REMOTE", 1, 1,
233 ovsdb_server_remove_remote
, &server_config
);
234 unixctl_command_register("ovsdb-server/list-remotes", "", 0, 0,
235 ovsdb_server_list_remotes
, &remotes
);
237 unixctl_command_register("ovsdb-server/add-db", "DB", 1, 1,
238 ovsdb_server_add_database
, &server_config
);
239 unixctl_command_register("ovsdb-server/remove-db", "DB", 1, 1,
240 ovsdb_server_remove_database
, &server_config
);
241 unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
242 ovsdb_server_list_databases
, &all_dbs
);
246 remotes_error
= NULL
;
249 if (memory_should_report()) {
253 ovsdb_jsonrpc_server_get_memory_usage(jsonrpc
, &usage
);
254 SHASH_FOR_EACH(node
, &all_dbs
) {
255 struct db
*db
= node
->data
;
256 ovsdb_get_memory_usage(db
->db
, &usage
);
258 memory_report(&usage
);
259 simap_destroy(&usage
);
262 /* Run unixctl_server_run() before reconfigure_remotes() because
263 * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
264 * the set of remotes that reconfigure_remotes() uses. */
265 unixctl_server_run(unixctl
);
267 report_error_if_changed(
268 reconfigure_remotes(jsonrpc
, &all_dbs
, &remotes
),
270 report_error_if_changed(reconfigure_ssl(&all_dbs
), &ssl_error
);
271 ovsdb_jsonrpc_server_run(jsonrpc
);
273 SHASH_FOR_EACH(node
, &all_dbs
) {
274 struct db
*db
= node
->data
;
275 ovsdb_trigger_run(db
->db
, time_msec());
279 if (process_exited(run_process
)) {
284 /* update Manager status(es) every 5 seconds */
285 if (time_msec() >= status_timer
) {
286 status_timer
= time_msec() + 5000;
287 update_remote_status(jsonrpc
, &remotes
, &all_dbs
);
291 ovsdb_jsonrpc_server_wait(jsonrpc
);
292 unixctl_server_wait(unixctl
);
293 SHASH_FOR_EACH(node
, &all_dbs
) {
294 struct db
*db
= node
->data
;
295 ovsdb_trigger_wait(db
->db
, time_msec());
298 process_wait(run_process
);
301 poll_immediate_wake();
303 poll_timer_wait_until(status_timer
);
306 ovsdb_jsonrpc_server_destroy(jsonrpc
);
307 SHASH_FOR_EACH(node
, &all_dbs
) {
308 struct db
*db
= node
->data
;
309 ovsdb_destroy(db
->db
);
311 sset_destroy(&remotes
);
312 unixctl_server_destroy(unixctl
);
314 if (run_process
&& process_exited(run_process
)) {
315 int status
= process_status(run_process
);
317 ovs_fatal(0, "%s: child exited, %s",
318 run_command
, process_status_msg(status
));
326 open_db(struct server_config
*config
, const char *filename
)
328 struct ovsdb_error
*db_error
;
332 db
= xzalloc(sizeof *db
);
333 db
->filename
= xstrdup(filename
);
335 db_error
= ovsdb_file_open(db
->filename
, false, &db
->db
, &db
->file
);
337 error
= ovsdb_error_to_string(db_error
);
338 } else if (!ovsdb_jsonrpc_server_add_db(config
->jsonrpc
, db
->db
)) {
339 error
= xasprintf("%s: duplicate database name", db
->db
->schema
->name
);
341 shash_add_assert(config
->all_dbs
, db
->db
->schema
->name
, db
);
345 ovsdb_error_destroy(db_error
);
346 ovsdb_destroy(db
->db
);
352 static const struct db
*
353 find_db(const struct shash
*all_dbs
, const char *db_name
)
355 struct shash_node
*node
;
357 SHASH_FOR_EACH(node
, all_dbs
) {
358 struct db
*db
= node
->data
;
359 if (!strcmp(db
->db
->schema
->name
, db_name
)) {
367 static char * WARN_UNUSED_RESULT
368 parse_db_column__(const struct shash
*all_dbs
,
369 const char *name_
, char *name
,
370 const struct db
**dbp
,
371 const struct ovsdb_table
**tablep
,
372 const struct ovsdb_column
**columnp
)
374 const char *db_name
, *table_name
, *column_name
;
375 const struct ovsdb_column
*column
;
376 const struct ovsdb_table
*table
;
377 const char *tokens
[3];
378 char *save_ptr
= NULL
;
385 strtok_r(name
, ":", &save_ptr
); /* "db:" */
386 tokens
[0] = strtok_r(NULL
, ",", &save_ptr
);
387 tokens
[1] = strtok_r(NULL
, ",", &save_ptr
);
388 tokens
[2] = strtok_r(NULL
, ",", &save_ptr
);
389 if (!tokens
[0] || !tokens
[1] || !tokens
[2]) {
390 return xasprintf("\"%s\": invalid syntax", name_
);
394 table_name
= tokens
[1];
395 column_name
= tokens
[2];
397 db
= find_db(all_dbs
, tokens
[0]);
399 return xasprintf("\"%s\": no database named %s", name_
, db_name
);
402 table
= ovsdb_get_table(db
->db
, table_name
);
404 return xasprintf("\"%s\": no table named %s", name_
, table_name
);
407 column
= ovsdb_table_schema_get_column(table
->schema
, column_name
);
409 return xasprintf("\"%s\": table \"%s\" has no column \"%s\"",
410 name_
, table_name
, column_name
);
419 /* Returns NULL if successful, otherwise a malloc()'d string describing the
421 static char * WARN_UNUSED_RESULT
422 parse_db_column(const struct shash
*all_dbs
,
424 const struct db
**dbp
,
425 const struct ovsdb_table
**tablep
,
426 const struct ovsdb_column
**columnp
)
428 char *name
= xstrdup(name_
);
429 char *retval
= parse_db_column__(all_dbs
, name_
, name
,
430 dbp
, tablep
, columnp
);
435 /* Returns NULL if successful, otherwise a malloc()'d string describing the
437 static char * WARN_UNUSED_RESULT
438 parse_db_string_column(const struct shash
*all_dbs
,
440 const struct db
**dbp
,
441 const struct ovsdb_table
**tablep
,
442 const struct ovsdb_column
**columnp
)
446 retval
= parse_db_column(all_dbs
, name
, dbp
, tablep
, columnp
);
451 if ((*columnp
)->type
.key
.type
!= OVSDB_TYPE_STRING
452 || (*columnp
)->type
.value
.type
!= OVSDB_TYPE_VOID
) {
453 return xasprintf("\"%s\": table \"%s\" column \"%s\" is "
454 "not string or set of strings",
455 name
, (*tablep
)->schema
->name
, (*columnp
)->name
);
462 query_db_string(const struct shash
*all_dbs
, const char *name
,
465 if (!name
|| strncmp(name
, "db:", 3)) {
468 const struct ovsdb_column
*column
;
469 const struct ovsdb_table
*table
;
470 const struct ovsdb_row
*row
;
474 retval
= parse_db_string_column(all_dbs
, name
,
475 &db
, &table
, &column
);
477 ds_put_format(errors
, "%s\n", retval
);
481 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
482 const struct ovsdb_datum
*datum
;
485 datum
= &row
->fields
[column
->index
];
486 for (i
= 0; i
< datum
->n
; i
++) {
487 if (datum
->keys
[i
].string
[0]) {
488 return datum
->keys
[i
].string
;
496 static struct ovsdb_jsonrpc_options
*
497 add_remote(struct shash
*remotes
, const char *target
)
499 struct ovsdb_jsonrpc_options
*options
;
501 options
= shash_find_data(remotes
, target
);
503 options
= ovsdb_jsonrpc_default_options(target
);
504 shash_add(remotes
, target
, options
);
510 static struct ovsdb_datum
*
511 get_datum(struct ovsdb_row
*row
, const char *column_name
,
512 const enum ovsdb_atomic_type key_type
,
513 const enum ovsdb_atomic_type value_type
,
516 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
517 const struct ovsdb_table_schema
*schema
= row
->table
->schema
;
518 const struct ovsdb_column
*column
;
520 column
= ovsdb_table_schema_get_column(schema
, column_name
);
522 VLOG_DBG_RL(&rl
, "Table `%s' has no `%s' column",
523 schema
->name
, column_name
);
527 if (column
->type
.key
.type
!= key_type
528 || column
->type
.value
.type
!= value_type
529 || column
->type
.n_max
!= n_max
) {
530 if (!VLOG_DROP_DBG(&rl
)) {
531 char *type_name
= ovsdb_type_to_english(&column
->type
);
532 VLOG_DBG("Table `%s' column `%s' has type %s, not expected "
533 "key type %s, value type %s, max elements %zd.",
534 schema
->name
, column_name
, type_name
,
535 ovsdb_atomic_type_to_string(key_type
),
536 ovsdb_atomic_type_to_string(value_type
),
543 return &row
->fields
[column
->index
];
546 /* Read string-string key-values from a map. Returns the value associated with
547 * 'key', if found, or NULL */
549 read_map_string_column(const struct ovsdb_row
*row
, const char *column_name
,
552 const struct ovsdb_datum
*datum
;
553 union ovsdb_atom
*atom_key
= NULL
, *atom_value
= NULL
;
556 datum
= get_datum(CONST_CAST(struct ovsdb_row
*, row
), column_name
,
557 OVSDB_TYPE_STRING
, OVSDB_TYPE_STRING
, UINT_MAX
);
563 for (i
= 0; i
< datum
->n
; i
++) {
564 atom_key
= &datum
->keys
[i
];
565 if (!strcmp(atom_key
->string
, key
)){
566 atom_value
= &datum
->values
[i
];
571 return atom_value
? atom_value
->string
: NULL
;
574 static const union ovsdb_atom
*
575 read_column(const struct ovsdb_row
*row
, const char *column_name
,
576 enum ovsdb_atomic_type type
)
578 const struct ovsdb_datum
*datum
;
580 datum
= get_datum(CONST_CAST(struct ovsdb_row
*, row
), column_name
, type
,
582 return datum
&& datum
->n
? datum
->keys
: NULL
;
586 read_integer_column(const struct ovsdb_row
*row
, const char *column_name
,
587 long long int *integerp
)
589 const union ovsdb_atom
*atom
;
591 atom
= read_column(row
, column_name
, OVSDB_TYPE_INTEGER
);
592 *integerp
= atom
? atom
->integer
: 0;
597 read_string_column(const struct ovsdb_row
*row
, const char *column_name
,
598 const char **stringp
)
600 const union ovsdb_atom
*atom
;
602 atom
= read_column(row
, column_name
, OVSDB_TYPE_STRING
);
603 *stringp
= atom
? atom
->string
: NULL
;
608 write_bool_column(struct ovsdb_row
*row
, const char *column_name
, bool value
)
610 const struct ovsdb_column
*column
;
611 struct ovsdb_datum
*datum
;
613 column
= ovsdb_table_schema_get_column(row
->table
->schema
, column_name
);
614 datum
= get_datum(row
, column_name
, OVSDB_TYPE_BOOLEAN
,
621 ovsdb_datum_destroy(datum
, &column
->type
);
624 datum
->keys
= xmalloc(sizeof *datum
->keys
);
625 datum
->values
= NULL
;
628 datum
->keys
[0].boolean
= value
;
632 write_string_string_column(struct ovsdb_row
*row
, const char *column_name
,
633 char **keys
, char **values
, size_t n
)
635 const struct ovsdb_column
*column
;
636 struct ovsdb_datum
*datum
;
639 column
= ovsdb_table_schema_get_column(row
->table
->schema
, column_name
);
640 datum
= get_datum(row
, column_name
, OVSDB_TYPE_STRING
, OVSDB_TYPE_STRING
,
643 for (i
= 0; i
< n
; i
++) {
650 /* Free existing data. */
651 ovsdb_datum_destroy(datum
, &column
->type
);
653 /* Allocate space for new values. */
655 datum
->keys
= xmalloc(n
* sizeof *datum
->keys
);
656 datum
->values
= xmalloc(n
* sizeof *datum
->values
);
658 for (i
= 0; i
< n
; ++i
) {
659 datum
->keys
[i
].string
= keys
[i
];
660 datum
->values
[i
].string
= values
[i
];
663 /* Sort and check constraints. */
664 ovsdb_datum_sort_assert(datum
, column
->type
.key
.type
);
667 /* Adds a remote and options to 'remotes', based on the Manager table row in
670 add_manager_options(struct shash
*remotes
, const struct ovsdb_row
*row
)
672 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
673 struct ovsdb_jsonrpc_options
*options
;
674 long long int max_backoff
, probe_interval
;
675 const char *target
, *dscp_string
;
677 if (!read_string_column(row
, "target", &target
) || !target
) {
678 VLOG_INFO_RL(&rl
, "Table `%s' has missing or invalid `target' column",
679 row
->table
->schema
->name
);
683 options
= add_remote(remotes
, target
);
684 if (read_integer_column(row
, "max_backoff", &max_backoff
)) {
685 options
->max_backoff
= max_backoff
;
687 if (read_integer_column(row
, "inactivity_probe", &probe_interval
)) {
688 options
->probe_interval
= probe_interval
;
691 options
->dscp
= DSCP_DEFAULT
;
692 dscp_string
= read_map_string_column(row
, "other_config", "dscp");
694 int dscp
= atoi(dscp_string
);
695 if (dscp
>= 0 && dscp
<= 63) {
696 options
->dscp
= dscp
;
702 query_db_remotes(const char *name
, const struct shash
*all_dbs
,
703 struct shash
*remotes
, struct ds
*errors
)
705 const struct ovsdb_column
*column
;
706 const struct ovsdb_table
*table
;
707 const struct ovsdb_row
*row
;
711 retval
= parse_db_column(all_dbs
, name
, &db
, &table
, &column
);
713 ds_put_format(errors
, "%s\n", retval
);
718 if (column
->type
.key
.type
== OVSDB_TYPE_STRING
719 && column
->type
.value
.type
== OVSDB_TYPE_VOID
) {
720 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
721 const struct ovsdb_datum
*datum
;
724 datum
= &row
->fields
[column
->index
];
725 for (i
= 0; i
< datum
->n
; i
++) {
726 add_remote(remotes
, datum
->keys
[i
].string
);
729 } else if (column
->type
.key
.type
== OVSDB_TYPE_UUID
730 && column
->type
.key
.u
.uuid
.refTable
731 && column
->type
.value
.type
== OVSDB_TYPE_VOID
) {
732 const struct ovsdb_table
*ref_table
= column
->type
.key
.u
.uuid
.refTable
;
733 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
734 const struct ovsdb_datum
*datum
;
737 datum
= &row
->fields
[column
->index
];
738 for (i
= 0; i
< datum
->n
; i
++) {
739 const struct ovsdb_row
*ref_row
;
741 ref_row
= ovsdb_table_get_row(ref_table
, &datum
->keys
[i
].uuid
);
743 add_manager_options(remotes
, ref_row
);
751 update_remote_row(const struct ovsdb_row
*row
, struct ovsdb_txn
*txn
,
752 const struct ovsdb_jsonrpc_server
*jsonrpc
)
754 struct ovsdb_jsonrpc_remote_status status
;
755 struct ovsdb_row
*rw_row
;
757 char *keys
[9], *values
[9];
760 /* Get the "target" (protocol/host/port) spec. */
761 if (!read_string_column(row
, "target", &target
)) {
762 /* Bad remote spec or incorrect schema. */
765 rw_row
= ovsdb_txn_row_modify(txn
, row
);
766 ovsdb_jsonrpc_server_get_remote_status(jsonrpc
, target
, &status
);
768 /* Update status information columns. */
769 write_bool_column(rw_row
, "is_connected", status
.is_connected
);
772 keys
[n
] = xstrdup("state");
773 values
[n
++] = xstrdup(status
.state
);
775 if (status
.sec_since_connect
!= UINT_MAX
) {
776 keys
[n
] = xstrdup("sec_since_connect");
777 values
[n
++] = xasprintf("%u", status
.sec_since_connect
);
779 if (status
.sec_since_disconnect
!= UINT_MAX
) {
780 keys
[n
] = xstrdup("sec_since_disconnect");
781 values
[n
++] = xasprintf("%u", status
.sec_since_disconnect
);
783 if (status
.last_error
) {
784 keys
[n
] = xstrdup("last_error");
786 xstrdup(ovs_retval_to_string(status
.last_error
));
788 if (status
.locks_held
&& status
.locks_held
[0]) {
789 keys
[n
] = xstrdup("locks_held");
790 values
[n
++] = xstrdup(status
.locks_held
);
792 if (status
.locks_waiting
&& status
.locks_waiting
[0]) {
793 keys
[n
] = xstrdup("locks_waiting");
794 values
[n
++] = xstrdup(status
.locks_waiting
);
796 if (status
.locks_lost
&& status
.locks_lost
[0]) {
797 keys
[n
] = xstrdup("locks_lost");
798 values
[n
++] = xstrdup(status
.locks_lost
);
800 if (status
.n_connections
> 1) {
801 keys
[n
] = xstrdup("n_connections");
802 values
[n
++] = xasprintf("%d", status
.n_connections
);
804 if (status
.bound_port
!= htons(0)) {
805 keys
[n
] = xstrdup("bound_port");
806 values
[n
++] = xasprintf("%"PRIu16
, ntohs(status
.bound_port
));
808 write_string_string_column(rw_row
, "status", keys
, values
, n
);
810 ovsdb_jsonrpc_server_free_remote_status(&status
);
814 update_remote_rows(const struct shash
*all_dbs
,
815 const char *remote_name
,
816 const struct ovsdb_jsonrpc_server
*jsonrpc
)
818 const struct ovsdb_table
*table
, *ref_table
;
819 const struct ovsdb_column
*column
;
820 const struct ovsdb_row
*row
;
824 if (strncmp("db:", remote_name
, 3)) {
828 retval
= parse_db_column(all_dbs
, remote_name
, &db
, &table
, &column
);
834 if (column
->type
.key
.type
!= OVSDB_TYPE_UUID
835 || !column
->type
.key
.u
.uuid
.refTable
836 || column
->type
.value
.type
!= OVSDB_TYPE_VOID
) {
840 ref_table
= column
->type
.key
.u
.uuid
.refTable
;
842 HMAP_FOR_EACH (row
, hmap_node
, &table
->rows
) {
843 const struct ovsdb_datum
*datum
;
846 datum
= &row
->fields
[column
->index
];
847 for (i
= 0; i
< datum
->n
; i
++) {
848 const struct ovsdb_row
*ref_row
;
850 ref_row
= ovsdb_table_get_row(ref_table
, &datum
->keys
[i
].uuid
);
852 update_remote_row(ref_row
, db
->txn
, jsonrpc
);
859 update_remote_status(const struct ovsdb_jsonrpc_server
*jsonrpc
,
860 const struct sset
*remotes
,
861 struct shash
*all_dbs
)
863 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
866 struct shash_node
*node
;
868 SHASH_FOR_EACH(node
, all_dbs
) {
870 db
->txn
= ovsdb_txn_create(db
->db
);
873 /* Iterate over --remote arguments given on command line. */
874 SSET_FOR_EACH (remote
, remotes
) {
875 update_remote_rows(all_dbs
, remote
, jsonrpc
);
878 SHASH_FOR_EACH(node
, all_dbs
) {
879 struct ovsdb_error
*error
;
881 error
= ovsdb_txn_commit(db
->txn
, false);
883 VLOG_ERR_RL(&rl
, "Failed to update remote status: %s",
884 ovsdb_error_to_string(error
));
885 ovsdb_error_destroy(error
);
890 /* Reconfigures ovsdb-server's remotes based on information in the database. */
892 reconfigure_remotes(struct ovsdb_jsonrpc_server
*jsonrpc
,
893 const struct shash
*all_dbs
, struct sset
*remotes
)
895 struct ds errors
= DS_EMPTY_INITIALIZER
;
896 struct shash resolved_remotes
;
899 /* Configure remotes. */
900 shash_init(&resolved_remotes
);
901 SSET_FOR_EACH (name
, remotes
) {
902 if (!strncmp(name
, "db:", 3)) {
903 query_db_remotes(name
, all_dbs
, &resolved_remotes
, &errors
);
905 add_remote(&resolved_remotes
, name
);
908 ovsdb_jsonrpc_server_set_remotes(jsonrpc
, &resolved_remotes
);
909 shash_destroy_free_data(&resolved_remotes
);
911 return errors
.string
;
915 reconfigure_ssl(const struct shash
*all_dbs
)
917 struct ds errors
= DS_EMPTY_INITIALIZER
;
918 const char *resolved_private_key
;
919 const char *resolved_certificate
;
920 const char *resolved_ca_cert
;
922 resolved_private_key
= query_db_string(all_dbs
, private_key_file
, &errors
);
923 resolved_certificate
= query_db_string(all_dbs
, certificate_file
, &errors
);
924 resolved_ca_cert
= query_db_string(all_dbs
, ca_cert_file
, &errors
);
926 stream_ssl_set_key_and_cert(resolved_private_key
, resolved_certificate
);
927 stream_ssl_set_ca_cert_file(resolved_ca_cert
, bootstrap_ca_cert
);
929 return errors
.string
;
933 report_error_if_changed(char *error
, char **last_errorp
)
936 if (!*last_errorp
|| strcmp(error
, *last_errorp
)) {
937 VLOG_WARN("%s", error
);
939 *last_errorp
= error
;
950 ovsdb_server_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
951 const char *argv
[] OVS_UNUSED
,
954 bool *exiting
= exiting_
;
956 unixctl_command_reply(conn
, NULL
);
960 ovsdb_server_compact(struct unixctl_conn
*conn
, int argc
,
961 const char *argv
[], void *dbs_
)
963 struct shash
*all_dbs
= dbs_
;
966 struct shash_node
*node
;
970 SHASH_FOR_EACH(node
, all_dbs
) {
974 name
= db
->db
->schema
->name
;
976 if (argc
< 2 || !strcmp(argv
[1], name
)) {
977 struct ovsdb_error
*error
;
979 VLOG_INFO("compacting %s database by user request", name
);
981 error
= ovsdb_file_compact(db
->file
);
983 char *s
= ovsdb_error_to_string(error
);
984 ds_put_format(&reply
, "%s\n", s
);
993 unixctl_command_reply_error(conn
, "no database by that name");
994 } else if (reply
.length
) {
995 unixctl_command_reply_error(conn
, ds_cstr(&reply
));
997 unixctl_command_reply(conn
, NULL
);
1002 /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC
1003 * connections and reconnect. */
1005 ovsdb_server_reconnect(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1006 const char *argv
[] OVS_UNUSED
, void *jsonrpc_
)
1008 struct ovsdb_jsonrpc_server
*jsonrpc
= jsonrpc_
;
1010 ovsdb_jsonrpc_server_reconnect(jsonrpc
);
1011 unixctl_command_reply(conn
, NULL
);
1014 /* "ovsdb-server/add-remote REMOTE": adds REMOTE to the set of remotes that
1015 * ovsdb-server services. */
1017 ovsdb_server_add_remote(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1018 const char *argv
[], void *config_
)
1020 struct server_config
*config
= config_
;
1021 const char *remote
= argv
[1];
1023 const struct ovsdb_column
*column
;
1024 const struct ovsdb_table
*table
;
1025 const struct db
*db
;
1028 retval
= (strncmp("db:", remote
, 3)
1030 : parse_db_column(config
->all_dbs
, remote
,
1031 &db
, &table
, &column
));
1033 if (sset_add(config
->remotes
, remote
)) {
1034 save_config(config
);
1036 unixctl_command_reply(conn
, NULL
);
1038 unixctl_command_reply_error(conn
, retval
);
1043 /* "ovsdb-server/remove-remote REMOTE": removes REMOTE frmo the set of remotes
1044 * that ovsdb-server services. */
1046 ovsdb_server_remove_remote(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1047 const char *argv
[], void *config_
)
1049 struct server_config
*config
= config_
;
1050 struct sset_node
*node
;
1052 node
= sset_find(config
->remotes
, argv
[1]);
1054 sset_delete(config
->remotes
, node
);
1055 save_config(config
);
1056 unixctl_command_reply(conn
, NULL
);
1058 unixctl_command_reply_error(conn
, "no such remote");
1062 /* "ovsdb-server/list-remotes": outputs a list of configured rmeotes. */
1064 ovsdb_server_list_remotes(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1065 const char *argv
[] OVS_UNUSED
, void *remotes_
)
1067 struct sset
*remotes
= remotes_
;
1068 const char **list
, **p
;
1073 list
= sset_sort(remotes
);
1074 for (p
= list
; *p
; p
++) {
1075 ds_put_format(&s
, "%s\n", *p
);
1079 unixctl_command_reply(conn
, ds_cstr(&s
));
1084 /* "ovsdb-server/add-db DB": adds the DB to ovsdb-server. */
1086 ovsdb_server_add_database(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1087 const char *argv
[], void *config_
)
1089 struct server_config
*config
= config_
;
1090 const char *filename
= argv
[1];
1093 error
= open_db(config
, filename
);
1095 save_config(config
);
1096 unixctl_command_reply(conn
, NULL
);
1098 unixctl_command_reply_error(conn
, error
);
1104 ovsdb_server_remove_database(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1105 const char *argv
[], void *config_
)
1107 struct server_config
*config
= config_
;
1108 struct shash_node
*node
;
1112 node
= shash_find(config
->all_dbs
, argv
[1]);
1114 unixctl_command_reply_error(conn
, "Failed to find the database.");
1119 ok
= ovsdb_jsonrpc_server_remove_db(config
->jsonrpc
, db
->db
);
1122 ovsdb_destroy(db
->db
);
1123 shash_delete(config
->all_dbs
, node
);
1127 save_config(config
);
1128 unixctl_command_reply(conn
, NULL
);
1132 ovsdb_server_list_databases(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1133 const char *argv
[] OVS_UNUSED
, void *all_dbs_
)
1135 struct shash
*all_dbs
= all_dbs_
;
1136 const struct shash_node
**nodes
;
1142 nodes
= shash_sort(all_dbs
);
1143 for (i
= 0; i
< shash_count(all_dbs
); i
++) {
1144 struct db
*db
= nodes
[i
]->data
;
1145 ds_put_format(&s
, "%s\n", db
->db
->schema
->name
);
1149 unixctl_command_reply(conn
, ds_cstr(&s
));
1154 parse_options(int *argcp
, char **argvp
[],
1155 struct sset
*remotes
, char **unixctl_pathp
, char **run_command
)
1158 OPT_REMOTE
= UCHAR_MAX
+ 1,
1161 OPT_BOOTSTRAP_CA_CERT
,
1166 static const struct option long_options
[] = {
1167 {"remote", required_argument
, NULL
, OPT_REMOTE
},
1168 {"unixctl", required_argument
, NULL
, OPT_UNIXCTL
},
1169 {"run", required_argument
, NULL
, OPT_RUN
},
1170 {"help", no_argument
, NULL
, 'h'},
1171 {"version", no_argument
, NULL
, 'V'},
1172 DAEMON_LONG_OPTIONS
,
1174 {"bootstrap-ca-cert", required_argument
, NULL
, OPT_BOOTSTRAP_CA_CERT
},
1175 {"private-key", required_argument
, NULL
, 'p'},
1176 {"certificate", required_argument
, NULL
, 'c'},
1177 {"ca-cert", required_argument
, NULL
, 'C'},
1178 {"enable-dummy", optional_argument
, NULL
, OPT_ENABLE_DUMMY
},
1181 char *short_options
= long_options_to_short_options(long_options
);
1183 char **argv
= *argvp
;
1189 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
1196 sset_add(remotes
, optarg
);
1200 *unixctl_pathp
= optarg
;
1204 *run_command
= optarg
;
1211 ovs_print_version(0, 0);
1214 VLOG_OPTION_HANDLERS
1215 DAEMON_OPTION_HANDLERS
1218 private_key_file
= optarg
;
1222 certificate_file
= optarg
;
1226 ca_cert_file
= optarg
;
1227 bootstrap_ca_cert
= false;
1230 case OPT_BOOTSTRAP_CA_CERT
:
1231 ca_cert_file
= optarg
;
1232 bootstrap_ca_cert
= true;
1235 case OPT_ENABLE_DUMMY
:
1236 dummy_enable(optarg
&& !strcmp(optarg
, "override"));
1246 free(short_options
);
1255 printf("%s: Open vSwitch database server\n"
1256 "usage: %s [OPTIONS] [DATABASE...]\n"
1257 "where each DATABASE is a database file in ovsdb format.\n"
1258 "The default DATABASE, if none is given, is\n%s/conf.db.\n",
1259 program_name
, program_name
, ovs_dbdir());
1260 printf("\nJSON-RPC options (may be specified any number of times):\n"
1261 " --remote=REMOTE connect or listen to REMOTE\n");
1262 stream_usage("JSON-RPC", true, true, true);
1265 printf("\nOther options:\n"
1266 " --run COMMAND run COMMAND as subprocess then exit\n"
1267 " --unixctl=SOCKET override default control socket name\n"
1268 " -h, --help display this help message\n"
1269 " -V, --version display version information\n");
1273 static struct json
*
1274 sset_to_json(const struct sset
*sset
)
1279 array
= json_array_create_empty();
1280 SSET_FOR_EACH (s
, sset
) {
1281 json_array_add(array
, json_string_create(s
));
1286 /* Truncates and replaces the contents of 'config_file' by a representation of
1287 * 'remotes' and 'db_filenames'. */
1289 save_config__(FILE *config_file
, const struct sset
*remotes
,
1290 const struct sset
*db_filenames
)
1295 if (ftruncate(fileno(config_file
), 0) == -1) {
1296 VLOG_FATAL("failed to truncate temporary file (%s)",
1297 ovs_strerror(errno
));
1300 obj
= json_object_create();
1301 json_object_put(obj
, "remotes", sset_to_json(remotes
));
1302 json_object_put(obj
, "db_filenames", sset_to_json(db_filenames
));
1303 s
= json_to_string(obj
, 0);
1306 if (fseek(config_file
, 0, SEEK_SET
) != 0
1307 || fputs(s
, config_file
) == EOF
1308 || fflush(config_file
) == EOF
) {
1309 VLOG_FATAL("failed to write temporary file (%s)", ovs_strerror(errno
));
1314 /* Truncates and replaces the contents of 'config_file' by a representation of
1317 save_config(struct server_config
*config
)
1319 struct sset db_filenames
;
1320 struct shash_node
*node
;
1322 sset_init(&db_filenames
);
1323 SHASH_FOR_EACH (node
, config
->all_dbs
) {
1324 struct db
*db
= node
->data
;
1325 sset_add(&db_filenames
, db
->filename
);
1328 save_config__(config
->config_tmpfile
, config
->remotes
, &db_filenames
);
1330 sset_destroy(&db_filenames
);
1334 sset_from_json(struct sset
*sset
, const struct json
*array
)
1340 ovs_assert(array
->type
== JSON_ARRAY
);
1341 for (i
= 0; i
< array
->u
.array
.n
; i
++) {
1342 const struct json
*elem
= array
->u
.array
.elems
[i
];
1343 sset_add(sset
, json_string(elem
));
1347 /* Clears and replaces 'remotes' and 'dbnames' by a configuration read from
1348 * 'config_file', which must have been previously written by save_config(). */
1350 load_config(FILE *config_file
, struct sset
*remotes
, struct sset
*db_filenames
)
1354 if (fseek(config_file
, 0, SEEK_SET
) != 0) {
1355 VLOG_FATAL("seek failed in temporary file (%s)", ovs_strerror(errno
));
1357 json
= json_from_stream(config_file
);
1358 if (json
->type
== JSON_STRING
) {
1359 VLOG_FATAL("reading json failed (%s)", json_string(json
));
1361 ovs_assert(json
->type
== JSON_OBJECT
);
1363 sset_from_json(remotes
, shash_find_data(json_object(json
), "remotes"));
1364 sset_from_json(db_filenames
,
1365 shash_find_data(json_object(json
), "db_filenames"));