[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