[ovs-dev] [PATCH monitor_cond V9 10/12] lib: add monitor_cond_change API to C IDL lib

Liran Schour lirans at il.ibm.com
Mon Jul 18 08:45:58 UTC 2016


Add to IDL API that allows the user to add and remove clauses on a table's condition
iteratively. IDL maintain tables condition and send monitor_cond_change to the server
upon condition change.
Add tests for conditional monitoring to IDL.

Signed-off-by: Liran Schour <lirans at il.ibm.com>
---
 lib/automake.mk          |   2 +
 lib/ovsdb-condition.c    |  47 ++++++
 lib/ovsdb-condition.h    |  45 ++++++
 lib/ovsdb-idl-provider.h |   2 +
 lib/ovsdb-idl.c          | 205 +++++++++++++++++++++++++-
 lib/ovsdb-idl.h          |  29 ++++
 ovsdb/condition.h        |  28 +---
 ovsdb/ovsdb-idlc.in      | 364 ++++++++++++++++++++++++++++++++++++++++++++++-
 python/ovs/db/idl.py     |  30 +++-
 tests/ovsdb-idl.at       | 136 ++++++++++++++++++
 tests/test-ovsdb.c       | 214 +++++++++++++++++++++++++++-
 tests/test-ovsdb.py      |  34 +++++
 12 files changed, 1098 insertions(+), 38 deletions(-)
 create mode 100644 lib/ovsdb-condition.c
 create mode 100644 lib/ovsdb-condition.h

diff --git a/lib/automake.mk b/lib/automake.mk
index 4d4ee01..1a44cc0 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -181,6 +181,8 @@ lib_libopenvswitch_la_SOURCES = \
 	lib/ovsdb-idl.h \
 	lib/ovsdb-map-op.c \
 	lib/ovsdb-map-op.h \
+	lib/ovsdb-condition.h \
+	lib/ovsdb-condition.c \
 	lib/ovsdb-parser.c \
 	lib/ovsdb-parser.h \
 	lib/ovsdb-types.c \
diff --git a/lib/ovsdb-condition.c b/lib/ovsdb-condition.c
new file mode 100644
index 0000000..e0c4e43
--- /dev/null
+++ b/lib/ovsdb-condition.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include "ovsdb-error.h"
+#include "ovsdb-condition.h"
+
+struct ovsdb_error *
+ovsdb_function_from_string(const char *name, enum ovsdb_function *function)
+{
+#define OVSDB_FUNCTION(ENUM, NAME)              \
+    if (!strcmp(name, NAME)) {                  \
+        *function = ENUM;                       \
+        return NULL;                            \
+    }
+    OVSDB_FUNCTIONS;
+#undef OVSDB_FUNCTION
+
+    return ovsdb_syntax_error(NULL, "unknown function",
+                              "No function named %s.", name);
+}
+
+const char *
+ovsdb_function_to_string(enum ovsdb_function function)
+{
+    switch (function) {
+#define OVSDB_FUNCTION(ENUM, NAME) case ENUM: return NAME;
+        OVSDB_FUNCTIONS;
+#undef OVSDB_FUNCTION
+    }
+
+    return NULL;
+}
diff --git a/lib/ovsdb-condition.h b/lib/ovsdb-condition.h
new file mode 100644
index 0000000..65496e1
--- /dev/null
+++ b/lib/ovsdb-condition.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVSDB_LIB_CONDITION_H
+#define OVSDB_LIB_CONDITION_H 1
+
+/* These list is ordered first with boolean functions and then in
+ * ascending order of the fraction of tables row that they are
+ * (heuristically) expected to leave in query results. */
+#define OVSDB_FUNCTIONS                         \
+    OVSDB_FUNCTION(OVSDB_F_FALSE, "false")            \
+    OVSDB_FUNCTION(OVSDB_F_TRUE, "true")              \
+    OVSDB_FUNCTION(OVSDB_F_EQ, "==")                  \
+    OVSDB_FUNCTION(OVSDB_F_INCLUDES, "includes")      \
+    OVSDB_FUNCTION(OVSDB_F_LE, "<=")                  \
+    OVSDB_FUNCTION(OVSDB_F_LT, "<")                   \
+    OVSDB_FUNCTION(OVSDB_F_GE, ">=")                  \
+    OVSDB_FUNCTION(OVSDB_F_GT, ">")                   \
+    OVSDB_FUNCTION(OVSDB_F_EXCLUDES, "excludes")      \
+    OVSDB_FUNCTION(OVSDB_F_NE, "!=")
+
+enum ovsdb_function {
+#define OVSDB_FUNCTION(ENUM, NAME) ENUM,
+    OVSDB_FUNCTIONS
+#undef OVSDB_FUNCTION
+    OVSDB_F_LAST = OVSDB_F_NE
+};
+
+struct ovsdb_error * ovsdb_function_from_string(const char *name,
+                                                enum ovsdb_function *function);
+const char * ovsdb_function_to_string(enum ovsdb_function function);
+
+#endif /* ovsdb-condition.h */
diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
index 04cf419..1f249c0 100644
--- a/lib/ovsdb-idl-provider.h
+++ b/lib/ovsdb-idl-provider.h
@@ -73,6 +73,8 @@ struct ovsdb_idl_table {
     struct ovsdb_idl *idl;   /* Containing idl. */
     unsigned int change_seqno[OVSDB_IDL_CHANGE_MAX];
     struct ovs_list track_list; /* Tracked rows (ovsdb_idl_row.track_node). */
+    struct ovsdb_idl_condition condition;
+    bool cond_changed;
 };
 
 struct ovsdb_idl_class {
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 0e7cdc5..f8e980b 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -108,6 +108,7 @@ struct ovsdb_idl {
     /* Transaction support. */
     struct ovsdb_idl_txn *txn;
     struct hmap outstanding_txns;
+    bool cond_changed;
 };
 
 struct ovsdb_idl_txn {
@@ -211,6 +212,9 @@ static struct ovsdb_idl_table *
 ovsdb_idl_table_from_class(const struct ovsdb_idl *,
                            const struct ovsdb_idl_table_class *);
 static bool ovsdb_idl_track_is_set(struct ovsdb_idl_table *table);
+static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl);
+static void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
+                                     const struct ovsdb_idl_table_class *tc);
 
 /* Creates and returns a connection to database 'remote', which should be in a
  * form acceptable to jsonrpc_session_open().  The connection will maintain an
@@ -269,8 +273,11 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
             = table->change_seqno[OVSDB_IDL_CHANGE_MODIFY]
             = table->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0;
         table->idl = idl;
+        ovsdb_idl_condition_init(&table->condition, tc);
+        table->cond_changed = false;
     }
 
+    idl->cond_changed = false;
     idl->state_seqno = UINT_MAX;
     idl->request_id = NULL;
     idl->schema = NULL;
@@ -373,6 +380,9 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
     int i;
 
     ovs_assert(!idl->txn);
+
+    ovsdb_idl_send_cond_change(idl);
+
     jsonrpc_session_run(idl->session);
     for (i = 0; jsonrpc_session_is_connected(idl->session) && i < 50; i++) {
         struct jsonrpc_msg *msg;
@@ -700,6 +710,190 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
     OVS_NOT_REACHED();
 }
 
+static struct json *
+ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
+{
+    if (clause->function != OVSDB_F_TRUE &&
+        clause->function != OVSDB_F_FALSE) {
+        const char *function = ovsdb_function_to_string(clause->function);
+
+        return json_array_create_3(json_string_create(clause->column->name),
+                                   json_string_create(function),
+                                   ovsdb_datum_to_json(&clause->arg,
+                                                       &clause->column->type));
+    }
+
+    return json_boolean_create(clause->function == OVSDB_F_TRUE ?
+                               true : false);
+}
+
+static void
+ovsdb_idl_clause_free(struct ovsdb_idl_clause *clause)
+{
+    if (clause->function != OVSDB_F_TRUE &&
+        clause->function != OVSDB_F_FALSE) {
+        ovsdb_datum_destroy(&clause->arg, &clause->column->type);
+    }
+
+    ovs_list_remove(&clause->node);
+    free(clause);
+}
+
+void
+ovsdb_idl_condition_reset(struct ovsdb_idl *idl,
+                          const struct ovsdb_idl_table_class *tc)
+{
+    struct ovsdb_idl_clause *c, *next;
+    struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
+
+    LIST_FOR_EACH_SAFE (c, next, node, &table->condition.clauses) {
+        ovs_list_remove(&c->node);
+        ovsdb_idl_clause_free(c);
+    }
+    idl->cond_changed = table->cond_changed = true;
+}
+
+static void
+ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
+                         const struct ovsdb_idl_table_class *tc)
+{
+    cnd->tc = tc;
+    ovs_list_init(&cnd->clauses);
+}
+
+void ovsdb_idl_condition_add_clause(struct ovsdb_idl *idl,
+                                    const struct ovsdb_idl_table_class *tc,
+                                    enum ovsdb_function function,
+                                    const struct ovsdb_idl_column *column,
+                                    struct ovsdb_datum *arg)
+{
+    struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
+    struct ovsdb_idl_clause *clause = xzalloc(sizeof *clause);
+    const struct ovsdb_type *type = NULL;
+    struct ovsdb_idl_clause *c;
+
+    LIST_FOR_EACH(c, node, &table->condition.clauses) {
+        if (c->function == function &&
+            (!column || (c->column == column &&
+                         ovsdb_datum_equals(&c->arg,
+                                             arg, &column->type)))) {
+            return;
+        }
+    }
+
+    ovs_list_init(&clause->node);
+    clause->function = function;
+    clause->column = column;
+    if (column) {
+        type = &column->type;
+    } else {
+        type = &ovsdb_type_boolean;
+    }
+    ovsdb_datum_clone(&clause->arg, arg, type);
+    ovs_list_push_back(&table->condition.clauses, &clause->node);
+    idl->cond_changed = table->cond_changed = true;
+    poll_immediate_wake();
+}
+
+void ovsdb_idl_condition_remove_clause(struct ovsdb_idl *idl,
+                                       const struct ovsdb_idl_table_class *tc,
+                                       enum ovsdb_function function,
+                                       const struct ovsdb_idl_column *column,
+                                       struct ovsdb_datum *arg)
+{
+    struct ovsdb_idl_clause *c, *next;
+    struct ovsdb_idl_table *table = ovsdb_idl_table_from_class(idl, tc);
+
+    LIST_FOR_EACH_SAFE(c, next, node, &table->condition.clauses) {
+        if (c->function == function &&
+            (!column || (c->column == column &&
+                         ovsdb_datum_equals(&c->arg,
+                                             arg, &column->type)))) {
+            ovsdb_idl_clause_free(c);
+            idl->cond_changed = table->cond_changed = true;
+            return;
+        }
+    }
+}
+
+static struct json *
+ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
+{
+    struct json **clauses;
+    size_t i = 0, n_clauses = ovs_list_size(&cnd->clauses);
+    struct ovsdb_idl_clause *c;
+
+    clauses = xmalloc(n_clauses * sizeof *clauses);
+    LIST_FOR_EACH (c, node, &cnd->clauses) {
+           clauses[i++] = ovsdb_idl_clause_to_json(c);
+    }
+
+    return json_array_create(clauses, n_clauses);
+}
+
+static struct json*
+ovsdb_idl_create_cond_change_req(struct ovsdb_idl_table *table)
+{
+    const struct ovsdb_idl_condition *cond = &table->condition;
+    struct json *monitor_cond_change_request = json_object_create();
+    struct json *cond_json = ovsdb_idl_condition_to_json(cond);
+
+    json_object_put(monitor_cond_change_request, "where", cond_json);
+
+    return monitor_cond_change_request;
+}
+
+static void
+ovsdb_idl_send_cond_change(struct ovsdb_idl *idl)
+{
+    int i;
+    char uuid[UUID_LEN + 1];
+    struct json *params, *json_uuid;
+    struct jsonrpc_msg *request;
+
+    if (!idl->cond_changed || !jsonrpc_session_is_connected(idl->session) ||
+        idl->state != IDL_S_MONITORING_COND) {
+        return;
+    }
+
+    struct json *monitor_cond_change_requests = NULL;
+
+    for (i = 0; i < idl->class->n_tables; i++) {
+        struct ovsdb_idl_table *table = &idl->tables[i];
+
+        if (table->cond_changed) {
+            struct json *req = ovsdb_idl_create_cond_change_req(table);
+            if (req) {
+                if (!monitor_cond_change_requests) {
+                    monitor_cond_change_requests = json_object_create();
+                }
+                json_object_put(monitor_cond_change_requests,
+                             table->class->name,
+                             json_array_create_1(req));
+            }
+            table->cond_changed = false;
+        }
+    }
+
+    /* Send request if not empty. */
+    if (monitor_cond_change_requests) {
+        snprintf(uuid, sizeof uuid, UUID_FMT,
+                 UUID_ARGS(&idl->uuid));
+        json_uuid = json_string_create(uuid);
+
+        /* Create a new uuid */
+        uuid_generate(&idl->uuid);
+        snprintf(uuid, sizeof uuid, UUID_FMT,
+                 UUID_ARGS(&idl->uuid));
+        params = json_array_create_3(json_uuid, json_string_create(uuid),
+                                     monitor_cond_change_requests);
+
+        request = jsonrpc_create_request("monitor_cond_change", params, NULL);
+        jsonrpc_session_send(idl->session, request);
+    }
+    idl->cond_changed = false;
+}
+
 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
  *
  * This function should be called between ovsdb_idl_create() and the first call
@@ -997,9 +1191,9 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
     schema = parse_schema(idl->schema);
     monitor_requests = json_object_create();
     for (i = 0; i < idl->class->n_tables; i++) {
-        const struct ovsdb_idl_table *table = &idl->tables[i];
+        struct ovsdb_idl_table *table = &idl->tables[i];
         const struct ovsdb_idl_table_class *tc = table->class;
-        struct json *monitor_request, *columns;
+        struct json *monitor_request, *columns, *where;
         const struct sset *table_schema;
         size_t j;
 
@@ -1037,6 +1231,12 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
 
             monitor_request = json_object_create();
             json_object_put(monitor_request, "columns", columns);
+            if (!strcmp(method, "monitor_cond") && table->cond_changed &&
+                ovs_list_size(&table->condition.clauses) > 0) {
+                where = ovsdb_idl_condition_to_json(&table->condition);
+                json_object_put(monitor_request, "where", where);
+                table->cond_changed = false;
+            }
             json_object_put(monitor_requests, tc->name, monitor_request);
         }
     }
@@ -1051,6 +1251,7 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
                             json_string_create(uuid), monitor_requests),
         &idl->request_id);
     jsonrpc_session_send(idl->session, msg);
+    idl->cond_changed = false;
 }
 
 static void
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index 70449fa..c08e31b 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -38,6 +38,9 @@
 #include <stdint.h>
 #include "compiler.h"
 #include "ovsdb-types.h"
+#include "ovsdb-data.h"
+#include "openvswitch/list.h"
+#include "ovsdb-condition.h"
 
 struct json;
 struct ovsdb_datum;
@@ -45,6 +48,7 @@ struct ovsdb_idl_class;
 struct ovsdb_idl_row;
 struct ovsdb_idl_column;
 struct ovsdb_idl_table_class;
+struct ovsdb_idl_condition;
 struct uuid;
 
 struct ovsdb_idl *ovsdb_idl_create(const char *remote,
@@ -299,4 +303,29 @@ void ovsdb_idl_loop_destroy(struct ovsdb_idl_loop *);
 struct ovsdb_idl_txn *ovsdb_idl_loop_run(struct ovsdb_idl_loop *);
 void ovsdb_idl_loop_commit_and_wait(struct ovsdb_idl_loop *);
 
+struct ovsdb_idl_condition {
+    const struct ovsdb_idl_table_class *tc;
+    struct ovs_list clauses;
+};
+
+struct ovsdb_idl_clause {
+    struct ovs_list node;
+    enum ovsdb_function function;
+    const struct ovsdb_idl_column *column;
+    struct ovsdb_datum arg;
+};
+
+void ovsdb_idl_condition_reset(struct ovsdb_idl *idl,
+                               const struct ovsdb_idl_table_class *tc);
+void ovsdb_idl_condition_add_clause(struct ovsdb_idl *idl,
+                                    const struct ovsdb_idl_table_class *tc,
+                                    enum ovsdb_function function,
+                                    const struct ovsdb_idl_column *column,
+                                    struct ovsdb_datum *arg);
+void ovsdb_idl_condition_remove_clause(struct ovsdb_idl *idl,
+                                       const struct ovsdb_idl_table_class *tc,
+                                       enum ovsdb_function function,
+                                       const struct ovsdb_idl_column *column,
+                                       struct ovsdb_datum *arg);
+
 #endif /* ovsdb-idl.h */
diff --git a/ovsdb/condition.h b/ovsdb/condition.h
index 2ddc811..c794966 100644
--- a/ovsdb/condition.h
+++ b/ovsdb/condition.h
@@ -20,38 +20,12 @@
 #include "compiler.h"
 #include "ovsdb-data.h"
 #include "bitmap.h"
+#include "ovsdb-condition.h"
 
 struct json;
 struct ovsdb_table_schema;
 struct ovsdb_row;
 
-/* These list is ordered first with boolean functions and then in
- * ascending order of the fraction of tables row that they are
- * (heuristically) expected to leave in query results. */
-#define OVSDB_FUNCTIONS                         \
-    OVSDB_FUNCTION(OVSDB_F_FALSE, "false")            \
-    OVSDB_FUNCTION(OVSDB_F_TRUE, "true")              \
-    OVSDB_FUNCTION(OVSDB_F_EQ, "==")                  \
-    OVSDB_FUNCTION(OVSDB_F_INCLUDES, "includes")      \
-    OVSDB_FUNCTION(OVSDB_F_LE, "<=")                  \
-    OVSDB_FUNCTION(OVSDB_F_LT, "<")                   \
-    OVSDB_FUNCTION(OVSDB_F_GE, ">=")                  \
-    OVSDB_FUNCTION(OVSDB_F_GT, ">")                   \
-    OVSDB_FUNCTION(OVSDB_F_EXCLUDES, "excludes")      \
-    OVSDB_FUNCTION(OVSDB_F_NE, "!=")
-
-enum ovsdb_function {
-#define OVSDB_FUNCTION(ENUM, NAME) ENUM,
-    OVSDB_FUNCTIONS
-#undef OVSDB_FUNCTION
-    OVSDB_F_LAST = OVSDB_F_NE
-};
-
-struct ovsdb_error *ovsdb_function_from_string(const char *,
-                                               enum ovsdb_function *)
-    OVS_WARN_UNUSED_RESULT;
-const char *ovsdb_function_to_string(enum ovsdb_function);
-
 struct ovsdb_clause {
     enum ovsdb_function function;
     const struct ovsdb_column *column;
diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index 0d836c0..253344e 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -229,11 +229,38 @@ bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
 
         print
         for columnName, column in sorted(table.columns.iteritems()):
-             if column.type.is_map():
+            if column.type.is_map():
                 print 'void %(s)s_update_%(c)s_setkey(const struct %(s)s *, ' % {'s': structName, 'c': columnName},
                 print '%(coltype)s, %(valtype)s);' % {'coltype':column.type.key.toCType(prefix), 'valtype':column.type.value.toCType(prefix)}
                 print 'void %(s)s_update_%(c)s_delkey(const struct %(s)s *, ' % {'s': structName, 'c': columnName},
-                print '%(coltype)s);' % {'coltype':column.type.key.toCType(prefix)}
+                print '%(coltype)s);' % {'coltype':column.type.key.toCType(prefix)},
+
+            print 'void %(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function,' % {'s': structName, 'c': columnName},
+            if column.type.is_smap():
+                args = ['const struct smap *']
+            else:
+                comment, members = cMembers(prefix, tableName, columnName,
+                                            column, True)
+                args = ['%(type)s%(name)s' % member for member in members]
+            print '%s);' % ', '.join(args)
+
+        print 'void %s_add_clause_true(struct ovsdb_idl *idl);' % structName
+        print 'void %s_add_clause_false(struct ovsdb_idl *idl);' % structName
+
+        print
+        for columnName, column in sorted(table.columns.iteritems()):
+            print 'void %(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function,' % {'s': structName, 'c': columnName},
+            if column.type.is_smap():
+                args = ['const struct smap *']
+            else:
+                comment, members = cMembers(prefix, tableName, columnName,
+                                            column, True)
+                args = ['%(type)s%(name)s' % member for member in members]
+            print '%s);' % ', '.join(args)
+
+        print 'void %s_remove_clause_true(struct ovsdb_idl *idl);' % structName
+        print 'void %s_remove_clause_false(struct ovsdb_idl *idl);' % structName
+
         print
 
     # Table indexes.
@@ -828,6 +855,339 @@ void
         'C': columnName.upper()}
         # End Update/Delete of partial maps
 
+        # Add clause functions.
+        for columnName, column in sorted(table.columns.iteritems()):
+            type = column.type
+
+            comment, members = cMembers(prefix, tableName, columnName,
+                                        column, True)
+
+            if type.is_smap():
+                print comment
+                print """void
+%(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, const struct smap *%(c)s)
+{
+    struct ovsdb_datum datum;
+
+    ovs_assert(inited);
+    if (%(c)s) {
+        struct smap_node *node;
+        size_t i;
+
+        datum.n = smap_count(%(c)s);
+        datum.keys = xmalloc(datum.n * sizeof *datum.keys);
+        datum.values = xmalloc(datum.n * sizeof *datum.values);
+
+        i = 0;
+        SMAP_FOR_EACH (node, %(c)s) {
+            datum.keys[i].string = xstrdup(node->key);
+            datum.values[i].string = xstrdup(node->value);
+            i++;
+        }
+        ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
+    } else {
+        ovsdb_datum_init_empty(&datum);
+    }
+
+    ovsdb_idl_condition_add_clause(idl,
+                                   &%(p)stable_classes[%(P)sTABLE_%(T)s],
+                                   function,
+                                   &%(s)s_columns[%(S)s_COL_%(C)s],
+                                   &datum);
+}
+""" % {'t': tableName,
+       'T': tableName.upper(),
+       'p': prefix,
+       'P': prefix.upper(),
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper()}
+                continue
+
+            keyVar = members[0]['name']
+            nVar = None
+            valueVar = None
+            if type.value:
+                valueVar = members[1]['name']
+                if len(members) > 2:
+                    nVar = members[2]['name']
+            else:
+                if len(members) > 1:
+                    nVar = members[1]['name']
+
+            print comment
+            print 'void'
+            print '%(s)s_add_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, %(args)s)' % \
+                {'s': structName, 'c': columnName,
+                 'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
+            print "{"
+            print "    struct ovsdb_datum datum;"
+            if type.n_min == 1 and type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                if type.value:
+                    print "    union ovsdb_atom value;"
+                print
+                print "    ovs_assert(inited);"
+                print "    datum.n = 1;"
+                print "    datum.keys = &key;"
+                print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
+                if type.value:
+                    print "    datum.values = &value;"
+                    print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
+                else:
+                    print "    datum.values = NULL;"
+            elif type.is_optional_pointer():
+                print "    union ovsdb_atom key;"
+                print
+                print "    ovs_assert(inited);"
+                print "    if (%s) {" % keyVar
+                print "        datum.n = 1;"
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
+                print "    } else {"
+                print "        datum.n = 0;"
+                print "        datum.keys = NULL;"
+                print "    }"
+                print "    datum.values = NULL;"
+            elif type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                print
+                print "    ovs_assert(inited);"
+                print "    if (%s) {" % nVar
+                print "        datum.n = 1;"
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
+                print "    } else {"
+                print "        datum.n = 0;"
+                print "        datum.keys = NULL;"
+                print "    }"
+                print "    datum.values = NULL;"
+            else:
+                print "    size_t i;"
+                print
+                print "    ovs_assert(inited);"
+                print "    datum.n = %s;" % nVar
+                print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
+                if type.value:
+                    print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
+                else:
+                    print "    datum.values = NULL;"
+                print "    for (i = 0; i < %s; i++) {" % nVar
+                print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
+                if type.value:
+                    print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
+                print "    }"
+                if type.value:
+                    valueType = type.value.toAtomicType()
+                else:
+                    valueType = "OVSDB_TYPE_VOID"
+                print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
+                    type.key.toAtomicType(), valueType)
+
+            print"""    ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
+                          function,
+                          &%(s)s_columns[%(S)s_COL_%(C)s],
+                          &datum);
+}""" % {'t': tableName,
+       'T': tableName.upper(),
+       'p': prefix,
+       'P': prefix.upper(),
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper()}
+
+        print """void
+%(s)s_add_clause_false(struct ovsdb_idl *idl)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_FALSE, NULL, &datum);
+}""" % {'s': structName,
+        'T': tableName.upper(),
+        'p': prefix,
+        'P': prefix.upper()}
+
+        print """void
+%(s)s_add_clause_true(struct ovsdb_idl *idl)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_add_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_TRUE, NULL, &datum);
+}""" % {'s': structName,
+        'T': tableName.upper(),
+        'p': prefix,
+        'P': prefix.upper()}
+
+        # Remove clause functions.
+        for columnName, column in sorted(table.columns.iteritems()):
+            type = column.type
+
+            comment, members = cMembers(prefix, tableName, columnName,
+                                        column, True)
+
+            if type.is_smap():
+                print comment
+                print """void
+%(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, const struct smap *%(c)s)
+{
+    struct ovsdb_datum datum;
+
+    ovs_assert(inited);
+    if (%(c)s) {
+        struct smap_node *node;
+        size_t i;
+
+        datum.n = smap_count(%(c)s);
+        datum.keys = xmalloc(datum.n * sizeof *datum.keys);
+        datum.values = xmalloc(datum.n * sizeof *datum.values);
+
+        i = 0;
+        SMAP_FOR_EACH (node, %(c)s) {
+            datum.keys[i].string = xstrdup(node->key);
+            datum.values[i].string = xstrdup(node->value);
+            i++;
+        }
+        ovsdb_datum_sort_unique(&datum, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
+    } else {
+        ovsdb_datum_init_empty(&datum);
+    }
+
+    ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
+                                      function,
+                                      &%(s)s_columns[%(S)s_COL_%(C)s],
+                                      &datum);
+}
+""" % {'t': tableName,
+       'T': tableName.upper(),
+       'p': prefix,
+       'P': prefix.upper(),
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper()}
+                continue
+
+            keyVar = members[0]['name']
+            nVar = None
+            valueVar = None
+            if type.value:
+                valueVar = members[1]['name']
+                if len(members) > 2:
+                    nVar = members[2]['name']
+            else:
+                if len(members) > 1:
+                    nVar = members[1]['name']
+
+            print comment
+            print 'void'
+            print '%(s)s_remove_clause_%(c)s(struct ovsdb_idl *idl, enum ovsdb_function function, %(args)s)' % \
+                {'s': structName, 'c': columnName,
+                 'args': ', '.join(['%(type)s%(name)s' % m for m in members])}
+            print "{"
+            print "    struct ovsdb_datum datum;"
+            if type.n_min == 1 and type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                if type.value:
+                    print "    union ovsdb_atom value;"
+                print
+                print "    ovs_assert(inited);"
+                print "    datum.n = 1;"
+                print "    datum.keys = &key;"
+                print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
+                if type.value:
+                    print "    datum.values = &value;"
+                    print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
+                else:
+                    print "    datum.values = NULL;"
+            elif type.is_optional_pointer():
+                print "    union ovsdb_atom key;"
+                print
+                print "    ovs_assert(inited);"
+                print "    if (%s) {" % keyVar
+                print "        datum.n = 1;"
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
+                print "    } else {"
+                print "        datum.n = 0;"
+                print "        datum.keys = NULL;"
+                print "    }"
+                print "    datum.values = NULL;"
+            elif type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                print
+                print "    ovs_assert(inited);"
+                print "    if (%s) {" % nVar
+                print "        datum.n = 1;"
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
+                print "    } else {"
+                print "        datum.n = 0;"
+                print "        datum.keys = NULL;"
+                print "    }"
+                print "    datum.values = NULL;"
+            else:
+                print "    size_t i;"
+                print
+                print "    ovs_assert(inited);"
+                print "    datum.n = %s;" % nVar
+                print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
+                if type.value:
+                    print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
+                else:
+                    print "    datum.values = NULL;"
+                print "    for (i = 0; i < %s; i++) {" % nVar
+                print "        " + type.key.copyCValue("datum.keys[i].%s" % type.key.type.to_string(), "%s[i]" % keyVar)
+                if type.value:
+                    print "        " + type.value.copyCValue("datum.values[i].%s" % type.value.type.to_string(), "%s[i]" % valueVar)
+                print "    }"
+                if type.value:
+                    valueType = type.value.toAtomicType()
+                else:
+                    valueType = "OVSDB_TYPE_VOID"
+                print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
+                    type.key.toAtomicType(), valueType)
+
+            print"""    ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s],
+                          function,
+                          &%(s)s_columns[%(S)s_COL_%(C)s],
+                          &datum);
+}""" % {'t': tableName,
+       'T': tableName.upper(),
+       'p': prefix,
+       'P': prefix.upper(),
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper()}
+
+        print """void
+%(s)s_remove_clause_false(struct ovsdb_idl *idl)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_FALSE, NULL, &datum);
+}""" % {'s': structName,
+       'T': tableName.upper(),
+       'p': prefix,
+       'P': prefix.upper()}
+
+        print """void
+%(s)s_remove_clause_true(struct ovsdb_idl *idl)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_remove_clause(idl, &%(p)stable_classes[%(P)sTABLE_%(T)s], OVSDB_F_TRUE, NULL, &datum);
+}""" % {'s': structName,
+        'T': tableName.upper(),
+        'p': prefix,
+        'P': prefix.upper(),}
+
         # Table columns.
         print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
             structName, structName.upper())
diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py
index 2f36456..437e9b0 100644
--- a/python/ovs/db/idl.py
+++ b/python/ovs/db/idl.py
@@ -144,6 +144,7 @@ class Idl(object):
             table.rows = {}
             table.idl = self
             table.condition = []
+            table.cond_changed = False
 
     def close(self):
         """Closes the connection to the database.  The IDL will no longer
@@ -170,6 +171,8 @@ class Idl(object):
         for changes in self.change_seqno."""
         assert not self.txn
         initial_change_seqno = self.change_seqno
+
+        self.send_cond_change()
         self._session.run()
         i = 0
         while i < 50:
@@ -252,18 +255,32 @@ class Idl(object):
 
         return initial_change_seqno != self.change_seqno
 
-    def cond_change(self, table_name, cond):
+    def send_cond_change(self):
+        if not self._session.is_connected():
+            return
+
+        for table in six.itervalues(self.tables):
+            if table.cond_changed:
+                self.__send_cond_change(table, table.condition)
+                table.cond_changed = False
+
+    def cond_change(self, table_name, add_cmd, cond):
         """Change conditions for this IDL session. If session is not already
         connected, add condtion to table and submit it on send_monitor_request.
         Otherwise  send monitor_cond_change method with the requested
         changes."""
+
         table = self.tables.get(table_name)
         if not table:
             raise error.Error('Unknown table "%s"' % table_name)
-        if self._session.is_connected():
-            self.__send_cond_change(table, cond)
+
+        if add_cmd:
+            table.condition += cond
         else:
-            table.condition = cond
+            for c in cond:
+                table.condition.remove(c)
+
+        table.cond_changed = True
 
     def wait(self, poller):
         """Arranges for poller.block() to wake up when self.run() has something
@@ -401,9 +418,10 @@ class Idl(object):
                         (column not in self.readonly[table.name])):
                     columns.append(column)
             monitor_requests[table.name] = {"columns": columns}
-            if method == "monitor_cond" and table.condition:
+            if method == "monitor_cond" and table.cond_changed and \
+                   table.condition:
                 monitor_requests[table.name]["where"] = table.condition
-                table.condition = None
+                table.cond_change = False
 
         msg = ovs.jsonrpc.Message.create_request(
             method, [self._db.name, str(self.uuid), monitor_requests])
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index 63008b3..5d9bb81 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -389,6 +389,142 @@ OVSDB_CHECK_IDL([simple idl, destroy without commit or abort],
 004: done
 ]])
 
+OVSDB_CHECK_IDL([simple idl, conditional, false condition],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}}]']],
+  [['condition add simple [false]' \
+    'condition remove simple [false]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, conditional, true condition],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}}]']],
+  [['condition add simple [false]' \
+    'condition add simple [true]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, conditional, multiple clauses in condition],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}},
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 2,
+               "r": 3.0,
+               "b": true}}]']],
+  [['condition add simple [false]' \
+    'condition add simple [["i","==",1],["i","==",2]]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+003: i=2 r=3 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
+004: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, conditional, modify as insert due to condition],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}}]']],
+  [['condition add simple [false]' \
+    'condition add simple [["i","==",1]]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, conditional, modify as delete due to condition],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}}]']],
+  [['condition add simple [false]' \
+    'condition add simple [["i","==",1],["i","==",2]]' \
+    'condition remove simple [["i","==",1]]' \
+    '["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 2,
+               "r": 3.0,
+               "b": true}}]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: change conditions
+005: empty
+006: {"error":null,"result":[{"uuid":["uuid","<2>"]}]}
+007: i=2 r=3 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2>
+008: done
+]])
+
+OVSDB_CHECK_IDL([simple idl, conditional, multiple tables],
+  [['["idltest",
+       {"op": "insert",
+       "table": "simple",
+       "row": {"i": 1,
+               "r": 2.0,
+               "b": true}},
+       {"op": "insert",
+       "table": "link1",
+       "row": {"i": 0, "k": ["named-uuid", "self"]},
+       "uuid-name": "self"},
+        {"op": "insert",
+       "table": "link2",
+       "row": {"i": 2},
+       "uuid-name": "row0"}]']],
+  [['condition add simple [false];condition add link1 [false];condition add link2 [false]' \
+    'condition add simple [["i","==",1]]' \
+    'condition add link1 [["i","==",0]]' \
+    'condition add link2 [["i","==",3]]' \
+    '+["idltest",
+       {"op": "insert",
+       "table": "link2",
+       "row": {"i": 3},
+        "uuid-name": "row0"}]']],
+  [[000: change conditions
+001: empty
+002: change conditions
+003: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+004: change conditions
+005: i=0 k=0 ka=[] l2= uuid=<2>
+005: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+006: change conditions
+007: {"error":null,"result":[{"uuid":["uuid","<3>"]}]}
+008: i=0 k=0 ka=[] l2= uuid=<2>
+008: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1>
+008: i=3 l1= uuid=<3>
+009: done
+]])
+
 OVSDB_CHECK_IDL([self-linking idl, consistent ops],
   [],
   [['["idltest",
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index 74b76af..6357c9c 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -2145,6 +2145,208 @@ idl_set(struct ovsdb_idl *idl, char *commands, int step)
     ovsdb_idl_txn_destroy(txn);
 }
 
+static const struct ovsdb_idl_table_class *
+find_table_class(const char *name)
+{
+    if (!strcmp(name, "simple")) {
+        return &idltest_table_simple;
+    } else if (!strcmp(name, "link1")) {
+        return &idltest_table_link1;
+    } else if (!strcmp(name, "link2")) {
+        return &idltest_table_link2;
+    }
+    return NULL;
+}
+
+static void
+parse_simple_json_clause(struct ovsdb_idl *idl, bool add_cmd,
+                         struct json *json)
+{
+    const char *c;
+    struct ovsdb_error *error;
+    enum ovsdb_function function;
+
+    if (json->type == JSON_TRUE) {
+        add_cmd ? idltest_simple_add_clause_true(idl) :
+            idltest_simple_remove_clause_true(idl);
+        return;
+    } else if (json->type == JSON_FALSE) {
+        add_cmd ? idltest_simple_add_clause_false(idl) :
+            idltest_simple_remove_clause_false(idl);
+        return;
+    }
+    if (json->type != JSON_ARRAY || json->u.array.n != 3) {
+        ovs_fatal(0, "Error parsing condition");
+    }
+
+    c = json_string(json->u.array.elems[0]);
+    error = ovsdb_function_from_string(json_string(json->u.array.elems[1]),
+                                       &function);
+    if (error) {
+        ovs_fatal(0, "Error parsing clause function %s",
+                  json_string(json->u.array.elems[1]));
+    }
+
+    /* add clause according to column */
+    if (!strcmp(c, "b")) {
+        add_cmd ? idltest_simple_add_clause_b(idl, function,
+                                     json_boolean(json->u.array.elems[2])) :
+            idltest_simple_remove_clause_b(idl, function,
+                                     json_boolean(json->u.array.elems[2]));
+    } else if (!strcmp(c, "i")) {
+        add_cmd ? idltest_simple_add_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2])) :
+            idltest_simple_remove_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2]));
+    } else if (!strcmp(c, "s")) {
+        add_cmd ? idltest_simple_add_clause_s(idl, function,
+                                    json_string(json->u.array.elems[2])) :
+            idltest_simple_remove_clause_s(idl, function,
+                                    json_string(json->u.array.elems[2]));
+    } else if (!strcmp(c, "u")) {
+        struct uuid uuid;
+        if (!uuid_from_string(&uuid,
+                              json_string(json->u.array.elems[2]))) {
+            ovs_fatal(0, "\"%s\" is not a valid UUID",
+                      json_string(json->u.array.elems[2]));
+        }
+        add_cmd ? idltest_simple_add_clause_u(idl, function, uuid) :
+            idltest_simple_remove_clause_u(idl, function, uuid);
+    } else if (!strcmp(c, "r")) {
+        add_cmd ? idltest_simple_add_clause_r(idl, function,
+                                    json_real(json->u.array.elems[2])) :
+            idltest_simple_remove_clause_r(idl, function,
+                                    json_real(json->u.array.elems[2]));
+    } else {
+        ovs_fatal(0, "Unsupported columns name %s", c);
+    }
+}
+
+static void
+parse_link1_json_clause(struct ovsdb_idl *idl, bool add_cmd,
+                        struct json *json)
+{
+    const char *c;
+    struct ovsdb_error *error;
+    enum ovsdb_function function;
+
+    if (json->type == JSON_TRUE) {
+        add_cmd ? idltest_link1_add_clause_true(idl) :
+            idltest_link1_remove_clause_true(idl);
+        return;
+    } else if (json->type == JSON_FALSE) {
+        add_cmd ? idltest_link1_add_clause_false(idl) :
+            idltest_link1_remove_clause_false(idl);
+        return;
+    }
+    if (json->type != JSON_ARRAY || json->u.array.n != 3) {
+        ovs_fatal(0, "Error parsing condition");
+    }
+
+    c = json_string(json->u.array.elems[0]);
+    error = ovsdb_function_from_string(json_string(json->u.array.elems[1]),
+                                       &function);
+    if (error) {
+        ovs_fatal(0, "Error parsing clause function %s",
+                  json_string(json->u.array.elems[1]));
+    }
+
+    /* add clause according to column */
+    if (!strcmp(c, "i")) {
+        add_cmd ? idltest_link1_add_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2])) :
+            idltest_link1_remove_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2]));
+    } else {
+        ovs_fatal(0, "Unsupported columns name %s", c);
+    }
+}
+
+static void
+parse_link2_json_clause(struct ovsdb_idl *idl, bool add_cmd, struct json *json)
+{
+    const char *c;
+    struct ovsdb_error *error;
+    enum ovsdb_function function;
+
+    if (json->type == JSON_TRUE) {
+        add_cmd ? idltest_link2_add_clause_true(idl) :
+            idltest_link2_remove_clause_true(idl);
+        return;
+    } else if (json->type == JSON_FALSE) {
+        add_cmd ? idltest_link2_add_clause_false(idl) :
+            idltest_link2_remove_clause_false(idl);
+        return;
+    }
+    if (json->type != JSON_ARRAY || json->u.array.n != 3) {
+        ovs_fatal(0, "Error parsing condition");
+    }
+
+    c = json_string(json->u.array.elems[0]);
+    error = ovsdb_function_from_string(json_string(json->u.array.elems[1]),
+                                       &function);
+    if (error) {
+        ovs_fatal(0, "Error parsing clause function %s",
+                  json_string(json->u.array.elems[1]));
+    }
+
+    /* add clause according to column */
+    if (!strcmp(c, "i")) {
+        add_cmd ? idltest_link2_add_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2])) :
+            idltest_link2_remove_clause_i(idl, function,
+                                    json_integer(json->u.array.elems[2]));
+    } else {
+        ovs_fatal(0, "Unsupported columns name %s", c);
+    }
+}
+
+static void
+update_conditions(struct ovsdb_idl *idl, char *commands)
+{
+    char *cmd, *save_ptr1 = NULL;
+    const struct ovsdb_idl_table_class *tc;
+    bool add_cmd = false;
+
+    for (cmd = strtok_r(commands, ";", &save_ptr1); cmd;
+         cmd = strtok_r(NULL, ";", &save_ptr1)) {
+        if (strstr(cmd, "condition add")) {
+            cmd += strlen("condition add ");
+            add_cmd = true;
+        } else if (strstr(cmd, "condition remove")) {
+            cmd += strlen("condition remove ");
+        } else {
+            ovs_fatal(0, "condition command should be add or remove");
+        }
+
+        char *save_ptr2 = NULL;
+        char *table_name = strtok_r(cmd, " ", &save_ptr2);
+        struct json *json = parse_json(save_ptr2);
+        int i;
+
+        if (json->type != JSON_ARRAY) {
+            ovs_fatal(0, "condition should be an array");
+        }
+
+        tc = find_table_class(table_name);
+        if (!tc) {
+            ovs_fatal(0, "Table %s does not exist", table_name);
+        }
+
+        //ovsdb_idl_condition_reset(idl, tc);
+
+        for (i = 0; i < json->u.array.n; i++) {
+            if (!strcmp(table_name, "simple")) {
+                parse_simple_json_clause(idl, add_cmd, json->u.array.elems[i]);
+            } else if (!strcmp(table_name, "link1")) {
+                parse_link1_json_clause(idl, add_cmd, json->u.array.elems[i]);
+            } else if (!strcmp(table_name, "link2")) {
+                parse_link2_json_clause(idl, add_cmd, json->u.array.elems[i]);
+            }
+        }
+    }
+}
+
 static void
 do_idl(struct ovs_cmdl_context *ctx)
 {
@@ -2183,7 +2385,14 @@ do_idl(struct ovs_cmdl_context *ctx)
     setvbuf(stdout, NULL, _IONBF, 0);
 
     symtab = ovsdb_symbol_table_create();
-    for (i = 2; i < ctx->argc; i++) {
+    if (ctx->argc > 2 && strstr(ctx->argv[2], "condition ")) {
+        update_conditions(idl, ctx->argv[2]);
+        printf("%03d: change conditions\n", step++);
+        i = 3;
+    } else {
+        i = 2;
+    }
+    for (; i < ctx->argc; i++) {
         char *arg = ctx->argv[i];
         struct jsonrpc_msg *request, *reply;
 
@@ -2217,6 +2426,9 @@ do_idl(struct ovs_cmdl_context *ctx)
         if (!strcmp(arg, "reconnect")) {
             printf("%03d: reconnect\n", step++);
             ovsdb_idl_force_reconnect(idl);
+        }  else if (strstr(arg, "condition ")) {
+            update_conditions(idl, arg);
+            printf("%03d: change conditions\n", step++);
         } else if (arg[0] != '[') {
             idl_set(idl, arg, step++);
         } else {
diff --git a/tests/test-ovsdb.py b/tests/test-ovsdb.py
index 42d36d4..41f3444 100644
--- a/tests/test-ovsdb.py
+++ b/tests/test-ovsdb.py
@@ -391,6 +391,27 @@ def idl_set(idl, commands, step):
     sys.stdout.flush()
 
 
+def update_condition(idl, commands):
+    commands = commands.split(";")
+    for command in commands:
+        command = command[len("condition "):]
+        if "add" in command:
+            add_cmd = True
+            command = command[len("add "):]
+        else:
+            add_cmd = False
+            command = command[len("remove "):]
+
+        command = command.split(" ")
+        if(len(command) != 2):
+            sys.stderr.write("Error parsong condition %s\n" % command)
+            sys.exit(1)
+
+        table = command[0]
+        cond = ovs.json.from_string(command[1])
+
+        idl.cond_change(table, add_cmd, cond)
+
 def do_idl(schema_file, remote, *commands):
     schema_helper = ovs.db.idl.SchemaHelper(schema_file)
     if commands and commands[0].startswith("?"):
@@ -422,6 +443,14 @@ def do_idl(schema_file, remote, *commands):
     symtab = {}
     seqno = 0
     step = 0
+
+    commands = list(commands)
+    if len(commands) >= 1 and "condition" in commands[0]:
+        update_condition(idl, commands.pop(0))
+        sys.stdout.write("%03d: change conditions\n" % step)
+        sys.stdout.flush()
+        step += 1
+
     for command in commands:
         if command.startswith("+"):
             # The previous transaction didn't change anything.
@@ -446,6 +475,11 @@ def do_idl(schema_file, remote, *commands):
             sys.stdout.flush()
             step += 1
             idl.force_reconnect()
+        elif "condition" in command:
+            update_condition(idl, command)
+            sys.stdout.write("%03d: change conditions\n" % step)
+            sys.stdout.flush()
+            step += 1
         elif not command.startswith("["):
             idl_set(idl, command, step)
             step += 1
-- 
2.1.4




More information about the dev mailing list