summaryrefslogtreecommitdiff
path: root/ovsdb
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2015-10-15 14:07:43 -0700
committerAndy Zhou <azhou@ovn.org>2015-12-11 14:22:33 -0800
commit52553aeaa95ab46a1c120a8628621d8ed390a91f (patch)
tree1fc1d5caf92d93a036494e6379993132d0fca669 /ovsdb
parent1a6f1cefc0ecfc60f13b815d53666421e6e0b1a0 (diff)
downloadopenvswitch-52553aeaa95ab46a1c120a8628621d8ed390a91f.tar.gz
ovsdb: generate update2 notification for a monitor2 session
Add functions that can generate "update2" notification for a "monitor2" session. "monitor2" and "update2" are RFC 7047 extensions described by ovsdb-server(1) manpage. See the manpage changes for more details. Signed-off-by: Andy Zhou <azhou@nicira.com> Acked-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ovsdb')
-rw-r--r--ovsdb/jsonrpc-server.c4
-rw-r--r--ovsdb/monitor.c145
-rw-r--r--ovsdb/monitor.h13
-rw-r--r--ovsdb/ovsdb-server.1.in84
4 files changed, 219 insertions, 27 deletions
diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index fffcb731d..729b36819 100644
--- a/ovsdb/jsonrpc-server.c
+++ b/ovsdb/jsonrpc-server.c
@@ -22,6 +22,7 @@
#include "bitmap.h"
#include "column.h"
#include "dynamic-string.h"
+#include "monitor.h"
#include "json.h"
#include "jsonrpc.h"
#include "ovsdb-error.h"
@@ -1294,7 +1295,8 @@ static struct json *
ovsdb_jsonrpc_monitor_compose_update(struct ovsdb_jsonrpc_monitor *m,
bool initial)
{
- return ovsdb_monitor_get_update(m->dbmon, initial, &m->unflushed);
+ return ovsdb_monitor_get_update(m->dbmon, initial, &m->unflushed,
+ OVSDB_MONITOR_V1);
}
static bool
diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c
index daf69cd42..f08607aa3 100644
--- a/ovsdb/monitor.c
+++ b/ovsdb/monitor.c
@@ -119,6 +119,11 @@ struct ovsdb_monitor_table {
struct hmap changes;
};
+typedef struct json *
+(*compose_row_update_cb_func)(const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_row *row,
+ bool initial, unsigned long int *changed);
+
static void ovsdb_monitor_destroy(struct ovsdb_monitor *dbmon);
static struct ovsdb_monitor_changes * ovsdb_monitor_table_add_changes(
struct ovsdb_monitor_table *mt, uint64_t next_txn);
@@ -464,6 +469,37 @@ ovsdb_monitor_row_update_type(bool initial, const bool old, const bool new)
: !new ? OJMS_DELETE
: OJMS_MODIFY;
}
+static bool
+ovsdb_monitor_row_skip_update(const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_row *row,
+ enum ovsdb_monitor_selection type,
+ unsigned long int *changed)
+{
+ if (!(mt->select & type)) {
+ return true;
+ }
+
+ if (type == OJMS_MODIFY) {
+ size_t i, n_changes;
+
+ n_changes = 0;
+ memset(changed, 0, bitmap_n_bytes(mt->n_columns));
+ for (i = 0; i < mt->n_columns; i++) {
+ const struct ovsdb_column *c = mt->columns[i].column;
+ if (!ovsdb_datum_equals(&row->old[i], &row->new[i], &c->type)) {
+ bitmap_set1(changed, i);
+ n_changes++;
+ }
+ }
+ if (!n_changes) {
+ /* No actual changes: presumably a row changed and then
+ * changed back later. */
+ return true;
+ }
+ }
+
+ return false;
+}
/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
* 'mt', or NULL if no row update should be sent.
@@ -486,29 +522,10 @@ ovsdb_monitor_compose_row_update(
size_t i;
type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
- if (!(mt->select & type)) {
+ if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) {
return NULL;
}
- if (type == OJMS_MODIFY) {
- size_t n_changes;
-
- n_changes = 0;
- memset(changed, 0, bitmap_n_bytes(mt->n_columns));
- for (i = 0; i < mt->n_columns; i++) {
- const struct ovsdb_column *c = mt->columns[i].column;
- if (!ovsdb_datum_equals(&row->old[i], &row->new[i], &c->type)) {
- bitmap_set1(changed, i);
- n_changes++;
- }
- }
- if (!n_changes) {
- /* No actual changes: presumably a row changed and then
- * changed back later. */
- return NULL;
- }
- }
-
row_json = json_object_create();
old_json = new_json = NULL;
if (type & (OJMS_DELETE | OJMS_MODIFY)) {
@@ -545,6 +562,76 @@ ovsdb_monitor_compose_row_update(
return row_json;
}
+/* Returns JSON for a <row-update2> (as described in ovsdb-server(1) mapage)
+ * for 'row' within * 'mt', or NULL if no row update should be sent.
+ *
+ * The caller should specify 'initial' as true if the returned JSON is
+ * going to be used as part of the initial reply to a "monitor2" request,
+ * false if it is going to be used as part of an "update2" notification.
+ *
+ * 'changed' must be a scratch buffer for internal use that is at least
+ * bitmap_n_bytes(mt->n_columns) bytes long. */
+static struct json *
+ovsdb_monitor_compose_row_update2(
+ const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_row *row,
+ bool initial, unsigned long int *changed)
+{
+ enum ovsdb_monitor_selection type;
+ struct json *row_update2, *diff_json;
+ size_t i;
+
+ type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
+ if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) {
+ return NULL;
+ }
+
+ row_update2 = json_object_create();
+ if (type == OJMS_DELETE) {
+ json_object_put(row_update2, "delete", json_null_create());
+ } else {
+ diff_json = json_object_create();
+ const char *op;
+
+ for (i = 0; i < mt->n_columns; i++) {
+ const struct ovsdb_monitor_column *c = &mt->columns[i];
+
+ if (!(type & c->select)) {
+ /* We don't care about this type of change for this
+ * particular column (but we will care about it for some
+ * other column). */
+ continue;
+ }
+
+ if (type == OJMS_MODIFY) {
+ struct ovsdb_datum diff;
+
+ if (!bitmap_is_set(changed, i)) {
+ continue;
+ }
+
+ ovsdb_datum_diff(&diff ,&row->old[i], &row->new[i],
+ &c->column->type);
+ json_object_put(diff_json, c->column->name,
+ ovsdb_datum_to_json(&diff, &c->column->type));
+ ovsdb_datum_destroy(&diff, &c->column->type);
+ } else {
+ if (!ovsdb_datum_is_default(&row->new[i], &c->column->type)) {
+ json_object_put(diff_json, c->column->name,
+ ovsdb_datum_to_json(&row->new[i],
+ &c->column->type));
+ }
+ }
+ }
+
+ op = type == OJMS_INITIAL ? "initial"
+ : type == OJMS_MODIFY ? "modify" : "insert";
+ json_object_put(row_update2, op, diff_json);
+ }
+
+ return row_update2;
+}
+
static size_t
ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon)
{
@@ -565,7 +652,8 @@ ovsdb_monitor_max_columns(struct ovsdb_monitor *dbmon)
* 'transaction'. */
static struct json*
ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon,
- bool initial, uint64_t transaction)
+ bool initial, uint64_t transaction,
+ compose_row_update_cb_func row_update)
{
struct shash_node *node;
struct json *json;
@@ -587,8 +675,7 @@ ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon,
HMAP_FOR_EACH_SAFE (row, next, hmap_node, &changes->rows) {
struct json *row_json;
- row_json = ovsdb_monitor_compose_row_update(
- mt, row, initial, changed);
+ row_json = (*row_update)(mt, row, initial, changed);
if (row_json) {
char uuid[UUID_LEN + 1];
@@ -623,7 +710,8 @@ ovsdb_monitor_compose_update(struct ovsdb_monitor *dbmon,
* going to be used as part of an "update" notification. */
struct json *
ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
- bool initial, uint64_t *unflushed)
+ bool initial, uint64_t *unflushed,
+ enum ovsdb_monitor_version version)
{
struct ovsdb_monitor_json_cache_node *cache_node;
struct shash_node *node;
@@ -637,7 +725,14 @@ ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
if (cache_node) {
json = cache_node->json ? json_clone(cache_node->json) : NULL;
} else {
- json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn);
+ if (version == OVSDB_MONITOR_V1) {
+ json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
+ ovsdb_monitor_compose_row_update);
+ } else {
+ ovs_assert(version == OVSDB_MONITOR_V2);
+ json = ovsdb_monitor_compose_update(dbmon, initial, prev_txn,
+ ovsdb_monitor_compose_row_update2);
+ }
ovsdb_monitor_json_cache_insert(dbmon, prev_txn, json);
}
diff --git a/ovsdb/monitor.h b/ovsdb/monitor.h
index a8e531012..b1a5146b6 100644
--- a/ovsdb/monitor.h
+++ b/ovsdb/monitor.h
@@ -27,6 +27,15 @@ enum ovsdb_monitor_selection {
};
+enum ovsdb_monitor_version {
+ OVSDB_MONITOR_V1, /* RFC 7047 "monitor" method. */
+ OVSDB_MONITOR_V2, /* Extension to RFC 7047, see ovsdb-server
+ man page for details. */
+
+ /* Last entry. */
+ OVSDB_MONITOR_VERSION_MAX
+};
+
struct ovsdb_monitor *ovsdb_monitor_create(struct ovsdb *db,
struct ovsdb_jsonrpc_monitor *jsonrpc_monitor);
@@ -55,7 +64,9 @@ ovsdb_monitor_table_check_duplicates(struct ovsdb_monitor *,
const struct ovsdb_table *);
struct json *ovsdb_monitor_get_update(struct ovsdb_monitor *dbmon,
- bool initial, uint64_t *unflushed_transaction);
+ bool initial,
+ uint64_t *unflushed_transaction,
+ enum ovsdb_monitor_version version);
void ovsdb_monitor_table_add_select(struct ovsdb_monitor *dbmon,
const struct ovsdb_table *table,
diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in
index e340993f7..6c857294c 100644
--- a/ovsdb/ovsdb-server.1.in
+++ b/ovsdb/ovsdb-server.1.in
@@ -245,6 +245,90 @@ notifications (see below) to the request, it must be unique among all
active monitors. \fBovsdb\-server\fR rejects attempt to create two
monitors with the same identifier.
.
+.IP "4.1.12. Monitor2"
+A new monitor method added in Open vSwitch version 2.5. Monitor2 allows
+for more efficient update notifications (described below).
+.IP
+The monitor method described in Section 4.1.5 also applies to
+monitor2, with the following exceptions.
+.
+.RS
+.IP \(bu
+RPC request method becomes "monitor2".
+.IP \(bu
+Replay result follows <table-updates2>, described in Section 4.1.13.
+.IP \(bu
+Subsequent changes are sent to the client using the "update2" monitor
+notification, described in Section 4.1.13
+.RE
+.
+.IP
+Both monitor and monitor2 sessions can exist concurrently. However,
+monitor and monitor2 shares the same <json-value> parameter space; it
+must be unique among all monitor and monitor2 sessions.
+.
+.IP "4.1.13. Update2 notification"
+The "update2" notification is sent by the server to the client to report
+changes in tables that are being monitored following a "monitor2" request
+as described above. The notification has the following members:
+.
+.RS
+.nf
+"method": "update2"
+"params": [<json-value>, <table-updates2>]
+"id": null
+.fi
+.RE
+.
+.IP
+The <json-value> in "params" is the same as the value passed as the
+<json-value> in "params" for the corresponding "monitor" request.
+<table-updates2> is an object that maps from a table name to a <table-update2>.
+A <table-update2> is an object that maps from row's UUID to a <row-update2> object. A <row-update2> is an object with one of the following members:
+.
+.RS
+.IP "\(dqinitial\(dq: <row>"
+present for "initial" updates
+.IP "\(dqinsert\(dq: <row>"
+present for "insert" updates
+.IP "\(dqdelete\(dq: <row>"
+present for "delete" updates
+.IP "\(dqmodify\(dq: <row>"
+present for "modify" updates
+.RE
+.
+.IP
+The format of <row> is described in Section 5.1.
+.
+.IP
+<row> is always a null object for a "delete" update. In "initial" and
+"insert" updates, <row> omits columns whose values equal the default
+value of the column type.
+.
+.IP
+For a "modify" update, <row> contains only the columns that are modified.
+<row> stores the difference between the old and new value for those columns,
+as described below.
+.
+.IP
+For columns with single value, the difference is the value of the new
+column.
+.
+.IP
+The difference between two sets are all elements that only belong
+to one of the sets.
+.
+.IP
+The difference between two maps are all key-value pairs whose keys
+appears in only one of the maps, plus the key-value pairs whose keys
+appear in both maps but with different values. For the latter
+elements, <row> includes the value from the new column.
+.
+.IP
+Initial views of rows are not presented in update2 notifications,
+but in the response object to the monitor2 request. The formatting of the
+<table-updates2> object, however, is the same in either case.
+.
.IP "5.1. Notation"
For <condition>, RFC 7047 only allows the use of \fB!=\fR, \fB==\fR,
\fBincludes\fR, and \fBexcludes\fR operators with set types. Open