Skip to content

Commit

Permalink
ovsdb-server: Add support for a built-in _Server database.
Browse files Browse the repository at this point in the history
The _Server database is valuable primarily because it provides database
clients a way to find out the details of changes to databases, schemas,
etc. in a granular, natural way.  Until now, the only way that the server
could notify clients about these kinds of changes was to close the session;
when the client reconnects, it is expected to reassess the server's state.
One way to provide this kind of granular information would be to add
specific JSON-RPC requests to obtain notifications for different kinds of
changes, but since ovsdb-server already provides granular and flexible
notification support for databases, using a database for the purpose is
convenient and avoids duplicating functionality.

Initially this database only reports databases' names and schemas, but
when clustering support is added in a later commit it will also report
important aspects of clustering and cluster status.  Thus, this database
also reduces the need to add JSON-RPC calls to retrieve information about
new features.

Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
blp committed Mar 24, 2018
1 parent 00d5d63 commit 6bb9b06
Show file tree
Hide file tree
Showing 18 changed files with 367 additions and 57 deletions.
4 changes: 4 additions & 0 deletions Documentation/ref/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ The remainder are still in roff format can be found below:
- `(pdf) <http://openvswitch.org/support/dist-docs/ovsdb-server.1.pdf>`__
- `(html) <http://openvswitch.org/support/dist-docs/ovsdb-server.1.html>`__
- `(plain text) <http://openvswitch.org/support/dist-docs/ovsdb-server.1.txt>`__
* - ovsdb-server(5)
- `(pdf) <http://openvswitch.org/support/dist-docs/ovsdb-server.5.pdf>`__
- `(html) <http://openvswitch.org/support/dist-docs/ovsdb-server.5.html>`__
- `(plain text) <http://openvswitch.org/support/dist-docs/ovsdb-server.5.txt>`__
* - ovsdb-tool(1)
- `(pdf) <http://openvswitch.org/support/dist-docs/ovsdb-tool.1.pdf>`__
- `(html) <http://openvswitch.org/support/dist-docs/ovsdb-tool.1.html>`__
Expand Down
8 changes: 0 additions & 8 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,6 @@ EXTRA_DIST = \
.travis/osx-prepare.sh \
appveyor.yml \
boot.sh \
build-aux/cccl \
build-aux/cksum-schema-check \
build-aux/calculate-schema-cksum \
build-aux/dist-docs \
build-aux/dpdkstrip.py \
build-aux/sodepends.py \
build-aux/soexpand.py \
build-aux/xml2nroff \
poc/builders/Vagrantfile \
poc/playbook-centos-builder.yml \
poc/playbook-ubuntu-builder.yml \
Expand Down
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ v2.9.0 - 19 Feb 2018
* New high-level documentation in ovsdb(7).
* New file format documentation for developers in ovsdb(5).
* Protocol documentation moved from ovsdb-server(1) to ovsdb-server(7).
* ovsdb-server now always hosts a built-in database named _Server. See
ovsdb-server(5) for more details.
* ovsdb-client: New "get-schema-cksum" and "query" commands.
* ovsdb-client: New "backup" and "restore" commands.
* ovsdb-client: New --timeout option.
Expand Down
12 changes: 11 additions & 1 deletion build-aux/automake.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# This file is purely used for checking the style of the python build tools.
EXTRA_DIST += \
build-aux/calculate-schema-cksum \
build-aux/cccl \
build-aux/cksum-schema-check \
build-aux/dist-docs \
build-aux/dpdkstrip.py \
build-aux/sodepends.py \
build-aux/soexpand.py \
build-aux/text2c \
build-aux/xml2nroff

FLAKE8_PYFILES += \
$(srcdir)/build-aux/xml2nroff \
build-aux/dpdkstrip.py \
Expand Down
16 changes: 16 additions & 0 deletions build-aux/text2c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#! /usr/bin/python

import re
import sys

"""This utility reads its input, which should be plain text, and
prints it back transformed into quoted strings that may be #included
into C source code."""

while True:
line = sys.stdin.readline()
if not line:
break

s = line.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
print('"' + s + '"')
1 change: 1 addition & 0 deletions debian/openvswitch-switch.manpages
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ovsdb/ovsdb-server.1
ovsdb/ovsdb-server.5
utilities/ovs-ctl.8
utilities/ovs-dpctl-top.8
utilities/ovs-dpctl.8
Expand Down
3 changes: 3 additions & 0 deletions ovsdb/.gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
/_server.ovsschema.inc
/_server.ovsschema.stamp
/ovsdb-client
/ovsdb-client.1
/ovsdb-doc
/ovsdb-dot
/ovsdb-idlc
/ovsdb-server
/ovsdb-server.1
/ovsdb-server.5
/ovsdb-tool
/ovsdb-tool.1
/libovsdb.pc
9 changes: 9 additions & 0 deletions ovsdb/_server.ovsschema
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{"name": "_Server",
"version": "1.0.0",
"cksum": "3931859656 185",
"tables": {
"Database": {
"columns": {
"name": {"type": "string"},
"schema": {"type": "string"}},
"isRoot": true}}}
31 changes: 31 additions & 0 deletions ovsdb/_server.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<database name="ovsdb-server" title="ovsdb-server _Server schema">
<p>
Every <code>ovsdb-server</code> (version 2.9 or later) always hosts an
instance of this schema, which holds information on the status and
configuration of the server itself. This database is read-only. This
manpage describes the schema for this database.
</p>

<table name="Database" title="Databases.">
<p>
This table describes the databases hosted by the database server, with
one row per database. As its database configuration and status changes,
the server automatically and immediately updates the table to match.
</p>
<p>
Clients can use the <code>_uuid</code> column in this table as a
generation number. The server generates a fresh <code>_uuid</code> every
time it adds a database, so that removing and then re-adding a database
to the server causes its row <code>_uuid</code> to change.
</p>

<column name="name">
The database's name, as specified in its schema.
</column>

<column name="schema">
The database schema, as a JSON string.
</column>
</table>
</database>
25 changes: 25 additions & 0 deletions ovsdb/automake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,28 @@ EXTRA_DIST += ovsdb/ovsdb-dot.in ovsdb/dot2pic
noinst_SCRIPTS += ovsdb/ovsdb-dot
CLEANFILES += ovsdb/ovsdb-dot
OVSDB_DOT = $(run_python) $(srcdir)/ovsdb/ovsdb-dot.in

EXTRA_DIST += ovsdb/_server.ovsschema
CLEANFILES += ovsdb/_server.ovsschema.inc
ovsdb/ovsdb-server.o: ovsdb/_server.ovsschema.inc
ovsdb/_server.ovsschema.inc: ovsdb/_server.ovsschema $(srcdir)/build-aux/text2c
$(AM_V_GEN)$(run_python) $(srcdir)/build-aux/text2c < $< > $@.tmp
$(AM_V_at)mv $@.tmp $@

# Version checking for _server.ovsschema.
ALL_LOCAL += ovsdb/_server.ovsschema.stamp
ovsdb/_server.ovsschema.stamp: ovsdb/_server.ovsschema
$(srcdir)/build-aux/cksum-schema-check $? $@
CLEANFILES += ovsdb/_server.ovsschema.stamp

# _Server schema documentation
EXTRA_DIST += ovsdb/_server.xml
CLEANFILES += ovsdb/ovsdb-server.5
man_MANS += ovsdb/ovsdb-server.5
ovsdb/ovsdb-server.5: \
ovsdb/ovsdb-doc ovsdb/_server.xml ovsdb/_server.ovsschema
$(AM_V_GEN)$(OVSDB_DOC) \
--version=$(VERSION) \
$(srcdir)/ovsdb/_server.ovsschema \
$(srcdir)/ovsdb/_server.xml > $@.tmp && \
mv $@.tmp $@
6 changes: 6 additions & 0 deletions ovsdb/ovsdb-server.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ example, \fBovsdb\-tool create\fR.
This OVSDB implementation supports standalone and active-backup
databases, as well as database replication.
See the Service Models section of \fBovsdb\fR(7) for more information.
.PP
In addition to user-specified databases, \fBovsdb\-server\fR version
2.9 and later also always hosts a built-in database named
\fB_Server\fR. Please see \fBovsdb\-server\fR(5) for documentation on
this database's schema.
.
.SH OPTIONS
.
.IP "\fB\-\-remote=\fIremote\fR"
Expand Down
131 changes: 125 additions & 6 deletions ovsdb/ovsdb-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct db {
char *filename;
struct ovsdb_file *file;
struct ovsdb *db;
struct uuid row_uuid;
};

/* SSL configuration. */
Expand Down Expand Up @@ -107,6 +108,7 @@ static unixctl_cb_func ovsdb_server_remove_database;
static unixctl_cb_func ovsdb_server_list_databases;

static char *open_db(struct server_config *config, const char *filename);
static void add_server_db(struct server_config *);
static void close_db(struct db *db);

static void parse_options(int *argc, char **argvp[],
Expand All @@ -124,6 +126,7 @@ static void report_error_if_changed(char *error, char **last_errorp);
static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
const struct sset *remotes,
struct shash *all_dbs);
static void update_server_status(struct shash *all_dbs);

static void save_config__(FILE *config_file, const struct sset *remotes,
const struct sset *db_filenames,
Expand Down Expand Up @@ -214,6 +217,8 @@ main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
update_remote_status(jsonrpc, remotes, all_dbs);
}

update_server_status(all_dbs);

memory_wait();
if (*is_backup) {
replication_wait();
Expand Down Expand Up @@ -328,6 +333,7 @@ main(int argc, char *argv[])
ovs_fatal(0, "%s", error);
}
}
add_server_db(&server_config);

error = reconfigure_remotes(jsonrpc, &all_dbs, &remotes);
if (!error) {
Expand Down Expand Up @@ -490,6 +496,16 @@ close_db(struct db *db)
free(db);
}

static void
add_db(struct server_config *config, const char *name, struct db *db)
{
db->row_uuid = UUID_ZERO;
shash_add_assert(config->all_dbs, name, db);
bool ok OVS_UNUSED = ovsdb_jsonrpc_server_add_db(config->jsonrpc,
db->db);
ovs_assert(ok);
}

static char *
open_db(struct server_config *config, const char *filename)
{
Expand Down Expand Up @@ -524,6 +540,27 @@ open_db(struct server_config *config, const char *filename)
return error;
}

/* Add the internal _Server database to the server configuration. */
static void
add_server_db(struct server_config *config)
{
struct json *schema_json = json_from_string(
#include "ovsdb/_server.ovsschema.inc"
);
ovs_assert(schema_json->type == JSON_OBJECT);

struct ovsdb_schema *schema;
struct ovsdb_error *error OVS_UNUSED = ovsdb_schema_from_json(schema_json,
&schema);
ovs_assert(!error);
json_destroy(schema_json);

struct db *db = xzalloc(sizeof *db);
db->filename = xstrdup("<internal>");
db->db = ovsdb_create(schema);
add_db(config, db->db->schema->name, db);
}

static char * OVS_WARN_UNUSED_RESULT
parse_db_column__(const struct shash *all_dbs,
const char *name_, char *name,
Expand Down Expand Up @@ -887,6 +924,18 @@ update_remote_rows(const struct shash *all_dbs, const struct db *db_,
}
}

static void
commit_txn(struct ovsdb_txn *txn, const char *name)
{
struct ovsdb_error *error = ovsdb_txn_commit(txn, false);
if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
char *msg = ovsdb_error_to_string_free(error);
VLOG_ERR_RL(&rl, "Failed to update %s: %s", name, msg);
free(msg);
}
}

static void
update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
const struct sset *remotes,
Expand All @@ -903,14 +952,84 @@ update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
update_remote_rows(all_dbs, db, remote, jsonrpc, txn);
}

struct ovsdb_error *error = ovsdb_txn_commit(txn, false);
if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
char *msg = ovsdb_error_to_string_free(error);
VLOG_ERR_RL(&rl, "Failed to update remote status: %s", msg);
free(msg);
commit_txn(txn, node->name);
}
}

/* Updates 'row', a row in the _Server database's Database table, to match
* 'db'. */
static void
update_database_status(struct ovsdb_row *row, struct db *db)
{
ovsdb_util_write_string_column(row, "name", db->db->schema->name);

const struct uuid *row_uuid = ovsdb_row_get_uuid(row);
if (!uuid_equals(row_uuid, &db->row_uuid)) {
db->row_uuid = *row_uuid;

/* The schema can only change if the row UUID changes, so only update
* it in that case. Presumably, this is worth optimizing because
* schemas are often kilobytes in size and nontrivial to serialize. */
struct json *json_schema = ovsdb_schema_to_json(db->db->schema);
char *schema = json_to_string(json_schema, JSSF_SORT);
ovsdb_util_write_string_column(row, "schema", schema);
free(schema);
json_destroy(json_schema);
}
}

/* Updates the Database table in the _Server database. */
static void
update_server_status(struct shash *all_dbs)
{
struct db *server_db = shash_find_data(all_dbs, "_Server");
struct ovsdb_table *database_table = shash_find_data(
&server_db->db->tables, "Database");
struct ovsdb_txn *txn = ovsdb_txn_create(server_db->db);

/* Update rows for databases that still exist.
* Delete rows for databases that no longer exist. */
const struct ovsdb_row *row, *next_row;
HMAP_FOR_EACH_SAFE (row, next_row, hmap_node, &database_table->rows) {
const char *name;
ovsdb_util_read_string_column(row, "name", &name);
struct db *db = shash_find_data(all_dbs, name);
if (!db || !db->db) {
ovsdb_txn_row_delete(txn, row);
} else {
update_database_status(ovsdb_txn_row_modify(txn, row), db);
}
}

/* Add rows for new databases.
*
* This is O(n**2) but usually there are only 2 or 3 databases. */
struct shash_node *node;
SHASH_FOR_EACH (node, all_dbs) {
struct db *db = node->data;

if (!db->db) {
continue;
}

HMAP_FOR_EACH (row, hmap_node, &database_table->rows) {
const char *name;
ovsdb_util_read_string_column(row, "name", &name);
if (!strcmp(name, node->name)) {
goto next;
}
}

/* Add row. */
struct ovsdb_row *row = ovsdb_row_create(database_table);
uuid_generate(ovsdb_row_get_uuid_rw(row));
update_database_status(row, db);
ovsdb_txn_row_insert(txn, row);

next:;
}

commit_txn(txn, "_Server");
}

/* Reconfigures ovsdb-server's remotes based on information in the database. */
Expand Down
Loading

0 comments on commit 6bb9b06

Please sign in to comment.