From 16ebb90e05cad5a3013cadd5b4249fac93935447 Mon Sep 17 00:00:00 2001 From: Liran Schour Date: Mon, 18 Jul 2016 11:45:58 +0300 Subject: [PATCH] lib: add monitor_cond_change API to C IDL lib 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 Signed-off-by: Ben Pfaff --- 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 | 35 ++++ 12 files changed, 1099 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 4d4ee01db..1a44cc090 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 000000000..e0c4e43da --- /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 + +#include +#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 000000000..65496e1b2 --- /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 04cf4192a..1f249c09a 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 0e7cdc591..f8e980b14 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 70449fa3e..c08e31bbf 100644 --- a/lib/ovsdb-idl.h +++ b/lib/ovsdb-idl.h @@ -38,6 +38,9 @@ #include #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 2ddc811dd..c794966ce 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 0d836c02e..253344e0c 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 2f3645625..437e9b0b0 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 63008b3df..5d9bb81c1 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 74b76afc2..6357c9cd4 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 42d36d4b9..83fe4af36 100644 --- a/tests/test-ovsdb.py +++ b/tests/test-ovsdb.py @@ -391,6 +391,28 @@ 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 +444,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 +476,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.20.1