"dev" <dev-boun...@openvswitch.org> wrote on 05/20/2016 01:17:57 PM:
> From: Amitabha Biswas/San Jose/IBM@IBMUS > To: dev@openvswitch.org > Date: 05/20/2016 01:18 PM > Subject: [ovs-dev] [v1 1/1] Fix "raceful" E2E ovn tests > Sent by: "dev" <dev-boun...@openvswitch.org> > > This patch fixes the "raceful" situation that occurs when ovn-nbctl > configures the OVN Northbound database till the point when the > ovn-controller picks up the corresponding logical flows and applies > them as OpenFlow rules on the hypervisor. > > The algorithm is outlined in the email - > http://openvswitch.org/pipermail/dev/2016-April/070042.html which > began as a thread here - > http://openvswitch.org/pipermail/dev/2016-April/069602.html > > A new table, Config, is added to OVN_Northbound and OVN_Southbound > DBs. This table is restricted to a single row in both the DBs. > The OVN_Northbound Config contains a single row, with next_cfg and > cur_cfg. The next_cfg is updated by ovn-nbctl whenever it commits > an update to the OVN_Northbound DB. The ovn-northd picks up the > next_cfg from the OVN_Northbound DB and sets the same value in the > OVN_Southbound's Config table next_cfg column. > > A new column (cur_cfg) is added to the Chassis table in the > OVN_Southbound DB. Every ovn-controller updates the cur_cfg in its > Chassis row (to the value in the OVN_Southbound DB cur_cfg column). > This is done in the next iteration after the ovn-controller picks up > the latest logical flows and pends them to be applied as OpenFlow > rules. The ovn-northd computes the mimumum of all the cur_cfg values > in the Chassis table and sets the OVN_Northbound's DB cur_cfg value. > > The ovn-nbctl utility increments the OVN_Northbound's next_cfg value > whenever it commits a transaction that modifies the OVN_Northbound > DB. A "--wait" option is added to the ovn-nbctl utility. When the > "--wait" option is used, the ovn-nbctl waits for the > OVN_Northbound's cur_cfg to equal next_cfg before it exits. A new > operation "nop" is added to use when the ovn-nbctl does not have any > read or write operation but wants to wait for all previous > configurations to have been picked up by the ovn-controllers by > using - "ovn-nbctl --wait nop" command. > > The ovn E2E test cases have been modified to use the > "ovn-nbctl --wait nop" command instead of using "sleep 1" to assume > synchronization between the OVN_Northbound settings and the > ovn-controllers. > > Caveats: > > Not all ovn-nbctl operations that modify the OVN_Northbound DB and > therefore increment the next_cfg value actually result in OpenFlow > rules being modified in the hypervisors. So a --wait option must not > be used under such circumstances. > > If a logical datapath doesn't exist on a particular hypervisor, the > ovn-controller will not apply any OpenFlow rules associated with that > datapath and not update the cur_cfg. Use caution with the "--wait" > option. > > Signed-off-by: Amitabha Biswas <abis...@us.ibm.com> > > Reported-by: Ryan Moats <rmo...@us.ibm.com> > > Reported-at: http://openvswitch.org/pipermail/dev/2016-April/069602.html > --- > ovn/controller/ofctrl.c | 15 ++++++++--- > ovn/controller/ofctrl.h | 2 +- > ovn/controller/ovn-controller.c | 43 ++++++++++++++++++++++++++++++- > ovn/northd/ovn-northd.c | 56 ++++++++++++++++++++++++++++++ > +++++++++++ > ovn/ovn-nb.ovsschema | 10 ++++++-- > ovn/ovn-nb.xml | 21 +++++++++++++++- > ovn/ovn-sb.ovsschema | 12 +++++++-- > ovn/ovn-sb.xml | 19 ++++++++++++++ > ovn/utilities/ovn-nbctl.8.xml | 29 +++++++++++++++++++++ > ovn/utilities/ovn-nbctl.c | 56 ++++++++++++++++++++++++++++++ > ++++++----- > tests/ovn.at | 37 ++++++++++++++++----------- > 11 files changed, 269 insertions(+), 31 deletions(-) > > diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c > index f537bc0..9d211bb 100644 > --- a/ovn/controller/ofctrl.c > +++ b/ovn/controller/ofctrl.c > @@ -597,10 +597,14 @@ queue_flow_mod(struct ofputil_flow_mod *fm) > * flows from 'flow_table' and frees them. (The hmap itself isn't > * destroyed.) > * > - * This called be called be ofctrl_run() within the main loop. */ > -void > + * This called be called be ofctrl_run() within the main loop. > + * Returns true if the installed flows were updated (queued) false otherwise. > + */ > +bool > ofctrl_put(struct hmap *flow_table) > { > + bool flows_updated = false; > + > /* The flow table can be updated if the connection to the > switch is up and > * in the correct state and not backlogged with existing flow_mods. (Our > * criteria for being backlogged appear very conservative, but the socket > @@ -610,7 +614,7 @@ ofctrl_put(struct hmap *flow_table) > if (state != S_UPDATE_FLOWS > || rconn_packet_counter_n_packets(tx_counter)) { > ovn_flow_table_clear(flow_table); > - return; > + return flows_updated; > } > > /* Iterate through all of the installed flows. If any of them are no > @@ -629,6 +633,7 @@ ofctrl_put(struct hmap *flow_table) > .command = OFPFC_DELETE_STRICT, > }; > queue_flow_mod(&fm); > + flows_updated = true; > ovn_flow_log(i, "removing"); > > hmap_remove(&installed_flows, &i->hmap_node); > @@ -647,6 +652,7 @@ ofctrl_put(struct hmap *flow_table) > }; > queue_flow_mod(&fm); > ovn_flow_log(i, "updating"); > + flows_updated = true; > > /* Replace 'i''s actions by 'd''s. */ > free(i->ofpacts); > @@ -676,10 +682,13 @@ ofctrl_put(struct hmap *flow_table) > .command = OFPFC_ADD, > }; > queue_flow_mod(&fm); > + flows_updated = true; > ovn_flow_log(d, "adding"); > > /* Move 'd' from 'flow_table' to installed_flows. */ > hmap_remove(flow_table, &d->hmap_node); > hmap_insert(&installed_flows, &d->hmap_node, d->hmap_node.hash); > } > + > + return flows_updated; > } > diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h > index bc9cfba..dd26f6e 100644 > --- a/ovn/controller/ofctrl.h > +++ b/ovn/controller/ofctrl.h > @@ -30,7 +30,7 @@ struct ovsrec_bridge; > /* Interface for OVN main loop. */ > void ofctrl_init(void); > enum mf_field_id ofctrl_run(const struct ovsrec_bridge *br_int); > -void ofctrl_put(struct hmap *flows); > +bool ofctrl_put(struct hmap *flows); > void ofctrl_wait(void); > void ofctrl_destroy(void); > > diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c > index 511b184..2a06f7c 100644 > --- a/ovn/controller/ovn-controller.c > +++ b/ovn/controller/ovn-controller.c > @@ -252,6 +252,34 @@ get_ovnsb_remote_probe_interval(struct > ovsdb_idl *ovs_idl, int *value) > return false; > } > > +/* Set the current configuration of the local chassis to the OVN Southbound > + * next_cfg value. This indicates that the ovn-controller has picked up and > + * applied (queued) the latest flows. > + */ > +static bool > +update_chassis_config(struct controller_ctx *ctx, const char *chassis_id) > +{ > + const struct sbrec_chassis *chassis_rec; > + > + if (!ctx->ovnsb_idl || !ctx->ovnsb_idl_txn) { > + return false; > + } > + > + chassis_rec = get_chassis(ctx->ovnsb_idl, chassis_id); > + if (!chassis_rec) { > + return false; > + } > + > + const struct sbrec_config *sb_config > + = sbrec_config_first(ctx->ovnsb_idl); > + if (!sb_config) { > + return false; > + } > + > + sbrec_chassis_set_cur_cfg(chassis_rec, sb_config->next_cfg); > + return true; > +} > + > int > main(int argc, char *argv[]) > { > @@ -384,7 +412,20 @@ main(int argc, char *argv[]) > br_int, chassis_id, &ct_zones, &flow_table, > &local_datapaths, &patched_datapaths); > } > - ofctrl_put(&flow_table); > + /* Update the cur_cfg of the local chassis if the flow table > + * was (pended to be) modified in a previous iteration but no > + * modified in the current iteration. This indicates that the > + * flow modification has reached a steady state (for now). > + */ > + static bool new_flows_pended = false; > + if (ofctrl_put(&flow_table)) { > + new_flows_pended = true; > + } > + else if (new_flows_pended && chassis_id) { One nit: this is usually pulled together into one line: "} else if ..." > + if (update_chassis_config(&ctx, chassis_id)) { > + new_flows_pended = false; > + } > + } > hmap_destroy(&flow_table); > mcgroup_index_destroy(&mcgroups); > lport_index_destroy(&lports); > diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c > index 44e9430..954978a 100644 > --- a/ovn/northd/ovn-northd.c > +++ b/ovn/northd/ovn-northd.c > @@ -2382,6 +2382,54 @@ add_column_noalert(struct ovsdb_idl *idl, > ovsdb_idl_omit_alert(idl, column); > } > > +static void > +cp_nextcfg_to_sb(struct northd_context *ctx) > +{ > + const struct nbrec_config *nb; > + const struct sbrec_config *sb; > + > + nb = nbrec_config_first(ctx->ovnnb_idl); > + if (!nb && ctx->ovnnb_txn) { > + /* XXX add verification that table is empty */ > + nb = nbrec_config_insert(ctx->ovnnb_txn); > + } > + > + sb = sbrec_config_first(ctx->ovnsb_idl); > + if (!sb && ctx->ovnsb_txn) { > + /* XXX add verification that table is empty */ > + sb = sbrec_config_insert(ctx->ovnsb_txn); > + } > + > + if (sb && nb && ctx->ovnsb_txn && sb->next_cfg < nb->next_cfg) { > + sbrec_config_set_next_cfg(sb, nb->next_cfg); > + } > +} > + > +/* Compute the cur_cfg of the OVN_Northbound as the minimum of all cur_cfg > + * values in the Chassis Table. > + */ > +static void > +compute_curcfg(struct northd_context *ctx) > +{ > + const struct nbrec_config *nb; > + const struct sbrec_chassis *chassis_rec; > + int64_t cur_cfg_min = (((int64_t)1) << 62) - 1; > + bool cur_cfg_modified = false; > + > + SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) { > + if (cur_cfg_min > chassis_rec->cur_cfg) { > + cur_cfg_min = chassis_rec->cur_cfg; > + cur_cfg_modified = true; > + } > + } > + > + nb = nbrec_config_first(ctx->ovnnb_idl); > + if (nb && ctx->ovnnb_txn && cur_cfg_modified && > + nb->cur_cfg < cur_cfg_min) { > + nbrec_config_set_cur_cfg(nb, cur_cfg_min); > + } > +} > + > int > main(int argc, char *argv[]) > { > @@ -2452,6 +2500,12 @@ main(int argc, char *argv[]) > add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac); > ovsdb_idl_add_column(ovnsb_idl_loop.idl, > &sbrec_port_binding_col_chassis); > > + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_cur_cfg); > + > + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_config); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_config_col_next_cfg); > + > /* Main loop. */ > exiting = false; > while (!exiting) { > @@ -2462,6 +2516,8 @@ main(int argc, char *argv[]) > .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), > }; > > + cp_nextcfg_to_sb(&ctx); > + compute_curcfg(&ctx); > ovnnb_db_run(&ctx); > ovnsb_db_run(&ctx); > > diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema > index 8163f6a..fd6e16f 100644 > --- a/ovn/ovn-nb.ovsschema > +++ b/ovn/ovn-nb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Northbound", > "version": "2.1.1", > - "cksum": "2615511875 5108", > + "cksum": "3226126619 5306", > "tables": { > "Logical_Switch": { > "columns": { > @@ -99,6 +99,12 @@ > "ip_prefix": {"type": "string"}, > "nexthop": {"type": "string"}, > "output_port": {"type": {"key": "string", "min": 0, > "max": 1}}}, > - "isRoot": false} > + "isRoot": false}, > + "Config": { > + "columns": { > + "cur_cfg": {"type": "integer"}, > + "next_cfg": {"type": "integer"}}, > + "isRoot": true, > + "maxRows": 1} > } > } > diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml > index c01455d..96dabd4 100644 > --- a/ovn/ovn-nb.xml > +++ b/ovn/ovn-nb.xml > @@ -637,7 +637,7 @@ > column is set to <code>false</code>, the router is disabled. A disabled > router has all ingress and egress traffic dropped. > </column> > - > + > <group title="Common Columns"> > <column name="external_ids"> > See <em>External IDs</em> at the beginning of this document. > @@ -757,4 +757,23 @@ > </column> > </table> > > + <table name="Config" title="OVN Northbound configuration."> > + Configuration for an OVN Northbound DB. There must be exactly > + one record in the <ref table="Config"/> table. > + > + <group title="Status"> > + <column name="next_cfg"> > + Sequence number for client to increment. When a client > + modifies any part of the database configuration and wishes to > + wait for all the ovn-controllers to finish applying the > + changes, it may increment this sequence number. > + </column> > + > + <column name="cur_cfg"> > + Sequence number that ovn-northd sets to the current value of > + <ref column="next_cfg"/> after all the ovn-controllers have > + applied a (configuration) sequence number. > + </column> > + </group> > + </table> > </database> > diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema > index 06e8a07..5d266e2 100644 > --- a/ovn/ovn-sb.ovsschema > +++ b/ovn/ovn-sb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Southbound", > "version": "1.3.0", > - "cksum": "654726257 5528", > + "cksum": "329629017 5732", > "tables": { > "Chassis": { > "columns": { > @@ -13,6 +13,7 @@ > "vtep_logical_switches" : {"type": {"key": "string", > "min": 0, > "max": "unlimited"}}, > + "cur_cfg": {"type": "integer"}, > "external_ids": { > "type": {"key": "string", "value": "string", > "min": 0, "max": "unlimited"}}}, > @@ -110,4 +111,11 @@ > "ip": {"type": "string"}, > "mac": {"type": "string"}}, > "indexes": [["logical_port", "ip"]], > - "isRoot": true}}} > + "isRoot": true}, > + "Config": { > + "columns": { > + "next_cfg": {"type": "integer"}}, > + "isRoot": true, > + "maxRows": 1} > + } > +} > diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml > index efd2f9a..28938ee 100644 > --- a/ovn/ovn-sb.xml > +++ b/ovn/ovn-sb.xml > @@ -179,6 +179,13 @@ > information. > </column> > > + <column name='cur_cfg'> > + <code>ovn-controller</code> populates this value with the value > + of <ref column="next_cfg"/> in <ref table='Config'/> after it > + successfully applies all the logical flows in the OVN > + Southbound database as open flow rules. > + </column> > + > <group title="Common Columns"> > The overall purpose of these columns is described under <code>Common > Columns</code> at the beginning of this document. > @@ -1511,4 +1518,16 @@ tcp.flags = RST; > The Ethernet address to which the IP is bound. > </column> > </table> > + > + <table name="Config" title="OVN Southbound configuration."> > + Configuration for an OVN Northbound DB. There must be exactly > + one record in the <ref table="Config"/> table. > + > + <group title="Status"> > + <column name="next_cfg"> > + Sequence number copied by <code>ovn-northd</code> from the > + OVN Northbound database when that value changes. > + </column> > + </group> > + </table> > </database> > diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml > index 8375ab7..52b092a 100644 > --- a/ovn/utilities/ovn-nbctl.8.xml > +++ b/ovn/utilities/ovn-nbctl.8.xml > @@ -12,6 +12,35 @@ > <h1>General Commands</h1> > > <dl> > + <dt><code>nop</code></dt> > + <dd> > + <p> > + Implements an empty action. It should be used with the > + <var>--wait</var> to wait for the ovn-controllers to sync up with > + the OVN Northbound DB. > + </p> > + <p> > + The <code>ovn-nbctl</code> utility increments the > <var>next_cfg</var> > + in the <code>Config</code> Table of the OVN Northbound. When > + a <code>ovn-controllers</code> picks up and pends the corresponding > + OpenFlow rules on the hypervisors, it sets its own > + <code>Chassis's</code> <var>cur_cfg</var > to the > <var>next_cfg</var> > + of the OVN Southbound DB, which is essentially a copy of > + <var>next_cfg</var> of the OVN Northbound DB. The > + <code>ovn-northd</code> sets the <var>cur_cfg</var> of in the > + OVN Northbound to the minimum value of <var>cur_cfg</var> > + reported by the <code>Chassis'</code>. > + </p> > + <p> > + The <var>--wait</var> option informs <code>ovn-nbctl</code> to > + wait for <var>cur_cfg</var> to equal <var>next_cfg</var>.It should > + be noted that there may be <code>ovn-nbctl</code> actions that > + modify the OVN Northbound <var>next_cfg</var> but do not result in > + OpenFlow rules. In such cases the <var>cur_cfg</var> > will not equal > + the <var>next_cfg</var> till a future operation updates > the OpenFlow > + rules in the hypervisor. > + </p> > + </dd> > <dt><code>show [<var>lswitch</var>]</code></dt> > <dd> > Prints a brief overview of the database contents. If > diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c > index d267829..fd1620c 100644 > --- a/ovn/utilities/ovn-nbctl.c > +++ b/ovn/utilities/ovn-nbctl.c > @@ -48,6 +48,9 @@ static bool oneline; > /* --dry-run: Do not commit any changes. */ > static bool dry_run; > > +/* --wait: Wait for all ovn-controllers to apply open flow rules. */ > +static bool wait_for_controllers = false; > + > /* --timeout: Time to wait for a connection to 'db'. */ > static int timeout; > > @@ -68,7 +71,7 @@ static const char *nbctl_default_db(void); > static void run_prerequisites(struct ctl_command[], size_t n_commands, > struct ovsdb_idl *); > static bool do_nbctl(const char *args, struct ctl_command *, size_t n, > - struct ovsdb_idl *); > + struct ovsdb_idl *, bool might_write_to_db); > > int > main(int argc, char *argv[]) > @@ -79,6 +82,7 @@ main(int argc, char *argv[]) > unsigned int seqno; > size_t n_commands; > char *args; > + bool might_write_to_db; > > set_program_name(argv[0]); > fatal_ignore_sigpipe(); > @@ -90,8 +94,8 @@ main(int argc, char *argv[]) > > /* Log our arguments. This is often valuable for debugging systems. */ > args = process_escape_args(argv); > - VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG, > - "Called as %s", args); > + might_write_to_db = ctl_might_write_to_db(argv); > + VLOG(might_write_to_db ? VLL_INFO : VLL_DBG, "Called as %s", args); > > /* Parse command line. */ > shash_init(&local_options); > @@ -125,7 +129,8 @@ main(int argc, char *argv[]) > > if (seqno != ovsdb_idl_get_seqno(idl)) { > seqno = ovsdb_idl_get_seqno(idl); > - if (do_nbctl(args, commands, n_commands, idl)) { > + if (do_nbctl(args, commands, n_commands, idl, > + might_write_to_db)) { > free(args); > exit(EXIT_SUCCESS); > } > @@ -157,6 +162,7 @@ parse_options(int argc, char *argv[], struct > shash *local_options) > enum { > OPT_DB = UCHAR_MAX + 1, > OPT_NO_SYSLOG, > + OPT_WAIT, > OPT_DRY_RUN, > OPT_ONELINE, > OPT_LOCAL, > @@ -168,6 +174,7 @@ parse_options(int argc, char *argv[], struct > shash *local_options) > static const struct option global_long_options[] = { > {"db", required_argument, NULL, OPT_DB}, > {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, > + {"wait", optional_argument, NULL, OPT_WAIT}, > {"dry-run", no_argument, NULL, OPT_DRY_RUN}, > {"oneline", no_argument, NULL, OPT_ONELINE}, > {"timeout", required_argument, NULL, 't'}, > @@ -224,6 +231,10 @@ parse_options(int argc, char *argv[], struct > shash *local_options) > vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); > break; > > + case OPT_WAIT: > + wait_for_controllers = true; > + break; > + > case OPT_DRY_RUN: > dry_run = true; > break; > @@ -339,6 +350,7 @@ Options:\n\ > --db=DATABASE connect to DATABASE\n\ > (default: %s)\n\ > -t, --timeout=SECS wait at most SECS seconds\n\ > + --wait wait for ovn-controllers to sync with NB\n \ > --dry-run do not commit changes to database\n\ > --oneline print exactly one line of output per > command\n", > program_name, program_name, ctl_get_db_cmd_usage(), > nbctl_default_db()); > @@ -1162,22 +1174,36 @@ run_prerequisites(struct ctl_command > *commands, size_t n_commands, > > static bool > do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands, > - struct ovsdb_idl *idl) > + struct ovsdb_idl *idl, bool might_write_to_db) > { > struct ovsdb_idl_txn *txn; > + const struct nbrec_config *nb; > enum ovsdb_idl_txn_status status; > struct ovsdb_symbol_table *symtab; > struct ctl_context ctx; > struct ctl_command *c; > struct shash_node *node; > char *error = NULL; > + int64_t next_cfg = 0; > > txn = the_idl_txn = ovsdb_idl_txn_create(idl); > if (dry_run) { > ovsdb_idl_txn_set_dry_run(txn); > } > > - ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args); > + ovsdb_idl_txn_add_comment(txn, "ovn-nbctl: %s", args); > + > + nb = nbrec_config_first(idl); > + if (!nb) { > + /* XXX add verification that table is empty */ > + nb = nbrec_config_insert(txn); > + } > + > + next_cfg = nb->next_cfg; > + if (might_write_to_db) { > + ovsdb_idl_txn_increment(txn, &nb->header_, > + &nbrec_config_col_next_cfg); > + } > > symtab = ovsdb_symbol_table_create(); > for (c = commands; c < &commands[n_commands]; c++) { > @@ -1220,6 +1246,9 @@ do_nbctl(const char *args, struct ctl_command > *commands, size_t n_commands, > } > > status = ovsdb_idl_txn_commit_block(txn); > + if (status == TXN_SUCCESS && might_write_to_db) { > + next_cfg = ovsdb_idl_txn_get_increment_new_value(txn); > + } > if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { > for (c = commands; c < &commands[n_commands]; c++) { > if (c->syntax->postprocess) { > @@ -1296,6 +1325,20 @@ do_nbctl(const char *args, struct ctl_command > *commands, size_t n_commands, > shash_destroy_free_data(&c->options); > } > free(commands); > + > + if (wait_for_controllers) { > + for (;;) { > + ovsdb_idl_run(idl); > + NBREC_CONFIG_FOR_EACH(nb, idl) { > + if (nb->cur_cfg >= next_cfg) { > + goto done; > + } > + } > + ovsdb_idl_wait(idl); > + poll_block(); > + } > + done: ; > + } > ovsdb_idl_txn_destroy(txn); > ovsdb_idl_destroy(idl); > > @@ -1337,6 +1380,7 @@ nbctl_exit(int status) > } > > static const struct ctl_command_syntax nbctl_commands[] = { > + { "nop", 0, 1, "[]", NULL, NULL, NULL, "", RO }, > { "show", 0, 1, "[LSWITCH]", NULL, nbctl_show, NULL, "", RO }, > > /* lswitch commands. */ > diff --git a/tests/ovn.at b/tests/ovn.at > index e6ac1d7..1458134 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -589,8 +589,7 @@ ovn-nbctl acl-add lsw0 to-lport 1000 'eth.type > == 0x1236 && outport == "lp33"' d > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # Given the name of a logical port, prints the name of the hypervisor > # on which it is located. > @@ -762,6 +761,10 @@ done > # set address for lp13 with invalid characters. > # lp13 should be configured with only 192.168.0.13. > ovn-nbctl lport-set-addresses lp13 "f0:00:00:00:00:13 192.168.0.13 > invalid 192.169.0.13" > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +ovn-nbctl --wait nop > + > sip=`ip_to_hex 192 168 0 11` > tip=`ip_to_hex 192 168 0 13` > test_arp 11 f00000000011 $sip $tip f00000000013 > @@ -898,6 +901,9 @@ for i in 1 2; do > done > done > > +# Allow some time for ovn-northd and ovn-controller to catch up. > +ovn-nbctl --wait nop > + > ovn_populate_arp > > # XXX This is now the 3rd copy of these functions in this file ... > @@ -1108,8 +1114,7 @@ ovs-vsctl add-port br-phys vif3 -- set > Interface vif3 options:tx_pcap=hv3/vif3-t > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # test_packet INPORT DST SRC ETHTYPE OUTPORT... > # > @@ -1339,8 +1344,7 @@ done > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT... > # > @@ -1698,8 +1702,7 @@ done > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # Given the name of a logical port, prints the name of the hypervisor > # on which it is located. > @@ -1937,7 +1940,8 @@ done > # configure lport13 to send and received IPv4 packets with an address range > ovn-nbctl lport-set-port-security lp13 "f0:00:00:00:00:13 192.168. > 0.13 20.0.0.4/24 10.0.0.0/24" > > -sleep 2 > +# Allow some time for ovn-northd and ovn-controller to catch up. > +ovn-nbctl --wait nop > > sip=`ip_to_hex 10 0 0 13` > tip=`ip_to_hex 192 168 0 22` > @@ -2130,8 +2134,7 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- \ > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # Send ip packets between the two ports. > ip_to_hex() { > @@ -2262,8 +2265,7 @@ ovs-vsctl -- add-port br-int vif2 -- \ > > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > # Send ip packets between the two ports. > ip_to_hex() { > @@ -2303,6 +2305,9 @@ as hv1 ovs-ofctl dump-flows br-int > #Disable router R1 > ovn-nbctl set Logical_Router R1 enabled=false > > +# Allow some time for ovn-northd and ovn-controller to catch up. > +ovn-nbctl --wait nop > + > echo "---------SB dump-----" > ovn-sbctl list datapath_binding > echo "---------------------" > @@ -2459,8 +2464,7 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- \ > ovn_populate_arp > > # Allow some time for ovn-northd and ovn-controller to catch up. > -# XXX This should be more systematic. > -sleep 1 > +ovn-nbctl --wait nop > > ip_to_hex() { > printf "%02x%02x%02x%02x" "$@" > @@ -2577,6 +2581,9 @@ AT_CHECK([ovn-nbctl lport-set-options ln_port > network_name=physnet1]) > > AT_CHECK([ovs-vsctl add-port br-int localvif1 -- set Interface > localvif1 external_ids:iface-id=localvif1]) > > +# Allow some time for ovn-northd and ovn-controller to catch up. > +ovn-nbctl --wait nop > + > # Wait for packet to be received. > OVS_WAIT_UNTIL([test `wc -c < "hv/snoopvif-tx.pcap"` -ge 50]) > trim_zeros() { > -- > 2.7.4 (Apple Git-66) > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev Other than the above nit, this looks like what I had in mind... Still running through it in some more detail to make sure it handles some of the nastier problems I've seen... Ryan _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev