[ovs-dev] [PATCH monitor_cond V3 08/10] lib: add monitor_cond_update API to C IDL lib

Liran Schour lirans at il.ibm.com
Wed Feb 3 13:53:32 UTC 2016


Add API that allows the user to create condition iteratively
and send condition_update to the server.

Signed-off-by: Liran Schour <lirans at il.ibm.com>

---
v2->v3:
* Simplify API to allow iteratively adding clauses to condition
  before send monitor_cond_update
* monitor_cond_update receives only a single json condition
* Automaticly generate <dbName>_<tableName)_add_clause_<columnName()
---
 lib/ovsdb-idl-provider.h |  13 ++++
 lib/ovsdb-idl.c          | 178 ++++++++++++++++++++++++++++++++++++++++++++++-
 lib/ovsdb-idl.h          |  34 +++++++++
 ovsdb/ovsdb-idlc.in      | 168 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 392 insertions(+), 1 deletion(-)

diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
index 190acca..1288ad3 100644
--- a/lib/ovsdb-idl-provider.h
+++ b/lib/ovsdb-idl-provider.h
@@ -51,6 +51,18 @@ struct ovsdb_idl_column {
     void (*unparse)(struct ovsdb_idl_row *);
 };
 
+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_idl_function function;
+    const struct ovsdb_idl_column *column;
+    struct ovsdb_datum arg;
+};
+
 struct ovsdb_idl_table_class {
     char *name;
     bool is_root;
@@ -70,6 +82,7 @@ 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;
 };
 
 struct ovsdb_idl_class {
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index a05b420..513b23f 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -261,6 +261,7 @@ 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);
     }
 
     idl->state_seqno = UINT_MAX;
@@ -646,6 +647,176 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
     OVS_NOT_REACHED();
 }
 
+struct ovsdb_error *
+ovsdb_idl_function_from_string(const char *name,
+                               enum ovsdb_idl_function *function)
+{
+#define OVSDB_IDL_FUNCTION(ENUM, NAME)              \
+    if (!strcmp(name, NAME)) {                  \
+        *function = ENUM;                       \
+        return NULL;                            \
+    }
+    OVSDB_IDL_FUNCTIONS;
+#undef OVSDB_IDL_FUNCTION
+
+    return ovsdb_syntax_error(NULL, "unknown function",
+                              "No function named %s.", name);
+}
+
+static const char *
+ovsdb_idl_function_to_string(enum ovsdb_idl_function function)
+{
+    switch (function) {
+#define OVSDB_IDL_FUNCTION(ENUM, NAME) case ENUM: return NAME;
+        OVSDB_IDL_FUNCTIONS;
+#undef OVSDB_IDL_FUNCTION
+    }
+
+    return NULL;
+}
+
+static void
+ovsdb_idl_condition_merge(struct ovsdb_idl_condition *a,
+                          struct ovsdb_idl_condition *b)
+{
+    while(!list_is_empty(&b->clauses)) {
+        list_push_back(&a->clauses, list_pop_front(&b->clauses));
+    }
+}
+
+static struct json *
+ovsdb_idl_clause_to_json(const struct ovsdb_idl_clause *clause)
+{
+    if (clause->function != OVSDB_IDL_F_TRUE &&
+        clause->function != OVSDB_IDL_F_FALSE) {
+        const char *function = ovsdb_idl_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_IDL_F_TRUE ?
+                               true : false);
+}
+
+static void
+ovsdb_idl_clause_free(struct ovsdb_idl_clause *clause)
+{
+    if (clause->function != OVSDB_IDL_F_TRUE &&
+        clause->function != OVSDB_IDL_F_FALSE) {
+        ovsdb_datum_destroy(&clause->arg, &clause->column->type);
+    }
+
+    list_remove(&clause->node);
+    free(clause);
+}
+
+void
+ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd)
+{
+    struct ovsdb_idl_clause *c, *next;
+
+    LIST_FOR_EACH_SAFE (c, next, node, &cnd->clauses) {
+        ovsdb_idl_clause_free(c);
+    }
+}
+
+void
+ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
+                         const struct ovsdb_idl_table_class *tc)
+{
+    cnd->tc = tc;
+    list_init(&cnd->clauses);
+}
+
+void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *cnd,
+                                    enum ovsdb_idl_function function,
+                                    const struct ovsdb_idl_column *column,
+                                    struct ovsdb_datum *arg)
+{
+    struct ovsdb_idl_clause *clause = xzalloc(sizeof *clause);
+    const struct ovsdb_type *type = NULL;
+
+    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);
+    list_push_back(&cnd->clauses, &clause->node);
+}
+
+static struct json *
+ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
+{
+    struct json **clauses;
+    size_t i = 0, n_clauses = 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 void
+ovsdb_idl_send_cond_update__(struct ovsdb_idl *idl,
+                             struct ovsdb_idl_table *table,
+                             const struct ovsdb_idl_condition *cond)
+{
+    char uuid[UUID_LEN + 1];
+    struct json *monitor_cond_update_requests = json_object_create();
+    struct json *monitor_cond_update_request = json_object_create();
+    struct json *cond_json = ovsdb_idl_condition_to_json(cond);
+    struct json *params, *json_uuid;
+    struct jsonrpc_msg *request;
+
+    json_object_put(monitor_cond_update_request, "where", cond_json);
+    json_object_put(monitor_cond_update_requests,
+                    table->class->name,
+                    json_array_create_1(monitor_cond_update_request));
+
+    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_update_requests);
+
+    request = jsonrpc_create_request("monitor_cond_update", params, NULL);
+    jsonrpc_session_send(idl->session, request);
+}
+
+/* Add conditions to the replicated tables. Ensure that tables are added to the
+ * replication.
+ */
+bool
+ovsdb_idl_cond_update(struct ovsdb_idl *idl,
+                      struct ovsdb_idl_condition *cond)
+{
+    struct ovsdb_idl_table *table;
+
+    table = ovsdb_idl_table_from_class(idl, cond->tc);
+
+    if (jsonrpc_session_is_connected(idl->session)) {
+        ovsdb_idl_send_cond_update__(idl, table, cond);
+    } else {
+        ovsdb_idl_condition_merge(&table->condition, cond);
+    }
+    return true;
+}
+
 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
  *
  * This function should be called between ovsdb_idl_create() and the first call
@@ -945,7 +1116,7 @@ ovsdb_idl_send_monitor_request__(struct ovsdb_idl *idl,
     for (i = 0; i < idl->class->n_tables; i++) {
         const 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;
 
@@ -983,6 +1154,11 @@ 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") &&
+                list_size(&table->condition.clauses) > 0) {
+                where = ovsdb_idl_condition_to_json(&table->condition);
+                json_object_put(monitor_request, "where", where);
+            }
             json_object_put(monitor_requests, tc->name, monitor_request);
         }
     }
diff --git a/lib/ovsdb-idl.h b/lib/ovsdb-idl.h
index 1cbaf35..c93fdf3 100644
--- a/lib/ovsdb-idl.h
+++ b/lib/ovsdb-idl.h
@@ -45,6 +45,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,
@@ -277,4 +278,37 @@ 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 *);
 
+/* These list is ordered in ascending order of the fraction of tables row that
+ * they are (heuristically) expected to leave in query results. */
+#define OVSDB_IDL_FUNCTIONS                         \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_FALSE, "false")            \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_TRUE, "true")              \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EQ, "==")                  \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_INCLUDES, "includes")      \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LE, "<=")                  \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_LT, "<")                   \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GE, ">=")                  \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_GT, ">")                   \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_EXCLUDES, "excludes")      \
+    OVSDB_IDL_FUNCTION(OVSDB_IDL_F_NE, "!=")
+
+enum ovsdb_idl_function {
+#define OVSDB_IDL_FUNCTION(ENUM, NAME) ENUM,
+    OVSDB_IDL_FUNCTIONS
+#undef OVSDB_IDL_FUNCTION
+};
+
+void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd,
+                              const struct ovsdb_idl_table_class *tc);
+void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd);
+void ovsdb_idl_condition_add_clause(struct ovsdb_idl_condition *cnd,
+                                    enum ovsdb_idl_function function,
+                                    const struct ovsdb_idl_column *column,
+                                    struct ovsdb_datum *arg);
+bool ovsdb_idl_cond_update(struct ovsdb_idl *idl,
+                           struct ovsdb_idl_condition *cond);
+
+struct ovsdb_error *
+ovsdb_idl_function_from_string(const char *name,
+                               enum ovsdb_idl_function *function);
 #endif /* ovsdb-idl.h */
diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
index 26b0de4..596c2a7 100755
--- a/ovsdb/ovsdb-idlc.in
+++ b/ovsdb/ovsdb-idlc.in
@@ -216,6 +216,20 @@ bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id);
             print '%s);' % ', '.join(args)
 
         print
+        for columnName, column in sorted(table.columns.iteritems()):
+            print 'void %(s)s_add_clause_%(c)s(struct ovsdb_idl_condition *, enum ovsdb_idl_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_condition *);' % structName
+        print 'void %s_add_clause_false(struct ovsdb_idl_condition *);' % structName
+
+        print
 
     # Table indexes.
     printEnum("%stable_id" % prefix.lower(), ["%sTABLE_%s" % (prefix.upper(), tableName.upper()) for tableName in sorted(schema.tables)] + ["%sN_TABLES" % prefix.upper()])
@@ -747,6 +761,160 @@ const struct ovsdb_datum *
                    'C': columnName.upper()}
             print "}"
 
+        # 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_condition *cnd, enum ovsdb_idl_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(cnd,
+                                   function,
+                                   &%(s)s_columns[%(S)s_COL_%(C)s],
+                                   &datum);
+}
+""" % {'t': tableName,
+       '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_condition *cnd, enum ovsdb_idl_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(cnd,
+                          function,
+                          &%(s)s_columns[%(S)s_COL_%(C)s],
+                          &datum);
+}""" % {'t': tableName,
+       's': structName,
+       'S': structName.upper(),
+       'c': columnName,
+       'C': columnName.upper()}
+
+        print """void
+%s_add_clause_false(struct ovsdb_idl_condition *cnd)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_add_clause(cnd, OVSDB_IDL_F_FALSE, NULL, &datum);
+}""" % structName
+
+        print """void
+%s_add_clause_true(struct ovsdb_idl_condition *cnd)
+{
+    struct ovsdb_datum datum;
+
+    ovsdb_datum_init_empty(&datum);
+    ovsdb_idl_condition_add_clause(cnd, OVSDB_IDL_F_TRUE, NULL, &datum);
+}""" % structName
+
         # Table columns.
         print "\nstruct ovsdb_idl_column %s_columns[%s_N_COLUMNS];" % (
             structName, structName.upper())
-- 
2.1.4





More information about the dev mailing list