Acked-by: Ethan Jackson <et...@nicira.com>
On Fri, Sep 21, 2012 at 11:26 AM, Ben Pfaff <b...@nicira.com> wrote: > The OVSDB protocol has supported multiple databases for a long time, but > the ovsdb-server implementation only supported one database at a time. > This commit adds support for multiple databases. > > Feature #12353. > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > ovsdb/jsonrpc-server.c | 115 ++++++++++++-------- > ovsdb/jsonrpc-server.h | 4 +- > ovsdb/ovsdb-server.1.in | 32 +++--- > ovsdb/ovsdb-server.c | 273 > ++++++++++++++++++++++++++++++++--------------- > ovsdb/server.c | 28 ++++-- > ovsdb/server.h | 13 ++- > ovsdb/trigger.c | 9 +- > ovsdb/trigger.h | 8 +- > tests/ovsdb-server.at | 61 ++++++++--- > tests/test-ovsdb.c | 8 +- > utilities/ovs-ctl.8 | 6 + > utilities/ovs-ctl.in | 17 +++- > 12 files changed, 392 insertions(+), 182 deletions(-) > > diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c > index bb887d0..279ea97 100644 > --- a/ovsdb/jsonrpc-server.c > +++ b/ovsdb/jsonrpc-server.c > @@ -66,6 +66,7 @@ static void ovsdb_jsonrpc_session_unlock__(struct > ovsdb_lock_waiter *); > > /* Triggers. */ > static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *, > + struct ovsdb *, > struct json *id, struct json > *params); > static struct ovsdb_jsonrpc_trigger *ovsdb_jsonrpc_trigger_find( > struct ovsdb_jsonrpc_session *, const struct json *id, size_t hash); > @@ -76,7 +77,7 @@ static void ovsdb_jsonrpc_trigger_complete_done( > > /* Monitors. */ > static struct json *ovsdb_jsonrpc_monitor_create( > - struct ovsdb_jsonrpc_session *, struct json *params); > + struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params); > static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel( > struct ovsdb_jsonrpc_session *, > struct json_array *params, > @@ -106,16 +107,29 @@ static struct ovsdb_jsonrpc_remote > *ovsdb_jsonrpc_server_add_remote( > ); > static void ovsdb_jsonrpc_server_del_remote(struct shash_node *); > > +/* Creates and returns a new server to provide JSON-RPC access to an OVSDB. > + * > + * The caller must call ovsdb_jsonrpc_server_add_db() for each database to > + * which 'server' should provide access. */ > struct ovsdb_jsonrpc_server * > -ovsdb_jsonrpc_server_create(struct ovsdb *db) > +ovsdb_jsonrpc_server_create(void) > { > struct ovsdb_jsonrpc_server *server = xzalloc(sizeof *server); > - ovsdb_server_init(&server->up, db); > + ovsdb_server_init(&server->up); > server->max_sessions = 64; > shash_init(&server->remotes); > return server; > } > > +/* Adds 'db' to the set of databases served out by 'svr'. Returns true if > + * successful, false if 'db''s name is the same as some database already in > + * 'server'. */ > +bool > +ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb > *db) > +{ > + return ovsdb_server_add_db(&svr->up, db); > +} > + > void > ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *svr) > { > @@ -350,7 +364,7 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote > *remote, > struct ovsdb_jsonrpc_session *s; > > s = xzalloc(sizeof *s); > - ovsdb_session_init(&s->up, remote->server->up.db); > + ovsdb_session_init(&s->up, &remote->server->up); > s->remote = remote; > list_push_back(&remote->sessions, &s->node); > hmap_init(&s->triggers); > @@ -558,21 +572,22 @@ ovsdb_jsonrpc_session_get_status(const struct > ovsdb_jsonrpc_remote *remote, > return true; > } > > -static const char * > -get_db_name(const struct ovsdb_jsonrpc_session *s) > -{ > - return s->remote->server->up.db->schema->name; > -} > - > -static struct jsonrpc_msg * > -ovsdb_jsonrpc_check_db_name(const struct ovsdb_jsonrpc_session *s, > - const struct jsonrpc_msg *request) > +/* Examines 'request' to determine the database to which it relates, and then > + * searches 's' to find that database: > + * > + * - If successful, returns the database and sets '*replyp' to NULL. > + * > + * - If no such database exists, returns NULL and sets '*replyp' to an > + * appropriate JSON-RPC error reply, owned by the caller. */ > +static struct ovsdb * > +ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s, > + const struct jsonrpc_msg *request, > + struct jsonrpc_msg **replyp) > { > struct json_array *params; > - const char *want_db_name; > - const char *have_db_name; > struct ovsdb_error *error; > - struct jsonrpc_msg *reply; > + const char *db_name; > + struct ovsdb *db; > > params = json_array(request->params); > if (!params->n || params->elems[0]->type != JSON_STRING) { > @@ -582,22 +597,23 @@ ovsdb_jsonrpc_check_db_name(const struct > ovsdb_jsonrpc_session *s, > goto error; > } > > - want_db_name = params->elems[0]->u.string; > - have_db_name = get_db_name(s); > - if (strcmp(want_db_name, have_db_name)) { > + db_name = params->elems[0]->u.string; > + db = shash_find_data(&s->up.server->dbs, db_name); > + if (!db) { > error = ovsdb_syntax_error( > request->params, "unknown database", > "%s request specifies unknown database %s", > - request->method, want_db_name); > + request->method, db_name); > goto error; > } > > - return NULL; > + *replyp = NULL; > + return db; > > error: > - reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id); > + *replyp = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id); > ovsdb_error_destroy(error); > - return reply; > + return NULL; > } > > static struct ovsdb_error * > @@ -739,10 +755,10 @@ error: > } > > static struct jsonrpc_msg * > -execute_transaction(struct ovsdb_jsonrpc_session *s, > +execute_transaction(struct ovsdb_jsonrpc_session *s, struct ovsdb *db, > struct jsonrpc_msg *request) > { > - ovsdb_jsonrpc_trigger_create(s, request->id, request->params); > + ovsdb_jsonrpc_trigger_create(s, db, request->id, request->params); > request->id = NULL; > request->params = NULL; > jsonrpc_msg_destroy(request); > @@ -756,30 +772,39 @@ ovsdb_jsonrpc_session_got_request(struct > ovsdb_jsonrpc_session *s, > struct jsonrpc_msg *reply; > > if (!strcmp(request->method, "transact")) { > - reply = ovsdb_jsonrpc_check_db_name(s, request); > + struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply); > if (!reply) { > - reply = execute_transaction(s, request); > + reply = execute_transaction(s, db, request); > } > } else if (!strcmp(request->method, "monitor")) { > - reply = ovsdb_jsonrpc_check_db_name(s, request); > + struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply); > if (!reply) { > reply = jsonrpc_create_reply( > - ovsdb_jsonrpc_monitor_create(s, request->params), > request->id); > + ovsdb_jsonrpc_monitor_create(s, db, request->params), > + request->id); > } > } else if (!strcmp(request->method, "monitor_cancel")) { > reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params), > request->id); > } else if (!strcmp(request->method, "get_schema")) { > - reply = ovsdb_jsonrpc_check_db_name(s, request); > + struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply); > if (!reply) { > - reply = jsonrpc_create_reply( > - ovsdb_schema_to_json(s->remote->server->up.db->schema), > - request->id); > + reply = jsonrpc_create_reply(ovsdb_schema_to_json(db->schema), > + request->id); > } > } else if (!strcmp(request->method, "list_dbs")) { > - reply = jsonrpc_create_reply( > - json_array_create_1(json_string_create(get_db_name(s))), > - request->id); > + size_t n_dbs = shash_count(&s->up.server->dbs); > + struct shash_node *node; > + struct json **dbs; > + size_t i; > + > + dbs = xmalloc(n_dbs * sizeof *dbs); > + i = 0; > + SHASH_FOR_EACH (node, &s->up.server->dbs) { > + dbs[i++] = json_string_create(node->name); > + } > + reply = jsonrpc_create_reply(json_array_create(dbs, n_dbs), > + request->id); > } else if (!strcmp(request->method, "lock")) { > reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT); > } else if (!strcmp(request->method, "steal")) { > @@ -836,7 +861,7 @@ struct ovsdb_jsonrpc_trigger { > }; > > static void > -ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, > +ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb > *db, > struct json *id, struct json *params) > { > struct ovsdb_jsonrpc_trigger *t; > @@ -858,7 +883,7 @@ ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session > *s, > > /* Insert into trigger table. */ > t = xmalloc(sizeof *t); > - ovsdb_trigger_init(&s->up, &t->trigger, params, time_msec()); > + ovsdb_trigger_init(&s->up, db, &t->trigger, params, time_msec()); > t->id = id; > hmap_insert(&s->triggers, &t->hmap_node, hash); > > @@ -962,6 +987,7 @@ struct ovsdb_jsonrpc_monitor_table { > struct ovsdb_jsonrpc_monitor { > struct ovsdb_replica replica; > struct ovsdb_jsonrpc_session *session; > + struct ovsdb *db; > struct hmap_node node; /* In ovsdb_jsonrpc_session's "monitors". */ > > struct json *monitor_id; > @@ -1113,7 +1139,7 @@ ovsdb_jsonrpc_parse_monitor_request(struct > ovsdb_jsonrpc_monitor_table *mt, > } > > static struct json * > -ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, > +ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb > *db, > struct json *params) > { > struct ovsdb_jsonrpc_monitor *m = NULL; > @@ -1141,8 +1167,9 @@ ovsdb_jsonrpc_monitor_create(struct > ovsdb_jsonrpc_session *s, > > m = xzalloc(sizeof *m); > ovsdb_replica_init(&m->replica, &ovsdb_jsonrpc_replica_class); > - ovsdb_add_replica(s->remote->server->up.db, &m->replica); > + ovsdb_add_replica(db, &m->replica); > m->session = s; > + m->db = db; > hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0)); > m->monitor_id = json_clone(monitor_id); > shash_init(&m->tables); > @@ -1154,7 +1181,7 @@ ovsdb_jsonrpc_monitor_create(struct > ovsdb_jsonrpc_session *s, > const struct json *mr_value; > size_t i; > > - table = ovsdb_get_table(s->remote->server->up.db, node->name); > + table = ovsdb_get_table(m->db, node->name); > if (!table) { > error = ovsdb_syntax_error(NULL, NULL, > "no table named %s", node->name); > @@ -1203,7 +1230,7 @@ ovsdb_jsonrpc_monitor_create(struct > ovsdb_jsonrpc_session *s, > > error: > if (m) { > - ovsdb_remove_replica(s->remote->server->up.db, &m->replica); > + ovsdb_remove_replica(m->db, &m->replica); > } > > json = ovsdb_error_to_json(error); > @@ -1227,7 +1254,7 @@ ovsdb_jsonrpc_monitor_cancel(struct > ovsdb_jsonrpc_session *s, > return jsonrpc_create_error(json_string_create("unknown > monitor"), > request_id); > } else { > - ovsdb_remove_replica(s->remote->server->up.db, &m->replica); > + ovsdb_remove_replica(m->db, &m->replica); > return jsonrpc_create_reply(json_object_create(), request_id); > } > } > @@ -1239,7 +1266,7 @@ ovsdb_jsonrpc_monitor_remove_all(struct > ovsdb_jsonrpc_session *s) > struct ovsdb_jsonrpc_monitor *m, *next; > > HMAP_FOR_EACH_SAFE (m, next, node, &s->monitors) { > - ovsdb_remove_replica(s->remote->server->up.db, &m->replica); > + ovsdb_remove_replica(m->db, &m->replica); > } > } > > diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h > index 2dc0c78..bf2a2fc 100644 > --- a/ovsdb/jsonrpc-server.h > +++ b/ovsdb/jsonrpc-server.h > @@ -22,7 +22,9 @@ struct ovsdb; > struct shash; > struct simap; > > -struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(struct ovsdb *); > +struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(void); > +bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *, > + struct ovsdb *); > void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *); > > /* Options for a remote. */ > diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in > index 1f5be03..b4b6eb6 100644 > --- a/ovsdb/ovsdb-server.1.in > +++ b/ovsdb/ovsdb-server.1.in > @@ -10,7 +10,7 @@ ovsdb\-server \- Open vSwitch database server > . > .SH SYNOPSIS > \fBovsdb\-server\fR > -[\fIdatabase\fR] > +[\fIdatabase\fR]\&... > [\fB\-\-remote=\fIremote\fR]\&... > [\fB\-\-run=\fIcommand\fR] > .so lib/daemon-syn.man > @@ -21,13 +21,13 @@ ovsdb\-server \- Open vSwitch database server > .so lib/common-syn.man > . > .SH DESCRIPTION > -The \fBovsdb\-server\fR program provides RPC interfaces to an Open > -vSwitch database (OVSDB). It supports JSON-RPC client connections > -over active or passive TCP/IP or Unix domain sockets. > +The \fBovsdb\-server\fR program provides RPC interfaces to one or more > +Open vSwitch databases (OVSDBs). It supports JSON-RPC client > +connections over active or passive TCP/IP or Unix domain sockets. > .PP > -The OVSDB file may be specified on the command line as \fIdatabase\fR. > -The default is \fB@DBDIR@/conf.db\fR. The database > -file must already have been created and initialized using, for > +Each OVSDB file may be specified on the command line as \fIdatabase\fR. > +If none is specified, the default is \fB@DBDIR@/conf.db\fR. The database > +files must already have been created and initialized using, for > example, \fBovsdb\-tool create\fR. > . > .SH OPTIONS > @@ -40,11 +40,12 @@ Adds \fIremote\fR as a connection method used by > \fBovsdb\-server\fR. > .so ovsdb/remote-passive.man > .so ovsdb/remote-active.man > . > -.IP "\fBdb:\fItable\fB,\fIcolumn\fR" > +.IP "\fBdb:\fR[\fIdb\fB,\fR]\fItable\fB,\fIcolumn\fR" > Reads additional connection methods from \fIcolumn\fR in all of the > -rows in \fItable\fR. As the contents of \fIcolumn\fR changes, > -\fBovsdb\-server\fR also adds and drops connection methods > -accordingly. > +rows in \fItable\fR within \fIdb\fR. (If \fBovsdb\-server\fR is > +providing access to only one database, then \fIdb\fR is optional.) As > +the contents of \fIcolumn\fR changes, \fBovsdb\-server\fR also adds > +and drops connection methods accordingly. > .IP > If \fIcolumn\fR's type is string or set of strings, then the > connection methods are taken directly from the column. The connection > @@ -61,7 +62,7 @@ is mandatory: if it is missing or empty then no connection > method can > be configured. > .IP "\fBmax_backoff\fR (integer)" > Maximum number of milliseconds to wait between connection attempts. > -.IP "\fBinactivity_probe\fR (integer) > +.IP "\fBinactivity_probe\fR (integer)" > Maximum number of milliseconds of idle time on connection to > client before sending an inactivity probe message. > .RE > @@ -111,9 +112,10 @@ described below. > These commands are specific to \fBovsdb\-server\fR. > .IP "\fBexit\fR" > Causes \fBovsdb\-server\fR to gracefully terminate. > -.IP "\fBovsdb\-server/compact\fR" > -Compacts the database in-place. The database is also automatically > -compacted occasionally. > +.IP "\fBovsdb\-server/compact\fR [\fIdb\fR]\&..." > +Compacts each database \fIdb\fR in-place. If no \fIdb\fR is > +specified, compacts every database in-place. Databases are also > +automatically compacted occasionally. > . > .IP "\fBovsdb\-server/reconnect\fR" > Makes \fBovsdb\-server\fR drop all of the JSON\-RPC > diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c > index 0baf9fc..69548c2 100644 > --- a/ovsdb/ovsdb-server.c > +++ b/ovsdb/ovsdb-server.c > @@ -26,6 +26,7 @@ > #include "daemon.h" > #include "dirs.h" > #include "dummy.h" > +#include "dynamic-string.h" > #include "file.h" > #include "hash.h" > #include "json.h" > @@ -56,6 +57,16 @@ > > VLOG_DEFINE_THIS_MODULE(ovsdb_server); > > +struct db { > + /* Initialized in main(). */ > + char *filename; > + struct ovsdb_file *file; > + struct ovsdb *db; > + > + /* Only used by update_remote_status(). */ > + struct ovsdb_txn *txn; > +}; > + > /* SSL configuration. */ > static char *private_key_file; > static char *certificate_file; > @@ -66,17 +77,18 @@ static unixctl_cb_func ovsdb_server_exit; > static unixctl_cb_func ovsdb_server_compact; > static unixctl_cb_func ovsdb_server_reconnect; > > -static void parse_options(int argc, char *argv[], char **file_namep, > +static void parse_options(int *argc, char **argvp[], > struct sset *remotes, char **unixctl_pathp, > char **run_command); > static void usage(void) NO_RETURN; > > static void reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, > - const struct ovsdb *db, struct sset > *remotes); > + const struct db dbs[], size_t n_dbs, > + struct sset *remotes); > > static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc, > const struct sset *remotes, > - struct ovsdb *db); > + struct db dbs[], size_t n_dbs); > > int > main(int argc, char *argv[]) > @@ -86,34 +98,53 @@ main(int argc, char *argv[]) > struct unixctl_server *unixctl; > struct ovsdb_jsonrpc_server *jsonrpc; > struct sset remotes; > - struct ovsdb_error *error; > - struct ovsdb_file *file; > - struct ovsdb *db; > struct process *run_process; > - char *file_name; > bool exiting; > int retval; > long long int status_timer = LLONG_MIN; > > + struct db *dbs; > + int n_dbs; > + int i; > + > proctitle_init(argc, argv); > set_program_name(argv[0]); > stress_init_command(); > signal(SIGPIPE, SIG_IGN); > process_init(); > > - parse_options(argc, argv, &file_name, &remotes, &unixctl_path, > - &run_command); > + parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command); > > daemonize_start(); > > - error = ovsdb_file_open(file_name, false, &db, &file); > - if (error) { > - ovs_fatal(0, "%s", ovsdb_error_to_string(error)); > + n_dbs = MAX(1, argc); > + dbs = xcalloc(n_dbs + 1, sizeof *dbs); > + if (argc > 0) { > + for (i = 0; i < argc; i++) { > + dbs[i].filename = argv[i]; > + } > + } else { > + dbs[0].filename = xasprintf("%s/conf.db", ovs_dbdir()); > } > - free(file_name); > > - jsonrpc = ovsdb_jsonrpc_server_create(db); > - reconfigure_from_db(jsonrpc, db, &remotes); > + for (i = 0; i < n_dbs; i++) { > + struct ovsdb_error *error; > + > + error = ovsdb_file_open(dbs[i].filename, false, > + &dbs[i].db, &dbs[i].file); > + if (error) { > + ovs_fatal(0, "%s", ovsdb_error_to_string(error)); > + } > + } > + > + jsonrpc = ovsdb_jsonrpc_server_create(); > + for (i = 0; i < n_dbs; i++) { > + if (!ovsdb_jsonrpc_server_add_db(jsonrpc, dbs[i].db)) { > + ovs_fatal(0, "%s: duplicate database name", > + dbs[i].db->schema->name); > + } > + } > + reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes); > > retval = unixctl_server_create(unixctl_path, &unixctl); > if (retval) { > @@ -146,28 +177,35 @@ main(int argc, char *argv[]) > } > > unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting); > - unixctl_command_register("ovsdb-server/compact", "", 0, 0, > - ovsdb_server_compact, file); > + unixctl_command_register("ovsdb-server/compact", "", 0, 1, > + ovsdb_server_compact, dbs); > unixctl_command_register("ovsdb-server/reconnect", "", 0, 0, > ovsdb_server_reconnect, jsonrpc); > > exiting = false; > while (!exiting) { > + int i; > + > memory_run(); > if (memory_should_report()) { > struct simap usage; > > simap_init(&usage); > ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage); > - ovsdb_get_memory_usage(db, &usage); > + for (i = 0; i < n_dbs; i++) { > + ovsdb_get_memory_usage(dbs[i].db, &usage); > + } > memory_report(&usage); > simap_destroy(&usage); > } > > - reconfigure_from_db(jsonrpc, db, &remotes); > + reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes); > ovsdb_jsonrpc_server_run(jsonrpc); > unixctl_server_run(unixctl); > - ovsdb_trigger_run(db, time_msec()); > + > + for (i = 0; i < n_dbs; i++) { > + ovsdb_trigger_run(dbs[i].db, time_msec()); > + } > if (run_process && process_exited(run_process)) { > exiting = true; > } > @@ -175,13 +213,15 @@ main(int argc, char *argv[]) > /* update Manager status(es) every 5 seconds */ > if (time_msec() >= status_timer) { > status_timer = time_msec() + 5000; > - update_remote_status(jsonrpc, &remotes, db); > + update_remote_status(jsonrpc, &remotes, dbs, n_dbs); > } > > memory_wait(); > ovsdb_jsonrpc_server_wait(jsonrpc); > unixctl_server_wait(unixctl); > - ovsdb_trigger_wait(db, time_msec()); > + for (i = 0; i < n_dbs; i++) { > + ovsdb_trigger_wait(dbs[i].db, time_msec()); > + } > if (run_process) { > process_wait(run_process); > } > @@ -192,7 +232,9 @@ main(int argc, char *argv[]) > poll_block(); > } > ovsdb_jsonrpc_server_destroy(jsonrpc); > - ovsdb_destroy(db); > + for (i = 0; i < n_dbs; i++) { > + ovsdb_destroy(dbs[i].db); > + } > sset_destroy(&remotes); > unixctl_server_destroy(unixctl); > > @@ -207,26 +249,64 @@ main(int argc, char *argv[]) > return 0; > } > > +static const struct db * > +find_db(const struct db dbs[], size_t n_dbs, const char *db_name) > +{ > + size_t i; > + > + for (i = 0; i < n_dbs; i++) { > + if (!strcmp(dbs[i].db->schema->name, db_name)) { > + return &dbs[i]; > + } > + } > + > + return NULL; > +} > + > static void > -parse_db_column(const struct ovsdb *db, > +parse_db_column(const struct db dbs[], size_t n_dbs, > const char *name_, > + const struct db **dbp, > const struct ovsdb_table **tablep, > const struct ovsdb_column **columnp) > { > - char *name, *table_name, *column_name; > + const char *table_name, *column_name; > const struct ovsdb_column *column; > const struct ovsdb_table *table; > + const char *tokens[3]; > char *save_ptr = NULL; > + const struct db *db; > + char *name; > > name = xstrdup(name_); > strtok_r(name, ":", &save_ptr); /* "db:" */ > - table_name = strtok_r(NULL, ",", &save_ptr); > - column_name = strtok_r(NULL, ",", &save_ptr); > - if (!table_name || !column_name) { > + tokens[0] = strtok_r(NULL, ",", &save_ptr); > + tokens[1] = strtok_r(NULL, ",", &save_ptr); > + tokens[2] = strtok_r(NULL, ",", &save_ptr); > + if (!tokens[0] || !tokens[1]) { > ovs_fatal(0, "\"%s\": invalid syntax", name_); > } > + if (tokens[2]) { > + const char *db_name = tokens[0]; > + table_name = tokens[1]; > + column_name = tokens[2]; > + > + db = find_db(dbs, n_dbs, tokens[0]); > + if (!db) { > + ovs_fatal(0, "\"%s\": no database named %s", name_, db_name); > + } > + } else { > + if (n_dbs > 1) { > + ovs_fatal(0, "\"%s\": database name must be specified (because " > + "multiple databases are configured)", name_); > + } > + > + table_name = tokens[0]; > + column_name = tokens[1]; > + db = &dbs[0]; > + } > > - table = ovsdb_get_table(db, table_name); > + table = ovsdb_get_table(db->db, table_name); > if (!table) { > ovs_fatal(0, "\"%s\": no table named %s", name_, table_name); > } > @@ -238,20 +318,23 @@ parse_db_column(const struct ovsdb *db, > } > free(name); > > + *dbp = db; > *columnp = column; > *tablep = table; > } > > static void > -parse_db_string_column(const struct ovsdb *db, > +parse_db_string_column(const struct db dbs[], size_t n_dbs, > const char *name, > + const struct db **dbp, > const struct ovsdb_table **tablep, > const struct ovsdb_column **columnp) > { > const struct ovsdb_column *column; > const struct ovsdb_table *table; > + const struct db *db; > > - parse_db_column(db, name, &table, &column); > + parse_db_column(dbs, n_dbs, name, &db, &table, &column); > > if (column->type.key.type != OVSDB_TYPE_STRING > || column->type.value.type != OVSDB_TYPE_VOID) { > @@ -260,12 +343,13 @@ parse_db_string_column(const struct ovsdb *db, > name, table->schema->name, column->name); > } > > + *dbp = db; > *columnp = column; > *tablep = table; > } > > static OVS_UNUSED const char * > -query_db_string(const struct ovsdb *db, const char *name) > +query_db_string(const struct db dbs[], size_t n_dbs, const char *name) > { > if (!name || strncmp(name, "db:", 3)) { > return name; > @@ -273,8 +357,9 @@ query_db_string(const struct ovsdb *db, const char *name) > const struct ovsdb_column *column; > const struct ovsdb_table *table; > const struct ovsdb_row *row; > + const struct db *db; > > - parse_db_string_column(db, name, &table, &column); > + parse_db_string_column(dbs, n_dbs, name, &db, &table, &column); > > HMAP_FOR_EACH (row, hmap_node, &table->rows) { > const struct ovsdb_datum *datum; > @@ -493,14 +578,15 @@ add_manager_options(struct shash *remotes, const struct > ovsdb_row *row) > } > > static void > -query_db_remotes(const char *name, const struct ovsdb *db, > +query_db_remotes(const char *name, const struct db dbs[], size_t n_dbs, > struct shash *remotes) > { > const struct ovsdb_column *column; > const struct ovsdb_table *table; > const struct ovsdb_row *row; > + const struct db *db; > > - parse_db_column(db, name, &table, &column); > + parse_db_column(dbs, n_dbs, name, &db, &table, &column); > > if (column->type.key.type == OVSDB_TYPE_STRING > && column->type.value.type == OVSDB_TYPE_VOID) { > @@ -594,19 +680,20 @@ update_remote_row(const struct ovsdb_row *row, struct > ovsdb_txn *txn, > } > > static void > -update_remote_rows(const struct ovsdb *db, struct ovsdb_txn *txn, > +update_remote_rows(const struct db dbs[], size_t n_dbs, > const char *remote_name, > const struct ovsdb_jsonrpc_server *jsonrpc) > { > const struct ovsdb_table *table, *ref_table; > const struct ovsdb_column *column; > const struct ovsdb_row *row; > + const struct db *db; > > if (strncmp("db:", remote_name, 3)) { > return; > } > > - parse_db_column(db, remote_name, &table, &column); > + parse_db_column(dbs, n_dbs, remote_name, &db, &table, &column); > > if (column->type.key.type != OVSDB_TYPE_UUID > || !column->type.key.u.uuid.refTable > @@ -626,7 +713,7 @@ update_remote_rows(const struct ovsdb *db, struct > ovsdb_txn *txn, > > ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid); > if (ref_row) { > - update_remote_row(ref_row, txn, jsonrpc); > + update_remote_row(ref_row, db->txn, jsonrpc); > } > } > } > @@ -634,32 +721,36 @@ update_remote_rows(const struct ovsdb *db, struct > ovsdb_txn *txn, > > static void > update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc, > - const struct sset *remotes, struct ovsdb *db) > + const struct sset *remotes, > + struct db dbs[], size_t n_dbs) > { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > - struct ovsdb_txn *txn; > - const bool durable_txn = false; > - struct ovsdb_error *error; > const char *remote; > + size_t i; > > - txn = ovsdb_txn_create(db); > + for (i = 0; i < n_dbs; i++) { > + dbs[i].txn = ovsdb_txn_create(dbs[i].db); > + } > > /* Iterate over --remote arguments given on command line. */ > SSET_FOR_EACH (remote, remotes) { > - update_remote_rows(db, txn, remote, jsonrpc); > + update_remote_rows(dbs, n_dbs, remote, jsonrpc); > } > > - error = ovsdb_txn_commit(txn, durable_txn); > - if (error) { > - VLOG_ERR_RL(&rl, "Failed to update remote status: %s", > - ovsdb_error_to_string(error)); > + for (i = 0; i < n_dbs; i++) { > + struct ovsdb_error *error = ovsdb_txn_commit(dbs[i].txn, false); > + if (error) { > + VLOG_ERR_RL(&rl, "Failed to update remote status: %s", > + ovsdb_error_to_string(error)); > + ovsdb_error_destroy(error); > + } > } > } > > /* Reconfigures ovsdb-server based on information in the database. */ > static void > reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, > - const struct ovsdb *db, struct sset *remotes) > + const struct db dbs[], size_t n_dbs, struct sset > *remotes) > { > struct shash resolved_remotes; > const char *name; > @@ -668,7 +759,7 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, > shash_init(&resolved_remotes); > SSET_FOR_EACH (name, remotes) { > if (!strncmp(name, "db:", 3)) { > - query_db_remotes(name, db, &resolved_remotes); > + query_db_remotes(name, dbs, n_dbs, &resolved_remotes); > } else { > add_remote(&resolved_remotes, name); > } > @@ -677,9 +768,9 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, > shash_destroy_free_data(&resolved_remotes); > > /* Configure SSL. */ > - stream_ssl_set_key_and_cert(query_db_string(db, private_key_file), > - query_db_string(db, certificate_file)); > - stream_ssl_set_ca_cert_file(query_db_string(db, ca_cert_file), > + stream_ssl_set_key_and_cert(query_db_string(dbs, n_dbs, > private_key_file), > + query_db_string(dbs, n_dbs, > certificate_file)); > + stream_ssl_set_ca_cert_file(query_db_string(dbs, n_dbs, ca_cert_file), > bootstrap_ca_cert); > } > > @@ -694,22 +785,42 @@ ovsdb_server_exit(struct unixctl_conn *conn, int argc > OVS_UNUSED, > } > > static void > -ovsdb_server_compact(struct unixctl_conn *conn, int argc OVS_UNUSED, > - const char *argv[] OVS_UNUSED, void *file_) > +ovsdb_server_compact(struct unixctl_conn *conn, int argc, > + const char *argv[], void *dbs_) > { > - struct ovsdb_file *file = file_; > - struct ovsdb_error *error; > + struct db *dbs = dbs_; > + struct ds reply; > + struct db *db; > + int n = 0; > > - VLOG_INFO("compacting database by user request"); > - error = ovsdb_file_compact(file); > - if (!error) { > - unixctl_command_reply(conn, NULL); > + ds_init(&reply); > + for (db = dbs; db->filename != NULL; db++) { > + const char *name = db->db->schema->name; > + > + if (argc < 2 || !strcmp(argv[1], name)) { > + struct ovsdb_error *error; > + > + VLOG_INFO("compacting %s database by user request", name); > + > + error = ovsdb_file_compact(db->file); > + if (error) { > + char *s = ovsdb_error_to_string(error); > + ds_put_format(&reply, "%s\n", s); > + free(s); > + } > + > + n++; > + } > + } > + > + if (!n) { > + unixctl_command_reply_error(conn, "no database by that name"); > + } else if (reply.length) { > + unixctl_command_reply_error(conn, ds_cstr(&reply)); > } else { > - char *s = ovsdb_error_to_string(error); > - ovsdb_error_destroy(error); > - unixctl_command_reply_error(conn, s); > - free(s); > + unixctl_command_reply(conn, NULL); > } > + ds_destroy(&reply); > } > > /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC > @@ -725,9 +836,8 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int > argc OVS_UNUSED, > } > > static void > -parse_options(int argc, char *argv[], char **file_namep, > - struct sset *remotes, char **unixctl_pathp, > - char **run_command) > +parse_options(int *argcp, char **argvp[], > + struct sset *remotes, char **unixctl_pathp, char **run_command) > { > enum { > OPT_REMOTE = UCHAR_MAX + 1, > @@ -756,6 +866,8 @@ parse_options(int argc, char *argv[], char **file_namep, > {NULL, 0, NULL, 0}, > }; > char *short_options = long_options_to_short_options(long_options); > + int argc = *argcp; > + char **argv = *argvp; > > sset_init(remotes); > for (;;) { > @@ -821,31 +933,18 @@ parse_options(int argc, char *argv[], char **file_namep, > } > free(short_options); > > - argc -= optind; > - argv += optind; > - > - switch (argc) { > - case 0: > - *file_namep = xasprintf("%s/conf.db", ovs_dbdir()); > - break; > - > - case 1: > - *file_namep = xstrdup(argv[0]); > - break; > - > - default: > - ovs_fatal(0, "database file is only non-option argument; " > - "use --help for usage"); > - } > + *argcp -= optind; > + *argvp += optind; > } > > static void > usage(void) > { > printf("%s: Open vSwitch database server\n" > - "usage: %s [OPTIONS] DATABASE\n" > - "where DATABASE is a database file in ovsdb format.\n", > - program_name, program_name); > + "usage: %s [OPTIONS] [DATABASE...]\n" > + "where each DATABASE is a database file in ovsdb format.\n" > + "The default DATABASE, if none is given, is\n%s/conf.db.\n", > + program_name, program_name, ovs_dbdir()); > printf("\nJSON-RPC options (may be specified any number of times):\n" > " --remote=REMOTE connect or listen to REMOTE\n"); > stream_usage("JSON-RPC", true, true, true); > diff --git a/ovsdb/server.c b/ovsdb/server.c > index 7cd4263..ac2aa29 100644 > --- a/ovsdb/server.c > +++ b/ovsdb/server.c > @@ -1,4 +1,4 @@ > -/* Copyright (c) 2011 Nicira, Inc. > +/* Copyright (c) 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -20,12 +20,13 @@ > #include <assert.h> > > #include "hash.h" > +#include "ovsdb.h" > > -/* Initializes 'session' as a session that operates on 'db'. */ > +/* Initializes 'session' as a session within 'server'. */ > void > -ovsdb_session_init(struct ovsdb_session *session, struct ovsdb *db) > +ovsdb_session_init(struct ovsdb_session *session, struct ovsdb_server > *server) > { > - session->db = db; > + session->server = server; > list_init(&session->completions); > hmap_init(&session->waiters); > } > @@ -113,18 +114,31 @@ ovsdb_lock_waiter_is_owner(const struct > ovsdb_lock_waiter *waiter) > return waiter->lock && waiter == ovsdb_lock_get_owner(waiter->lock); > } > > -/* Initializes 'server' as a server that operates on 'db'. */ > +/* Initializes 'server'. > + * > + * The caller must call ovsdb_server_add_db() for each database to which > + * 'server' should provide access. */ > void > -ovsdb_server_init(struct ovsdb_server *server, struct ovsdb *db) > +ovsdb_server_init(struct ovsdb_server *server) > { > - server->db = db; > + shash_init(&server->dbs); > hmap_init(&server->locks); > } > > +/* Adds 'db' to the set of databases served out by 'server'. Returns true if > + * successful, false if 'db''s name is the same as some database already in > + * 'server'. */ > +bool > +ovsdb_server_add_db(struct ovsdb_server *server, struct ovsdb *db) > +{ > + return shash_add_once(&server->dbs, db->schema->name, db); > +} > + > /* Destroys 'server'. */ > void > ovsdb_server_destroy(struct ovsdb_server *server) > { > + shash_destroy(&server->dbs); > hmap_destroy(&server->locks); > } > > diff --git a/ovsdb/server.h b/ovsdb/server.h > index e073850..561f01e 100644 > --- a/ovsdb/server.h > +++ b/ovsdb/server.h > @@ -18,17 +18,21 @@ > > #include "hmap.h" > #include "list.h" > +#include "shash.h" > + > +struct ovsdb; > +struct ovsdb_server; > > /* Abstract representation of an OVSDB client connection, not tied to any > * particular network protocol. Protocol implementations > * (e.g. jsonrpc-server.c) embed this in a larger data structure. */ > struct ovsdb_session { > - struct ovsdb *db; > + struct ovsdb_server *server; > struct list completions; /* Completed triggers. */ > struct hmap waiters; /* "ovsdb_lock_waiter *"s by lock name. */ > }; > > -void ovsdb_session_init(struct ovsdb_session *, struct ovsdb *); > +void ovsdb_session_init(struct ovsdb_session *, struct ovsdb_server *); > void ovsdb_session_destroy(struct ovsdb_session *); > > struct ovsdb_lock_waiter *ovsdb_session_get_lock_waiter( > @@ -73,11 +77,12 @@ bool ovsdb_lock_waiter_is_owner(const struct > ovsdb_lock_waiter *); > * network protocol. Protocol implementations (e.g. jsonrpc-server.c) embed > * this in a larger data structure. */ > struct ovsdb_server { > - struct ovsdb *db; > + struct shash dbs; /* Maps from a db name to a "struct ovsdb *". */ > struct hmap locks; /* Contains "struct ovsdb_lock"s indexed by name. > */ > }; > > -void ovsdb_server_init(struct ovsdb_server *, struct ovsdb *); > +void ovsdb_server_init(struct ovsdb_server *); > +bool ovsdb_server_add_db(struct ovsdb_server *, struct ovsdb *); > void ovsdb_server_destroy(struct ovsdb_server *); > > struct ovsdb_lock_waiter *ovsdb_server_lock(struct ovsdb_server *, > diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c > index 6ae1f51..a93b844 100644 > --- a/ovsdb/trigger.c > +++ b/ovsdb/trigger.c > @@ -1,4 +1,4 @@ > -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc. > +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -30,12 +30,13 @@ static bool ovsdb_trigger_try(struct ovsdb_trigger *, > long long int now); > static void ovsdb_trigger_complete(struct ovsdb_trigger *); > > void > -ovsdb_trigger_init(struct ovsdb_session *session, > +ovsdb_trigger_init(struct ovsdb_session *session, struct ovsdb *db, > struct ovsdb_trigger *trigger, > struct json *request, long long int now) > { > trigger->session = session; > - list_push_back(&trigger->session->db->triggers, &trigger->node); > + trigger->db = db; > + list_push_back(&trigger->db->triggers, &trigger->node); > trigger->request = request; > trigger->result = NULL; > trigger->created = now; > @@ -110,7 +111,7 @@ ovsdb_trigger_wait(struct ovsdb *db, long long int now) > static bool > ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now) > { > - t->result = ovsdb_execute(t->session->db, t->session, > + t->result = ovsdb_execute(t->db, t->session, > t->request, now - t->created, > &t->timeout_msec); > if (t->result) { > ovsdb_trigger_complete(t); > diff --git a/ovsdb/trigger.h b/ovsdb/trigger.h > index 1d47f3f..f686b15 100644 > --- a/ovsdb/trigger.h > +++ b/ovsdb/trigger.h > @@ -1,4 +1,4 @@ > -/* Copyright (c) 2009, 2011 Nicira, Inc. > +/* Copyright (c) 2009, 2011, 2012 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -22,7 +22,8 @@ struct ovsdb; > > struct ovsdb_trigger { > struct ovsdb_session *session; /* Session that owns this trigger. */ > - struct list node; /* !result: in session->db->triggers; > + struct ovsdb *db; /* Database on which trigger acts. */ > + struct list node; /* !result: in db->triggers; > * result: in session->completions. */ > struct json *request; /* Database request. */ > struct json *result; /* Result (null if none yet). */ > @@ -30,7 +31,8 @@ struct ovsdb_trigger { > long long int timeout_msec; /* Max wait duration. */ > }; > > -void ovsdb_trigger_init(struct ovsdb_session *, struct ovsdb_trigger *, > +void ovsdb_trigger_init(struct ovsdb_session *, struct ovsdb *, > + struct ovsdb_trigger *, > struct json *request, long long int now); > void ovsdb_trigger_destroy(struct ovsdb_trigger *); > > diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at > index b0a3377..f787f5a 100644 > --- a/tests/ovsdb-server.at > +++ b/tests/ovsdb-server.at > @@ -142,12 +142,15 @@ AT_CLEANUP > > AT_SETUP([database multiplexing implementation]) > AT_KEYWORDS([ovsdb server positive]) > -ordinal_schema > schema > -AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore]) > -AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid > --unixctl="`pwd`"/unixctl --remote=punix:socket db], [0], [ignore], [ignore]) > +ordinal_schema > schema1 > +constraint_schema > schema2 > +AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore]) > +AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore]) > +AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid > --unixctl="`pwd`"/unixctl --remote=punix:socket db1 db2], [0], [ignore], > [ignore]) > AT_CHECK( > [[ovsdb-client list-dbs unix:socket]], > - [0], [ordinals > + [0], [constraints > +ordinals > ], [ignore], [test ! -e pid || kill `cat pid`]) > AT_CHECK( > [[test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0], > @@ -158,37 +161,67 @@ AT_CLEANUP > > AT_SETUP([--remote=db: implementation]) > AT_KEYWORDS([ovsdb server positive]) > +OVS_RUNDIR=`pwd`; export OVS_RUNDIR > +OVS_LOGDIR=`pwd`; export OVS_LOGDIR > AT_DATA([schema], > [[{"name": "mydb", > "tables": { > + "Root": { > + "columns": { > + "managers": { > + "type": { > + "key": "string", > + "min": 0, > + "max": "unlimited"}}, > + "manager_options": { > + "type": { > + "key": {"type": "uuid", "refTable": "Manager"}, > + "min": 0, > + "max": "unlimited"}}}}, > "Manager": { > "columns": { > - "manager": {"type": "string"}}}}} > + "target": { > + "type": "string"}, > + "is_connected": { > + "type": { > + "key": "boolean", > + "min": 0, > + "max": 1}}}}}} > ]]) > AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore]) > AT_CHECK( > [[ovsdb-tool transact db \ > '["mydb", > {"op": "insert", > + "table": "Root", > + "row": { > + "managers": "punix:socket1", > + "manager_options": ["set", [["named-uuid", "x"]]]}}, > + {"op": "insert", > "table": "Manager", > - "row": {"manager": "punix:socket"}}]']], [0], [ignore], [ignore]) > -AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid > --remote=db:Manager,manager --unixctl="`pwd`"/unixctl db], [0], [ignore], > [ignore]) > + "uuid-name": "x", > + "row": {"target": "punix:socket2"}}]']], [0], [ignore], [ignore]) > +ON_EXIT([kill `cat ovsdb-server.pid`]) > +AT_CHECK([ovsdb-server --enable-dummy --detach --no-chdir --pidfile > --remote=db:Root,managers --remote=db:Root,manager_options --log-file db], > [0], [ignore], [ignore]) > +for i in 1 2 3 4 5 6; do ovs-appctl -t ovsdb-server time/warp 1000; done > AT_CHECK( > - [[ovsdb-client transact unix:socket \ > + [[ovsdb-client transact unix:socket1 \ > '["mydb", > {"op": "select", > + "table": "Root", > + "where": [], > + "columns": ["managers"]}, > + {"op": "select", > "table": "Manager", > "where": [], > - "columns": ["manager"]}]']], > - [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`]) > + "columns": ["target", "is_connected"]}]']], > + [0], [stdout], [ignore]) > AT_CHECK( > [perl $srcdir/uuidfilt.pl stdout], > [0], > - [[[{"rows":[{"manager":"punix:socket"}]}] > + > [[[{"rows":[{"managers":"punix:socket1"}]},{"rows":[{"is_connected":false,"target":"punix:socket2"}]}] > ]], > - [ignore], > - [test ! -e pid || kill `cat pid`]) > -OVSDB_SERVER_SHUTDOWN > + [ignore]) > AT_CLEANUP > > AT_SETUP([SSL db: implementation]) > diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c > index a1ad2cb..d448109 100644 > --- a/tests/test-ovsdb.c > +++ b/tests/test-ovsdb.c > @@ -1294,6 +1294,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[]) > { > struct ovsdb_schema *schema; > struct ovsdb_session session; > + struct ovsdb_server server; > struct json *json; > struct ovsdb *db; > long long int now; > @@ -1306,7 +1307,9 @@ do_trigger(int argc OVS_UNUSED, char *argv[]) > json_destroy(json); > db = ovsdb_create(schema); > > - ovsdb_session_init(&session, db); > + ovsdb_server_init(&server); > + ovsdb_server_add_db(&server, db); > + ovsdb_session_init(&session, &server); > > now = 0; > number = 0; > @@ -1321,7 +1324,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[]) > json_destroy(params); > } else { > struct test_trigger *t = xmalloc(sizeof *t); > - ovsdb_trigger_init(&session, &t->trigger, params, now); > + ovsdb_trigger_init(&session, db, &t->trigger, params, now); > t->number = number++; > if (ovsdb_trigger_is_complete(&t->trigger)) { > do_trigger_dump(t, now, "immediate"); > @@ -1342,6 +1345,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[]) > poll_block(); > } > > + ovsdb_server_destroy(&server); > ovsdb_destroy(db); > } > > diff --git a/utilities/ovs-ctl.8 b/utilities/ovs-ctl.8 > index c730778..22db06b 100644 > --- a/utilities/ovs-ctl.8 > +++ b/utilities/ovs-ctl.8 > @@ -223,6 +223,12 @@ Overrides the file name for the Unix domain socket used > to connect to > .IP "\fB\-\-db\-schema=\fIschema\fR" > Overrides the file name for the OVS database schema. > . > +.IP "\fB\-\-extra-dbs=\fIfile\fR" > +Adds \fIfile\fR as an extra database for \fBovsdb\-server\fR to serve > +out. Multiple space-separated file names may also be specified. > +\fIfile\fR should begin with \fB/\fR; if it does not, then it will be > +taken as relative to \fIdbdir\fR. > +. > .SH "The ``stop'' command" > . > .PP > diff --git a/utilities/ovs-ctl.in b/utilities/ovs-ctl.in > index 674c3c3..2aa6398 100755 > --- a/utilities/ovs-ctl.in > +++ b/utilities/ovs-ctl.in > @@ -189,9 +189,23 @@ start_ovsdb () { > > # Start ovsdb-server. > set ovsdb-server "$DB_FILE" > + for db in $EXTRA_DBS; do > + case $db in > + /*) ;; > + *) db=$dbdir/$db ;; > + esac > + > + if test ! -f "$db"; then > + log_warning_msg "$db (from \$EXTRA_DBS) does not exist." > + elif ovsdb-tool db-version "$db" >/dev/null; then > + set "$@" "$db" > + else > + log_warning_msg "$db (from \$EXTRA_DBS) cannot be read as a > database (see error message above)" > + fi > + done > set "$@" -vconsole:emer -vsyslog:err -vfile:info > set "$@" --remote=punix:"$DB_SOCK" > - set "$@" --remote=db:Open_vSwitch,manager_options > + set "$@" --remote=db:Open_vSwitch,Open_vSwitch,manager_options > set "$@" --private-key=db:SSL,private_key > set "$@" --certificate=db:SSL,certificate > set "$@" --bootstrap-ca-cert=db:SSL,ca_cert > @@ -406,6 +420,7 @@ set_defaults () { > DB_FILE=$dbdir/conf.db > DB_SOCK=$rundir/db.sock > DB_SCHEMA=$datadir/vswitch.ovsschema > + EXTRA_DBS= > > PROTOCOL=gre > DPORT= > -- > 1.7.2.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev