diff options
-rwxr-xr-x | debian/openvswitch-switch.init | 3 | ||||
-rw-r--r-- | ovsdb/ovsdb-server.1.in | 9 | ||||
-rw-r--r-- | ovsdb/ovsdb-server.c | 109 | ||||
-rw-r--r-- | tests/ovsdb-macros.at | 3 | ||||
-rw-r--r-- | tests/ovsdb-server.at | 54 | ||||
-rwxr-xr-x | xenserver/etc_init.d_vswitch | 5 |
6 files changed, 159 insertions, 24 deletions
diff --git a/debian/openvswitch-switch.init b/debian/openvswitch-switch.init index 7ce9a645..3db7ace7 100755 --- a/debian/openvswitch-switch.init +++ b/debian/openvswitch-switch.init @@ -230,6 +230,9 @@ case "$1" in set -- "$@" --detach --pidfile $monitor_opt set -- "$@" --remote punix:/var/run/ovsdb-server set -- "$@" /etc/openvswitch-switch/conf + set -- "$@" --private-key=db:SSL,private_key + set -- "$@" --certificate=db:SSL,certificate + set -- "$@" --bootstrap-ca-cert=db:SSL,ca_cert set -- "$@" $OVSDB_SERVER_OPTS echo -n "Starting ovsdb-server: " start-stop-daemon --start --quiet --pidfile /var/run/ovsdb-server.pid \ diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in index d315c8ae..14d88944 100644 --- a/ovsdb/ovsdb-server.1.in +++ b/ovsdb/ovsdb-server.1.in @@ -59,6 +59,15 @@ run a single command, e.g.: .SS "Logging Options" .so lib/vlog.man .SS "Public Key Infrastructure Options" +The options described below for configuring the SSL public key +infrastructure accept a special syntax for obtaining their +configuration from the database. If any of these options is given +\fBdb:\fItable\fB,\fIcolumn\fR as its argument, then the actual file +name is read from the specified \fIcolumn\fR in \fItable\fR within the +\fBovsdb\-server\fR database. The \fIcolumn\fR must have type string +or set of strings. The first nonempty string in the table is taken as +the file name. (This means that ordinarily there should be at most +one row in \fItable\fR.) .so lib/ssl.man .so lib/ssl-bootstrap.man .SS "Other Options" diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c index 7c4b7330..243243d2 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -49,6 +49,12 @@ #include "vlog.h" #define THIS_MODULE VLM_ovsdb_server +/* SSL configuration. */ +static char *private_key_file; +static char *certificate_file; +static char *ca_cert_file; +static bool bootstrap_ca_cert; + static unixctl_cb_func ovsdb_server_exit; static unixctl_cb_func ovsdb_server_compact; @@ -57,8 +63,8 @@ static void parse_options(int argc, char *argv[], char **file_namep, char **run_command); static void usage(void) NO_RETURN; -static void set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, - const struct ovsdb *db, struct shash *remotes); +static void reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, + const struct ovsdb *db, struct shash *remotes); int main(int argc, char *argv[]) @@ -95,7 +101,7 @@ main(int argc, char *argv[]) } jsonrpc = ovsdb_jsonrpc_server_create(db); - set_remotes(jsonrpc, db, &remotes); + reconfigure_from_db(jsonrpc, db, &remotes); retval = unixctl_server_create(unixctl_path, &unixctl); if (retval) { @@ -126,7 +132,7 @@ main(int argc, char *argv[]) exiting = false; while (!exiting) { - set_remotes(jsonrpc, db, &remotes); + reconfigure_from_db(jsonrpc, db, &remotes); ovsdb_jsonrpc_server_run(jsonrpc); unixctl_server_run(unixctl); ovsdb_trigger_run(db, time_msec()); @@ -159,13 +165,14 @@ main(int argc, char *argv[]) } static void -query_db_remotes(const char *name_, const struct ovsdb *db, - struct shash *remotes) +parse_db_string_column(const struct ovsdb *db, + const char *name_, + const struct ovsdb_table **tablep, + const struct ovsdb_column **columnp) { char *name, *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_); @@ -173,26 +180,68 @@ query_db_remotes(const char *name_, const struct ovsdb *db, 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_); + ovs_fatal(0, "\"%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); + ovs_fatal(0, "\"%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\"", + ovs_fatal(0, "\"%s\": table \"%s\" has no column \"%s\"", name_, table_name, column_name); } + free(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 " + ovs_fatal(0, "\"%s\": table \"%s\" column \"%s\" is " "not string or set of strings", - name_, table_name, column_name); + name_, table->schema->name, column->name); + } + + *columnp = column; + *tablep = table; +} + +static const char * +query_db_string(const struct ovsdb *db, const char *name) +{ + if (!name || strncmp(name, "db:", 3)) { + return name; + } else { + const struct ovsdb_column *column; + const struct ovsdb_table *table; + const struct ovsdb_row *row; + + parse_db_string_column(db, name, &table, &column); + + 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++) { + if (datum->keys[i].string[0]) { + return datum->keys[i].string; + } + } + } + return NULL; } +} + +static void +query_db_remotes(const char *name, const struct ovsdb *db, + struct shash *remotes) +{ + const struct ovsdb_column *column; + const struct ovsdb_table *table; + const struct ovsdb_row *row; + + parse_db_string_column(db, name, &table, &column); HMAP_FOR_EACH (row, struct ovsdb_row, hmap_node, &table->rows) { const struct ovsdb_datum *datum; @@ -203,17 +252,17 @@ query_db_remotes(const char *name_, const struct ovsdb *db, shash_add_once(remotes, datum->keys[i].string, NULL); } } - - free(name); } +/* Reconfigures ovsdb-server based on information in the database. */ static void -set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, - const struct ovsdb *db, struct shash *remotes) +reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc, + const struct ovsdb *db, struct shash *remotes) { struct shash resolved_remotes; struct shash_node *node; + /* Configure remotes. */ shash_init(&resolved_remotes); SHASH_FOR_EACH (node, remotes) { const char *name = node->name; @@ -226,8 +275,13 @@ set_remotes(struct ovsdb_jsonrpc_server *jsonrpc, } ovsdb_jsonrpc_server_set_remotes(jsonrpc, &resolved_remotes); shash_destroy(&resolved_remotes); -} + /* Configure SSL. */ + stream_ssl_set_private_key_file(query_db_string(db, private_key_file)); + stream_ssl_set_certificate_file(query_db_string(db, certificate_file)); + stream_ssl_set_ca_cert_file(query_db_string(db, ca_cert_file), + bootstrap_ca_cert); +} static void ovsdb_server_exit(struct unixctl_conn *conn, const char *args OVS_UNUSED, @@ -282,7 +336,9 @@ parse_options(int argc, char *argv[], char **file_namep, LEAK_CHECKER_LONG_OPTIONS, #ifdef HAVE_OPENSSL {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT}, - STREAM_SSL_LONG_OPTIONS + {"private-key", required_argument, 0, 'p'}, + {"certificate", required_argument, 0, 'c'}, + {"ca-cert", required_argument, 0, 'C'}, #endif {0, 0, 0, 0}, }; @@ -322,14 +378,25 @@ parse_options(int argc, char *argv[], char **file_namep, LEAK_CHECKER_OPTION_HANDLERS #ifdef HAVE_OPENSSL - STREAM_SSL_OPTION_HANDLERS + case 'p': + private_key_file = optarg; + break; + + case 'c': + certificate_file = optarg; + break; + + case 'C': + ca_cert_file = optarg; + bootstrap_ca_cert = false; + break; case OPT_BOOTSTRAP_CA_CERT: - stream_ssl_set_ca_cert_file(optarg, true); + ca_cert_file = optarg; + bootstrap_ca_cert = true; break; #endif - case '?': exit(EXIT_FAILURE); diff --git a/tests/ovsdb-macros.at b/tests/ovsdb-macros.at index ebe0d9de..c1aa619c 100644 --- a/tests/ovsdb-macros.at +++ b/tests/ovsdb-macros.at @@ -7,7 +7,8 @@ m4_define([OVSDB_INIT], [0], [stdout], [ignore]) AT_CHECK( [[ovsdb-tool transact $1 \ - '[{"op": "insert", + '["Open_vSwitch", + {"op": "insert", "table": "Open_vSwitch", "row": {}}]']], [0], [ignore], [ignore])]) diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at index 603de945..800506bb 100644 --- a/tests/ovsdb-server.at +++ b/tests/ovsdb-server.at @@ -90,6 +90,60 @@ AT_CHECK( OVSDB_SERVER_SHUTDOWN AT_CLEANUP +AT_SETUP([SSL db: implementation]) +AT_KEYWORDS([ovsdb server positive ssl $5]) +AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) +AT_SKIP_IF([test "x$RANDOM" = x]) +SSL_PORT=`expr 32767 + \( $RANDOM % 32767 \)` +PKIDIR=$abs_top_srcdir/tests +AT_SKIP_IF([expr "$PKIDIR" : ".*[ '\" +
\\]"]) +AT_DATA([schema], + [[{"name": "mydb", + "tables": { + "SSL": { + "columns": { + "private_key": {"type": "string"}, + "certificate": {"type": "string"}, + "ca_cert": {"type": "string"}}}}} +]]) +AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore]) +AT_CHECK( + [[ovsdb-tool transact db \ + '["mydb", + {"op": "insert", + "table": "SSL", + "row": {"private_key": "'"$PKIDIR/testpki-privkey2.pem"'", + "certificate": "'"$PKIDIR/testpki-cert2.pem"'", + "ca_cert": "'"$PKIDIR/testpki-cacert.pem"'"}}]']], + [0], [ignore], [ignore]) +AT_CHECK( + [ovsdb-server --detach --pidfile=$PWD/pid \ + --private-key=db:SSL,private_key \ + --certificate=db:SSL,certificate \ + --ca-cert=db:SSL,ca_cert \ + --remote=pssl:$SSL_PORT:127.0.0.1 --unixctl=$PWD/unixctl db], + [0], [ignore], [ignore]) +AT_CHECK( + [[ovsdb-client \ + --private-key=$PKIDIR/testpki-privkey.pem \ + --certificate=$PKIDIR/testpki-cert.pem \ + --ca-cert=$PKIDIR/testpki-cacert.pem \ + transact ssl:127.0.0.1:$SSL_PORT \ + '["mydb", + {"op": "select", + "table": "SSL", + "where": [], + "columns": ["private_key"]}]']], + [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`]) +cat stdout >> output +AT_CHECK_UNQUOTED( + [perl $srcdir/uuidfilt.pl output], [0], + [[[{"rows":[{"private_key":"$PKIDIR/testpki-privkey2.pem"}]}] +]], [ignore], [test ! -e pid || kill `cat pid`]) +OVSDB_SERVER_SHUTDOWN +AT_CLEANUP + AT_SETUP([compacting online]) AT_KEYWORDS([ovsdb server compact]) AT_DATA([schema], [ORDINAL_SCHEMA diff --git a/xenserver/etc_init.d_vswitch b/xenserver/etc_init.d_vswitch index 304eabb1..7a8b83e6 100755 --- a/xenserver/etc_init.d_vswitch +++ b/xenserver/etc_init.d_vswitch @@ -171,12 +171,13 @@ function start_ovsdb_server { valgrind_opt="valgrind --log-file=$OVSDB_SERVER_VALGRIND_LOG $OVSDB_SERVER_VALGRIND_OPT" daemonize="n" fi + ssl_opts="--private-key=db:SSL,private_key --certificate=db:SSL,certificate --bootstrap-ca-cert=db:SSL,ca_cert" 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 $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes) & + (nice -n "$OVSDB_SERVER_PRIORITY" $strace_opt $valgrind_opt "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes $ssl_opts) & else - action "Starting ovsdb-server" nice -n "$OVSDB_SERVER_PRIORITY" "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes + action "Starting ovsdb-server" nice -n "$OVSDB_SERVER_PRIORITY" "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes $ssl_opts fi } |