[ovs-dev] [PATCH monitor_cond 10/12] lib: add condition change to idl session

Liran Schour lirans at il.ibm.com
Tue Jan 5 13:14:03 UTC 2016


Implement function for changing condition in an idl session.

Signed-off-by: Liran Schour <lirans at il.ibm.com>
---
 lib/ovsdb-idl-provider.h |  33 ++++
 lib/ovsdb-idl.c          | 393 ++++++++++++++++++++++++++++++++++++++++++++++-
 lib/ovsdb-idl.h          |  13 ++
 3 files changed, 438 insertions(+), 1 deletion(-)

diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
index 099535e..e7d067e 100644
--- a/lib/ovsdb-idl-provider.h
+++ b/lib/ovsdb-idl-provider.h
@@ -49,6 +49,38 @@ struct ovsdb_idl_column {
     void (*unparse)(struct ovsdb_idl_row *);
 };
 
+
+/* 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
+};
+
+struct ovsdb_idl_clause {
+    enum ovsdb_idl_function function;
+    const struct ovsdb_idl_column *column;
+    struct ovsdb_datum arg;
+};
+
+struct ovsdb_idl_condition {
+    struct ovsdb_idl_clause *clauses;
+    size_t n_clauses;
+};
+
 struct ovsdb_idl_table_class {
     char *name;
     bool is_root;
@@ -68,6 +100,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 aed62a5..cc0d75e 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);
     }
 
     idl->state_seqno = UINT_MAX;
@@ -650,6 +651,391 @@ ovsdb_idl_add_table(struct ovsdb_idl *idl,
     OVS_NOT_REACHED();
 }
 
+static const struct ovsdb_idl_table_class *
+ovsdb_idl_table_name_to_class(struct ovsdb_idl *idl, const char *name)
+{
+    int i;
+    struct ovsdb_idl_table *table;
+
+    /* Ensure table are being replicated */
+    for (i = 0; i < idl->class->n_tables; i++) {
+        table = &idl->tables[i];
+
+        if (strcmp(table->class->name, name) == 0) {
+            return table->class;
+        }
+    }
+    return NULL;
+}
+
+static const struct ovsdb_idl_column *
+ovsdb_table_get_column(const struct ovsdb_idl_table_class *tc, const char *name)
+{
+    int i;
+
+    for (i = 0; i < tc->n_columns; i++) {
+        if(!strcmp(tc->columns[i].name, name)) {
+            return &tc->columns[i];
+        }
+    }
+    return NULL;
+}
+
+static 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 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);
+    }
+}
+
+void
+ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd)
+{
+    size_t i;
+
+    for (i = 0; i < cnd->n_clauses; i++) {
+        ovsdb_idl_clause_free(&cnd->clauses[i]);
+    }
+    free(cnd->clauses);
+    cnd->n_clauses = 0;
+}
+
+void
+ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd)
+{
+    cnd->clauses = NULL;
+    cnd->n_clauses = 0;
+}
+
+static int
+compare_clauses(const void *a_, const void *b_)
+{
+    const struct ovsdb_idl_clause *a = a_;
+    const struct ovsdb_idl_clause *b = b_;
+
+    if (a->function != b->function) {
+        return a->function < b->function ? -1 : 1;
+    } else if (a->function == OVSDB_IDL_F_TRUE ||
+               a->function == OVSDB_IDL_F_FALSE) {
+        return 0;
+    } else if (strcmp(a->column->name, b->column->name)) {
+        return strcmp(a->column->name, b->column->name);
+    } else {
+        return ovsdb_datum_compare_3way(&a->arg, &b->arg, &a->column->type);
+    }
+    OVS_NOT_REACHED();
+}
+
+static int
+ovsdb_idl_clause_exists(const struct ovsdb_idl_condition *cnd,
+                        const struct ovsdb_idl_clause *clause)
+{
+    size_t i;
+
+    for (i=0; i < cnd->n_clauses; i++) {
+        if(!compare_clauses(&cnd->clauses[i], clause)) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+static void
+ovsdb_idl_clone_clause(struct ovsdb_idl_clause *new,
+                       struct ovsdb_idl_clause *old)
+{
+    new->function = old->function;
+    if (new->function == OVSDB_IDL_F_TRUE ||
+        new->function ==OVSDB_IDL_F_FALSE) {
+        return;
+    }
+    new->column = old->column;
+    ovsdb_datum_clone(&new->arg,
+		      &old->arg,
+		      &old->column->type);
+}
+
+static void
+ovsdb_idl_condition_add(struct ovsdb_idl_condition *to,
+                        const struct ovsdb_idl_condition *add)
+{
+    size_t i, count = 0;
+    struct ovsdb_idl_clause *clauses;
+    unsigned long int *clause_map = xzalloc(bitmap_n_bytes(add->n_clauses));
+    int index = to->n_clauses;;
+
+    for (i = 0; i < add->n_clauses; i++) {
+        if (ovsdb_idl_clause_exists(to, &add->clauses[i]) == -1) {
+	    bitmap_set1(clause_map, i);
+	    count++;
+	}
+    }
+
+    if (!count) {
+        free(clause_map);
+        return;
+    }
+    clauses = xzalloc((to->n_clauses + count) * sizeof *clauses);
+
+    for (i = 0; i < to->n_clauses; i++) {
+        ovsdb_idl_clone_clause(&clauses[i], &to->clauses[i]);
+        ovsdb_idl_clause_free(&to->clauses[i]);
+    }
+
+    for (i = 0; i < add->n_clauses; i++) {
+        if (bitmap_is_set(clause_map, i)) {
+	    ovsdb_idl_clone_clause(&clauses[index++], &add->clauses[i]);
+        }
+    }
+
+    free(to->clauses);
+    free(clause_map);
+    to->clauses = clauses;
+    to->n_clauses += count;
+}
+
+static struct json *
+ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd)
+{
+    struct json **clauses;
+    size_t i;
+
+    clauses = xmalloc(cnd->n_clauses * sizeof *clauses);
+    for (i = 0; i < cnd->n_clauses; i++) {
+        clauses[i] = ovsdb_idl_clause_to_json(&cnd->clauses[i]);
+    }
+    return json_array_create(clauses, cnd->n_clauses);
+}
+
+static struct ovsdb_error *
+ovsdb_idl_clause_from_json(const struct ovsdb_idl_table_class *tc,
+                           const struct json *json,
+                           struct ovsdb_idl_clause *clause)
+{
+    const struct json_array *array;
+    struct ovsdb_error *error;
+    const char *function_name;
+    const char *column_name;
+    struct ovsdb_type type;
+
+    if (json->type == JSON_TRUE || json->type == JSON_FALSE) {
+	/* column and arg fields are not being used with boolean function */
+	function_name = (json->type == JSON_TRUE) ? "true" : "false";
+	error = ovsdb_idl_function_from_string(function_name, &clause->function);
+
+	return error;
+    }
+
+    if (json->type != JSON_ARRAY
+        || json->u.array.n != 3
+        || json->u.array.elems[0]->type != JSON_STRING
+        || json->u.array.elems[1]->type != JSON_STRING) {
+        return ovsdb_syntax_error(json, NULL, "Parse error in condition.");
+    }
+    array = json_array(json);
+
+    column_name = json_string(array->elems[0]);
+    clause->column = ovsdb_table_get_column(tc, column_name);
+    if (!clause->column) {
+        return ovsdb_syntax_error(json, "unknown column",
+                                  "No column %s in table %s.",
+                                  column_name, tc->name);
+    }
+    type = clause->column->type;
+
+    function_name = json_string(array->elems[1]);
+    error = ovsdb_idl_function_from_string(function_name, &clause->function);
+    if (error) {
+        return error;
+    }
+
+    /* Type-check and relax restrictions on 'type' if appropriate.  */
+    switch (clause->function) {
+    case OVSDB_IDL_F_LT:
+    case OVSDB_IDL_F_LE:
+    case OVSDB_IDL_F_GT:
+    case OVSDB_IDL_F_GE:
+        /* Allow these operators for types with n_min == 0, n_max == 1.
+         * (They will always be "false" if the value is missing.) */
+        if (!(ovsdb_type_is_scalar(&type)
+            || ovsdb_type_is_optional_scalar(&type))
+            || (type.key.type != OVSDB_TYPE_INTEGER
+                && type.key.type != OVSDB_TYPE_REAL)) {
+            char *s = ovsdb_type_to_english(&type);
+            error = ovsdb_syntax_error(
+                json, NULL, "Type mismatch: \"%s\" operator may not be "
+                "applied to column %s of type %s.",
+                ovsdb_idl_function_to_string(clause->function),
+                clause->column->name, s);
+            free(s);
+            return error;
+        }
+        break;
+    case OVSDB_IDL_F_TRUE:
+    case OVSDB_IDL_F_FALSE:
+    case OVSDB_IDL_F_EQ:
+    case OVSDB_IDL_F_NE:
+        break;
+
+    case OVSDB_IDL_F_EXCLUDES:
+        if (!ovsdb_type_is_scalar(&type)) {
+            type.n_min = 0;
+            type.n_max = UINT_MAX;
+        }
+        break;
+
+    case OVSDB_IDL_F_INCLUDES:
+        if (!ovsdb_type_is_scalar(&type)) {
+            type.n_min = 0;
+        }
+        break;
+    }
+    return ovsdb_datum_from_json(&clause->arg, &type, array->elems[2], NULL);
+}
+
+struct ovsdb_error *
+ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
+                              const char *table_name,
+                              const struct json *json,
+                              struct ovsdb_idl_condition *cnd)
+{
+    const struct ovsdb_idl_table_class *table_class =
+        ovsdb_idl_table_name_to_class(idl, table_name);
+    const struct json_array *array = json_array(json);
+    struct ovsdb_error *error;
+    size_t i;
+
+    if (!table_class) {
+        error = ovsdb_syntax_error(NULL, NULL, "Error finding table %s ",
+                                   table_name);
+        return error;
+    }
+
+    cnd->clauses = xzalloc(array->n * sizeof *cnd->clauses);
+    cnd->n_clauses = 0;
+    for (i = 0; i < array->n; i++) {
+        struct ovsdb_error *error;
+        error = ovsdb_idl_clause_from_json(table_class, array->elems[i],
+                                           &cnd->clauses[i]);
+        if (error) {
+            ovsdb_idl_condition_destroy(cnd);
+            cnd->clauses = NULL;
+            cnd->n_clauses = 0;
+            return error;
+        }
+        cnd->n_clauses++;
+    }
+
+    return NULL;
+}
+
+static void
+ovsdb_idl_send_cond_change__(struct ovsdb_idl *idl,
+                             struct ovsdb_idl_table *table,
+                             const struct ovsdb_idl_condition *add,
+                             const struct ovsdb_idl_condition *remove)
+{
+    char uuid[UUID_LEN + 1];
+    struct json *monitor_cond_change_requests = json_object_create();
+    struct json *monitor_cond_change_request = json_object_create();
+    struct json *added = ovsdb_idl_condition_to_json(add);
+    struct json *removed = ovsdb_idl_condition_to_json(remove);
+    struct json *params;
+    struct jsonrpc_msg *request;
+
+    json_object_put(monitor_cond_change_request, "added", added);
+    json_object_put(monitor_cond_change_request, "removed", removed);
+    json_object_put(monitor_cond_change_requests,
+                    table->class->name,
+                    json_array_create_1(monitor_cond_change_request));
+
+    snprintf(uuid, sizeof uuid, UUID_FMT,
+             UUID_ARGS(ovsdb_idl_get_monitor_id(idl)));
+    params = json_array_create_2(json_string_create(uuid),
+                                 monitor_cond_change_requests);
+
+    request = jsonrpc_create_request("monitor_cond_change", 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_change(struct ovsdb_idl *idl,
+                      const char *table_name,
+                      const struct ovsdb_idl_condition *add,
+                      const struct ovsdb_idl_condition *remove)
+{
+    const struct ovsdb_idl_table_class *table_class =
+        ovsdb_idl_table_name_to_class(idl, table_name);
+    struct ovsdb_idl_table *table;
+
+    if (table_class == NULL) {
+        return false;
+    }
+    table = ovsdb_idl_table_from_class(idl, table_class);
+
+    if (jsonrpc_session_is_connected(idl->session)) {
+        ovsdb_idl_send_cond_change__(idl, table, add, remove);
+    } else {
+        if (remove && remove->n_clauses > 0) {
+            /* No remove conditions on an unconnected session */
+            return false;
+        }
+        ovsdb_idl_condition_add(&table->condition, add);
+    }
+    return true;
+}
+
 /* Turns off OVSDB_IDL_ALERT for 'column' in 'idl'.
  *
  * This function should be called between ovsdb_idl_create() and the first call
@@ -922,7 +1308,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;
 
@@ -960,6 +1346,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") &&
+                table->condition.n_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 b4605d6..3d91932 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,
@@ -274,5 +275,17 @@ struct ovsdb_idl_loop {
 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 *);
+#define OVSDB_IDL_CONDITION_INITIALIZER { NULL, 0 }
+void ovsdb_idl_condition_init(struct ovsdb_idl_condition *cnd);
+void ovsdb_idl_condition_destroy(struct ovsdb_idl_condition *cnd);
+struct ovsdb_error *
+ovsdb_idl_condition_from_json(struct ovsdb_idl *idl,
+                              const char *table_name,
+                              const struct json *json,
+                              struct ovsdb_idl_condition *cnd);
+bool ovsdb_idl_cond_change(struct ovsdb_idl *idl,
+                           const char *table_name,
+                           const struct ovsdb_idl_condition *add,
+                           const struct ovsdb_idl_condition *remove);
 
 #endif /* ovsdb-idl.h */
-- 
2.1.4





More information about the dev mailing list