From: Ben Pfaff Date: Mon, 4 Jan 2010 18:05:51 +0000 (-0800) Subject: ovsdb-server: Make database connections configurable from database itself. X-Git-Tag: v1.0.0~259^2~352 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=0b1fae1b73c4c6cfc84edafc6845a17257191e42;p=sliver-openvswitch.git ovsdb-server: Make database connections configurable from database itself. Most importantly this adds a "managers" column to the vswitch database that specifies where the ovsdb-server should connect. --- diff --git a/debian/openvswitch-switch.init b/debian/openvswitch-switch.init index bf71e7df7..de8f295d0 100755 --- a/debian/openvswitch-switch.init +++ b/debian/openvswitch-switch.init @@ -206,7 +206,7 @@ case "$1" in set -- "$@" --verbose=ANY:console:emer --verbose=ANY:syslog:err set -- "$@" --log-file set -- "$@" --detach --pidfile - set -- "$@" --listen punix:/var/run/ovsdb-server + set -- "$@" --remote punix:/var/run/ovsdb-server set -- "$@" /etc/openvswitch-switch/conf set -- "$@" $OVSDB_SERVER_OPTS echo -n "Starting ovsdb-server: " diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 0bf11378e..4b83fd348 100644 --- a/ovsdb/jsonrpc-server.c +++ b/ovsdb/jsonrpc-server.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009 Nicira Networks +/* Copyright (c) 2009, 2010 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,15 +36,18 @@ #define THIS_MODULE VLM_ovsdb_jsonrpc_server #include "vlog.h" +struct ovsdb_jsonrpc_remote; struct ovsdb_jsonrpc_session; +/* Message rate-limiting. */ +struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + /* Sessions. */ -static void ovsdb_jsonrpc_session_create_active(struct ovsdb_jsonrpc_server *, - const char *name); -static void ovsdb_jsonrpc_session_create_passive(struct ovsdb_jsonrpc_server *, - struct stream *); -static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_server *); -static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_server *); +static struct ovsdb_jsonrpc_session *ovsdb_jsonrpc_session_create( + struct ovsdb_jsonrpc_remote *, struct jsonrpc_session *); +static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *); +static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *); +static void ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *); /* Triggers. */ static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *, @@ -69,89 +72,141 @@ static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *); struct ovsdb_jsonrpc_server { struct ovsdb *db; - - struct list sessions; /* List of "struct ovsdb_jsonrpc_session"s. */ unsigned int n_sessions, max_sessions; + struct shash remotes; /* Contains "struct ovsdb_jsonrpc_remote *"s. */ +}; - struct pstream **listeners; - size_t n_listeners, allocated_listeners; +/* A configured remote. This is either a passive stream listener plus a list + * of the currently connected sessions, or a list of exactly one active + * session. */ +struct ovsdb_jsonrpc_remote { + struct ovsdb_jsonrpc_server *server; + struct pstream *listener; /* Listener, if passive. */ + struct list sessions; /* List of "struct ovsdb_jsonrpc_session"s. */ }; +static void ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *, + const char *name); +static void ovsdb_jsonrpc_server_del_remote(struct shash_node *); + struct ovsdb_jsonrpc_server * ovsdb_jsonrpc_server_create(struct ovsdb *db) { struct ovsdb_jsonrpc_server *server = xzalloc(sizeof *server); server->db = db; server->max_sessions = 64; - list_init(&server->sessions); + shash_init(&server->remotes); return server; } +/* Sets 'svr''s current set of remotes to the names in 'new_remotes'. The data + * values in 'new_remotes' are ignored. + * + * A remote is an active or passive stream connection method, e.g. "pssl:" or + * "tcp:1.2.3.4". */ void -ovsdb_jsonrpc_server_listen(struct ovsdb_jsonrpc_server *svr, - struct pstream *pstream) +ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *svr, + const struct shash *new_remotes) { - if (svr->n_listeners >= svr->allocated_listeners) { - svr->listeners = x2nrealloc(svr->listeners, &svr->allocated_listeners, - sizeof *svr->listeners); + struct shash_node *node, *next; + + SHASH_FOR_EACH_SAFE (node, next, &svr->remotes) { + if (!shash_find(new_remotes, node->name)) { + ovsdb_jsonrpc_server_del_remote(node); + } + } + SHASH_FOR_EACH (node, new_remotes) { + if (!shash_find(&svr->remotes, node->name)) { + ovsdb_jsonrpc_server_add_remote(svr, node->name); + } } - svr->listeners[svr->n_listeners++] = pstream; } -void -ovsdb_jsonrpc_server_connect(struct ovsdb_jsonrpc_server *svr, - const char *name) +static void +ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr, + const char *name) { - ovsdb_jsonrpc_session_create_active(svr, name); + struct ovsdb_jsonrpc_remote *remote; + struct pstream *listener; + int error; + + error = pstream_open(name, &listener); + if (error && error != EAFNOSUPPORT) { + VLOG_ERR_RL(&rl, "%s: listen failed: %s", name, strerror(error)); + return; + } + + remote = xmalloc(sizeof *remote); + remote->server = svr; + remote->listener = listener; + list_init(&remote->sessions); + shash_add(&svr->remotes, name, remote); + + if (!listener) { + ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name)); + } +} + +static void +ovsdb_jsonrpc_server_del_remote(struct shash_node *node) +{ + struct ovsdb_jsonrpc_remote *remote = node->data; + + ovsdb_jsonrpc_session_close_all(remote); + pstream_close(remote->listener); + shash_delete(&remote->server->remotes, node); + free(remote); } void ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *svr) { - size_t i; + struct shash_node *node; - /* Accept new connections. */ - for (i = 0; i < svr->n_listeners && svr->n_sessions < svr->max_sessions;) { - struct pstream *listener = svr->listeners[i]; - struct stream *stream; - int error; - - error = pstream_accept(listener, &stream); - if (!error) { - ovsdb_jsonrpc_session_create_passive(svr, stream); - } else if (error == EAGAIN) { - i++; - } else if (error) { - VLOG_WARN("%s: accept failed: %s", - pstream_get_name(listener), strerror(error)); - pstream_close(listener); - svr->listeners[i] = svr->listeners[--svr->n_listeners]; + SHASH_FOR_EACH (node, &svr->remotes) { + struct ovsdb_jsonrpc_remote *remote = node->data; + + if (remote->listener && svr->n_sessions < svr->max_sessions) { + struct stream *stream; + int error; + + error = pstream_accept(remote->listener, &stream); + if (!error) { + struct jsonrpc_session *js; + js = jsonrpc_session_open_unreliably(jsonrpc_open(stream)); + ovsdb_jsonrpc_session_create(remote, js); + } else if (error != EAGAIN) { + VLOG_WARN_RL(&rl, "%s: accept failed: %s", + pstream_get_name(remote->listener), + strerror(error)); + } } - } - /* Handle each session. */ - ovsdb_jsonrpc_session_run_all(svr); + ovsdb_jsonrpc_session_run_all(remote); + } } void ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *svr) { - if (svr->n_sessions < svr->max_sessions) { - size_t i; + struct shash_node *node; + + SHASH_FOR_EACH (node, &svr->remotes) { + struct ovsdb_jsonrpc_remote *remote = node->data; - for (i = 0; i < svr->n_listeners; i++) { - pstream_wait(svr->listeners[i]); + if (remote->listener && svr->n_sessions < svr->max_sessions) { + pstream_wait(remote->listener); } - } - ovsdb_jsonrpc_session_wait_all(svr); + ovsdb_jsonrpc_session_wait_all(remote); + } } /* JSON-RPC database server session. */ struct ovsdb_jsonrpc_session { - struct ovsdb_jsonrpc_server *server; - struct list node; /* Element in server's sessions list. */ + struct ovsdb_jsonrpc_remote *remote; + struct list node; /* Element in remote's sessions list. */ /* Triggers. */ struct hmap triggers; /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */ @@ -174,46 +229,31 @@ static void ovsdb_jsonrpc_session_got_notify(struct ovsdb_jsonrpc_session *, struct jsonrpc_msg *); static struct ovsdb_jsonrpc_session * -ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_server *svr, +ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote, struct jsonrpc_session *js) { struct ovsdb_jsonrpc_session *s; s = xzalloc(sizeof *s); - s->server = svr; - list_push_back(&svr->sessions, &s->node); + s->remote = remote; + list_push_back(&remote->sessions, &s->node); hmap_init(&s->triggers); hmap_init(&s->monitors); list_init(&s->completions); s->js = js; s->js_seqno = jsonrpc_session_get_seqno(js); - svr->n_sessions++; + remote->server->n_sessions++; return s; } -static void -ovsdb_jsonrpc_session_create_active(struct ovsdb_jsonrpc_server *svr, - const char *name) -{ - ovsdb_jsonrpc_session_create(svr, jsonrpc_session_open(name)); -} - -static void -ovsdb_jsonrpc_session_create_passive(struct ovsdb_jsonrpc_server *svr, - struct stream *stream) -{ - ovsdb_jsonrpc_session_create( - svr, jsonrpc_session_open_unreliably(jsonrpc_open(stream))); -} - static void ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s) { jsonrpc_session_close(s->js); list_remove(&s->node); - s->server->n_sessions--; + s->remote->server->n_sessions--; } static int @@ -248,12 +288,12 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s) } static void -ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_server *svr) +ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *remote) { struct ovsdb_jsonrpc_session *s, *next; LIST_FOR_EACH_SAFE (s, next, struct ovsdb_jsonrpc_session, node, - &svr->sessions) { + &remote->sessions) { int error = ovsdb_jsonrpc_session_run(s); if (error) { ovsdb_jsonrpc_session_close(s); @@ -271,15 +311,26 @@ ovsdb_jsonrpc_session_wait(struct ovsdb_jsonrpc_session *s) } static void -ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_server *svr) +ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *remote) { struct ovsdb_jsonrpc_session *s; - LIST_FOR_EACH (s, struct ovsdb_jsonrpc_session, node, &svr->sessions) { + LIST_FOR_EACH (s, struct ovsdb_jsonrpc_session, node, &remote->sessions) { ovsdb_jsonrpc_session_wait(s); } } +static void +ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote) +{ + struct ovsdb_jsonrpc_session *s, *next; + + LIST_FOR_EACH_SAFE (s, next, struct ovsdb_jsonrpc_session, node, + &remote->sessions) { + ovsdb_jsonrpc_session_close(s); + } +} + static struct jsonrpc_msg * execute_transaction(struct ovsdb_jsonrpc_session *s, struct jsonrpc_msg *request) @@ -306,7 +357,7 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s, request->id); } else if (!strcmp(request->method, "get_schema")) { reply = jsonrpc_create_reply( - ovsdb_schema_to_json(s->server->db->schema), request->id); + ovsdb_schema_to_json(s->remote->server->db->schema), request->id); } else if (!strcmp(request->method, "echo")) { reply = jsonrpc_create_reply(json_clone(request->params), request->id); } else { @@ -380,7 +431,7 @@ ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, /* Insert into trigger table. */ t = xmalloc(sizeof *t); - ovsdb_trigger_init(s->server->db, + ovsdb_trigger_init(s->remote->server->db, &t->trigger, params, &s->completions, time_msec()); t->session = s; @@ -541,7 +592,7 @@ 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->server->db, &m->replica); + ovsdb_add_replica(s->remote->server->db, &m->replica); m->session = s; hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0)); m->monitor_id = json_clone(monitor_id); @@ -553,7 +604,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, const struct json *columns_json, *select_json; struct ovsdb_parser parser; - table = ovsdb_get_table(s->server->db, node->name); + table = ovsdb_get_table(s->remote->server->db, node->name); if (!table) { error = ovsdb_syntax_error(NULL, NULL, "no table named %s", node->name); @@ -620,7 +671,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, error: if (m) { - ovsdb_remove_replica(s->server->db, &m->replica); + ovsdb_remove_replica(s->remote->server->db, &m->replica); } json = ovsdb_error_to_json(error); @@ -644,7 +695,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->server->db, &m->replica); + ovsdb_remove_replica(s->remote->server->db, &m->replica); return jsonrpc_create_reply(json_object_create(), request_id); } } @@ -657,7 +708,7 @@ ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s) HMAP_FOR_EACH_SAFE (m, next, struct ovsdb_jsonrpc_monitor, node, &s->monitors) { - ovsdb_remove_replica(s->server->db, &m->replica); + ovsdb_remove_replica(s->remote->server->db, &m->replica); } } diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index 6ff6fe0cb..b6f837d5e 100644 --- a/ovsdb/jsonrpc-server.h +++ b/ovsdb/jsonrpc-server.h @@ -17,14 +17,12 @@ #define OVSDB_JSONRPC_SERVER_H 1 struct ovsdb; -struct pstream; +struct shash; struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(struct ovsdb *); -void ovsdb_jsonrpc_server_listen(struct ovsdb_jsonrpc_server *, - struct pstream *); -void ovsdb_jsonrpc_server_connect(struct ovsdb_jsonrpc_server *, - const char *name); +void ovsdb_jsonrpc_server_set_remotes(struct ovsdb_jsonrpc_server *, + const struct shash *); void ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *); void ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *); diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in index 9a888fc83..53cce8878 100644 --- a/ovsdb/ovsdb-server.1.in +++ b/ovsdb/ovsdb-server.1.in @@ -8,18 +8,15 @@ ovsdb\-server \- Open vSwitch database server .SH SYNOPSIS \fBovsdb\-server\fR \fIdatabase\fR -[\fB--connect \fIremote\fR]\&... -[\fB--listen \fIlocal\fR]\&... +[\fB--remote=\fIremote\fR]\&... .so lib/daemon-syn.man .so lib/vlog-syn.man .so lib/common-syn.man . .SH DESCRIPTION The \fBovsdb\-server\fR program provides RPC interfaces to an Open -vSwitch database (OVSDB). It can listen for JSON-RPC connections from -TCP/IP or Unix domain socket clients (with \fB\-\-listen\fR), connect to -remote JSON-RPC TCP/IP or Unix domain socket clients (with -\fB\-\-connect\fR). +vSwitch database (OVSDB). It supports JSON-RPC client connections +over active or passive TCP/IP or Unix domain sockets. .PP The name of the OVSDB file must be specified on the command line as \fIdatabase\fR, which must already have been created and initialized @@ -27,9 +24,9 @@ using, for example, \fBovsdb\-tool create\fR. . .SH OPTIONS . -.IP "\fB\-\-listen=\fIlocal\fR" -Makes \fBovsdb\-server\fR listen for JSON-RPC connections on -\fIlocal\fR, which must take one of the following forms: +.IP "\fB\-\-remote=\fIremote\fR" +Adds \fIremote\fR as a connection method used by \fBovsdb\-server\fR. +\fIremote\fR must take one of the following forms: . .RS .IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]" @@ -37,21 +34,26 @@ Listens for JSON-RPC connections on the given TCP \fIport\fR. By default, \fB\*(PN\fR listens for connections to any local IP address, but \fIip\fR may be specified to listen only for connections to the given \fIip\fR. +. .IP "\fBpunix:\fIfile\fR" Listens for JSON-RPC connections on the Unix domain server socket named \fIfile\fR. -.RE -. -.IP "\fB\-\-connect=\fIremote\fR" -Makes \fBovsdb\-server\fR initiate a JSON-RPC connection to -\fIremote\fR, which must take one of the forms listed below. The -server will reconnect to \fIremote\fR as necessary. . -.RS .IP "\fBtcp:\fIip\fB:\fIport\fR" -Connects to the given TCP \fIport\fR on \fIip\fR. +Initiates a JSON-RPC connection to the given TCP \fIport\fR on +\fIip\fR and reconnects as necessary. +. .IP "\fBunix:\fIfile\fR" -Connects to the Unix domain server socket named \fIfile\fR. +Initiates a JSON-RPC connection to the Unix domain server socket named +\fIfile\fR as reconnects as necessary. +. +.IP "\fBdb:\fItable\fB,\fIcolumn\fR" +Reads additional connection methods from \fIcolumn\fR in all of the +rows in \fItable\fR within the \fBovsdb\-server\fR database. The +\fIcolumn\fR must have type string or set of strings. The connection +methods in the column must have one of the forms described above. As +the contents of \fIcolumn\fR changes, \fBovsdb\-server\fR also adds +and drops connection methods accordingly. .RE . .SS "Daemon Options" diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 125001fe6..9250914fa 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009 Nicira Networks +/* Copyright (c) 2009, 2010 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ #include #include +#include "column.h" #include "command-line.h" #include "daemon.h" #include "fault.h" @@ -31,11 +32,15 @@ #include "jsonrpc-server.h" #include "leak-checker.h" #include "list.h" +#include "ovsdb-data.h" +#include "ovsdb-types.h" #include "ovsdb-error.h" #include "poll-loop.h" #include "process.h" +#include "row.h" #include "stream.h" #include "svec.h" +#include "table.h" #include "timeval.h" #include "trigger.h" #include "util.h" @@ -47,24 +52,24 @@ static unixctl_cb_func ovsdb_server_exit; static void parse_options(int argc, char *argv[], char **file_namep, - struct svec *active, struct svec *passive, - char **unixctl_pathp); + struct shash *remotes, char **unixctl_pathp); static void usage(void) NO_RETURN; +static void set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, + const struct ovsdb *db, struct shash *remotes); + int main(int argc, char *argv[]) { char *unixctl_path = NULL; struct unixctl_server *unixctl; struct ovsdb_jsonrpc_server *jsonrpc; - struct svec active, passive; + struct shash remotes; struct ovsdb_error *error; struct ovsdb *db; - const char *name; char *file_name; bool exiting; int retval; - size_t i; set_program_name(argv[0]); register_fault_handlers(); @@ -73,7 +78,7 @@ main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); process_init(); - parse_options(argc, argv, &file_name, &active, &passive, &unixctl_path); + parse_options(argc, argv, &file_name, &remotes, &unixctl_path); die_if_already_running(); daemonize_start(); @@ -84,21 +89,7 @@ main(int argc, char *argv[]) } jsonrpc = ovsdb_jsonrpc_server_create(db); - SVEC_FOR_EACH (i, name, &active) { - ovsdb_jsonrpc_server_connect(jsonrpc, name); - } - for (i = 0; i < passive.n; i++) { - struct pstream *pstream; - int error; - - error = pstream_open(passive.names[i], &pstream); - if (error) { - ovs_fatal(error, "failed to listen on \"%s\"", passive.names[i]); - } - ovsdb_jsonrpc_server_listen(jsonrpc, pstream); - } - svec_destroy(&active); - svec_destroy(&passive); + set_remotes(jsonrpc, db, &remotes); retval = unixctl_server_create(unixctl_path, &unixctl); if (retval) { @@ -111,6 +102,7 @@ main(int argc, char *argv[]) exiting = false; while (!exiting) { + set_remotes(jsonrpc, db, &remotes); ovsdb_jsonrpc_server_run(jsonrpc); unixctl_server_run(unixctl); ovsdb_trigger_run(db, time_msec()); @@ -124,6 +116,75 @@ main(int argc, char *argv[]) return 0; } +static void +query_db_remotes(const char *name_, const struct ovsdb *db, + struct shash *remotes) +{ + char *name, *db_prefix, *table_name, *column_name; + const struct ovsdb_column *column; + const struct ovsdb_table *table; + const struct ovsdb_row *row; + char *save_ptr = NULL; + + name = xstrdup(name_); + db_prefix = strtok_r(name, ":", &save_ptr); + table_name = strtok_r(NULL, ",", &save_ptr); + column_name = strtok_r(NULL, ",", &save_ptr); + if (!table_name || !column_name) { + ovs_fatal(0, "remote \"%s\": invalid syntax", name_); + } + + table = ovsdb_get_table(db, table_name); + if (!table) { + ovs_fatal(0, "remote \"%s\": no table named %s", name_, table_name); + } + + column = ovsdb_table_schema_get_column(table->schema, column_name); + if (!column) { + ovs_fatal(0, "remote \"%s\": table \"%s\" has no column \"%s\"", + name_, table_name, column_name); + } + + if (column->type.key_type != OVSDB_TYPE_STRING + || column->type.value_type != OVSDB_TYPE_VOID) { + ovs_fatal(0, "remote \"%s\": type of table \"%s\" column \"%s\" is " + "not string or set of strings", + name_, table_name, column_name); + } + + HMAP_FOR_EACH (row, struct ovsdb_row, hmap_node, &table->rows) { + const struct ovsdb_datum *datum; + size_t i; + + datum = &row->fields[column->index]; + for (i = 0; i < datum->n; i++) { + shash_add_once(remotes, datum->keys[i].string, NULL); + } + } +} + +static void +set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, + const struct ovsdb *db, struct shash *remotes) +{ + struct shash resolved_remotes; + struct shash_node *node; + + shash_init(&resolved_remotes); + SHASH_FOR_EACH (node, remotes) { + const char *name = node->name; + + if (!strncmp(name, "db:", 3)) { + query_db_remotes(name, db, &resolved_remotes); + } else { + shash_add_once(&resolved_remotes, name, NULL); + } + } + ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes); + shash_destroy(&resolved_remotes); +} + + static void ovsdb_server_exit(struct unixctl_conn *conn, const char *args UNUSED, void *exiting_) @@ -135,20 +196,17 @@ ovsdb_server_exit(struct unixctl_conn *conn, const char *args UNUSED, static void parse_options(int argc, char *argv[], char **file_namep, - struct svec *active, struct svec *passive, - char **unixctl_pathp) + struct shash *remotes, char **unixctl_pathp) { enum { OPT_DUMMY = UCHAR_MAX + 1, - OPT_CONNECT, - OPT_LISTEN, + OPT_REMOTE, OPT_UNIXCTL, VLOG_OPTION_ENUMS, LEAK_CHECKER_OPTION_ENUMS }; static struct option long_options[] = { - {"connect", required_argument, 0, OPT_CONNECT}, - {"listen", required_argument, 0, OPT_LISTEN}, + {"remote", required_argument, 0, OPT_REMOTE}, {"unixctl", required_argument, 0, OPT_UNIXCTL}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, @@ -159,8 +217,7 @@ parse_options(int argc, char *argv[], char **file_namep, }; char *short_options = long_options_to_short_options(long_options); - svec_init(active); - svec_init(passive); + shash_init(remotes); for (;;) { int c; @@ -170,12 +227,8 @@ parse_options(int argc, char *argv[], char **file_namep, } switch (c) { - case OPT_CONNECT: - svec_add(active, optarg); - break; - - case OPT_LISTEN: - svec_add(passive, optarg); + case OPT_REMOTE: + shash_add_once(remotes, optarg, NULL); break; case OPT_UNIXCTL: @@ -223,8 +276,7 @@ usage(void) "where DATABASE is a database file in ovsdb format.\n", program_name, program_name); printf("\nJSON-RPC options (may be specified any number of times):\n" - " --connect=REMOTE make active connection to REMOTE\n" - " --listen=LOCAL passively listen on LOCAL\n"); + " --remote=REMOTE connect or listen to REMOTE\n"); stream_usage("JSON-RPC", true, true); daemon_usage(); vlog_usage(); diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at index 6e968f060..22028d900 100644 --- a/tests/ovs-vsctl.at +++ b/tests/ovs-vsctl.at @@ -20,7 +20,7 @@ m4_define([OVS_VSCTL_SETUP], "table": "Open_vSwitch", "row": {}}]']], [0], [ignore], [ignore]) - AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --listen=punix:socket --unixctl=$PWD/unixctl db >/dev/null 2>&1], [0], [ignore], [ignore])]) + AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --remote=punix:socket --unixctl=$PWD/unixctl db >/dev/null 2>&1], [0], [ignore], [ignore])]) dnl OVS_VSCTL_CLEANUP dnl diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at index b1c78e005..0ce65355a 100644 --- a/tests/ovsdb-idl.at +++ b/tests/ovsdb-idl.at @@ -28,7 +28,7 @@ m4_define([OVSDB_CHECK_IDL], fi ovsdb-tool create db $SCHEMA], [0], [stdout], [ignore]) - AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --pidfile=$PWD/server-pid --listen=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --pidfile=$PWD/server-pid --remote=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) m4_if([$2], [], [], [OVS_CHECK_LCOV([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat server-pid`])]) AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $3], diff --git a/tests/ovsdb-monitor.at b/tests/ovsdb-monitor.at index f0b20e155..47300ea3b 100644 --- a/tests/ovsdb-monitor.at +++ b/tests/ovsdb-monitor.at @@ -23,7 +23,7 @@ m4_define([OVSDB_CHECK_MONITOR], OVS_CHECK_LCOV([ovsdb-tool create db schema], [0], [stdout], [ignore]) m4_foreach([txn], [$3], [OVS_CHECK_LCOV([ovsdb-tool transact db 'txn'], [0], [ignore], [ignore])]) - AT_CHECK([ovsdb-server --detach --pidfile=$PWD/server-pid --listen=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-server --detach --pidfile=$PWD/server-pid --remote=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) AT_CHECK([ovsdb-client --detach --pidfile=$PWD/client-pid monitor --format=csv unix:socket $4 > output], [0], [ignore], [ignore], [kill `cat server-pid`]) m4_foreach([txn], [$5], diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 98aeb4a84..e73add80a 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -20,7 +20,7 @@ m4_define([OVSDB_CHECK_EXECUTION], AT_DATA([schema], [$2 ]) OVS_CHECK_LCOV([ovsdb-tool create db schema], [0], [stdout], [ignore]) - AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --listen=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) + AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --remote=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) m4_foreach([txn], [$3], [OVS_CHECK_LCOV([ovsdb-client transact unix:socket 'txn'], [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`]) @@ -32,3 +32,36 @@ cat stdout >> output AT_CLEANUP]) EXECUTION_EXAMPLES + +AT_SETUP([--remote=db: implementation]) +AT_KEYWORDS([ovsdb server positive]) +AT_DATA([schema], + [[{"name": "mydb", + "tables": { + "Manager": { + "columns": { + "manager": {"type": "string"}}}}} +]]) +OVS_CHECK_LCOV([ovsdb-tool create db schema], [0], [ignore], [ignore]) +OVS_CHECK_LCOV( + [[ovsdb-tool transact db \ + '[{"op": "insert", + "table": "Manager", + "row": {"manager": "punix:socket"}}]']], [0], [ignore], [ignore]) +AT_CHECK([ovsdb-server --detach --pidfile=$PWD/pid --remote=db:Manager,manager --unixctl=$PWD/unixctl db], [0], [ignore], [ignore]) +OVS_CHECK_LCOV( + [[ovsdb-client transact unix:socket \ + '[{"op": "select", + "table": "Manager", + "where": [], + "columns": ["manager"]}]']], + [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`]) +AT_CHECK( + [perl $srcdir/uuidfilt.pl stdout], + [0], + [[[{"rows":[{"manager":"punix:socket"}]}] +]], + [ignore], + [test ! -e pid || kill `cat pid`]) +test ! -e pid || kill `cat pid` +AT_CLEANUP diff --git a/vswitchd/vswitch-idl.ovsidl b/vswitchd/vswitch-idl.ovsidl index 3fcf385d0..1c555a4f0 100644 --- a/vswitchd/vswitch-idl.ovsidl +++ b/vswitchd/vswitch-idl.ovsidl @@ -23,6 +23,9 @@ "controller": { "comment": "Default Controller used by bridges.", "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}}, + "managers": { + "comment": "Remote database clients to which the Open vSwitch's database server should connect or to which it should listen.", + "type": {"key": "string", "min": 0, "max": "unlimited"}}, "ssl": { "comment": "SSL used globally by the daemon.", "type": {"key": "uuid", "keyRefTable": "SSL", "min": 0, "max": 1}}, diff --git a/xenserver/etc_init.d_vswitch b/xenserver/etc_init.d_vswitch index 7263336b3..789ec7398 100755 --- a/xenserver/etc_init.d_vswitch +++ b/xenserver/etc_init.d_vswitch @@ -5,7 +5,7 @@ # chkconfig: 2345 09 91 # description: Manage vswitch kernel modules and user-space daemon -# Copyright (C) 2009 Nicira Networks, Inc. +# Copyright (C) 2009, 2010 Nicira Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,8 +29,7 @@ test -e /etc/sysconfig/vswitch && . /etc/sysconfig/vswitch : ${FORCE_COREFILES:=y} # Config variables specific to ovsdb-server -: ${OVSDB_SERVER_LISTEN:=punix:/var/run/ovsdb-server} -: ${OVSDB_SERVER_CONNECT:=} +: ${OVSDB_SERVER_REMOTES:=punix:/var/run/ovsdb-server db:Open_vSwitch,managers} : ${OVSDB_SERVER_DB:=/etc/ovs-vswitchd.conf.db} : ${OVSDB_SERVER_PIDFILE:=/var/run/ovsdb-server.pid} : ${OVSDB_SERVER_RUN_DIR:=/var/xen/vswitch} @@ -137,14 +136,10 @@ function start_ovsdb_server { mkdir -p "$OVSDB_SERVER_RUN_DIR" fi cd "$OVSDB_SERVER_RUN_DIR" - local listen_method="" - if [ -n "$OVSDB_SERVER_LISTEN" ]; then - listen_method="--listen=$OVSDB_SERVER_LISTEN" - fi - local connect_method="" - if [ -n "$OVSDB_SERVER_CONNECT" ]; then - connect_method="--connect=$OVSDB_SERVER_CONNECT" - fi + local remotes= + for remote in "$OVSDB_SERVER_REMOTES"; do + remotes="$remotes --remote=$OVSDB_SERVER_REMOTES" + done if [ -n "$OVSDB_SERVER_FILE_LOGLEVEL" ]; then logfile_level_opt="-vANY:FILE:${OVSDB_SERVER_FILE_LOGLEVEL}" logfile_file_opt="--log-file=$OVSDB_SERVER_LOGFILE" @@ -173,9 +168,9 @@ function start_ovsdb_server { if [ "$daemonize" != "y" ]; then # Start in background and force a "success" message action "Starting ovsdb_server ($strace_opt$valgrind_opt)" true - (nice -n "$OVSDB_SERVER_PRIORITY" $strace_opt $valgrind_opt "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $connect_method $listen_method) & + (nice -n "$OVSDB_SERVER_PRIORITY" $strace_opt $valgrind_opt "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes) & else - action "Starting ovsdb-server" nice -n "$OVSDB_SERVER_PRIORITY" "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $connect_method $listen_method + action "Starting ovsdb-server" nice -n "$OVSDB_SERVER_PRIORITY" "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes fi } diff --git a/xenserver/usr_share_vswitch_scripts_sysconfig.template b/xenserver/usr_share_vswitch_scripts_sysconfig.template index f1d19785d..2651cc3db 100644 --- a/xenserver/usr_share_vswitch_scripts_sysconfig.template +++ b/xenserver/usr_share_vswitch_scripts_sysconfig.template @@ -25,13 +25,9 @@ # See the manpage for "core". # COREFILE_PATTERN="/var/log/%e-%t" -# OVSDB_SERVER_LISTEN: Method to have ovsdb-server listen for a JSON-RPC -# connection. -# OVSDB_SERVER_LISTEN=punix:/var/run/ovsdb-server - -# OVSDB_SERVER_CONNECT: Method to have ovsdb-server initiate a JSON-RPC -# connection to a remote server. -# OVSDB_SERVER_CONNECT= +# OVSDB_SERVER_REMOTES: Space-separated list of methods on which to have +# ovsdb-server listen or connect for a JSON-RPC connection. +# OVSDB_SERVER_REMOTES="punix:/var/run/ovsdb-server db:Open_vSwitch,managers" # OVSDB_SERVER_DB: File for which ovsdb-server uses for storage. # OVSDB_SERVER_DB=/etc/ovs-vswitchd.conf.db