"dev" <dev-boun...@openvswitch.org> wrote on 05/23/2016 10:34:48 AM:

> From: Ryan Moats/Omaha/IBM@IBMUS
> To: Amitabha Biswas/San Jose/IBM@IBMUS
> Cc: dev@openvswitch.org
> Date: 05/23/2016 10:35 AM
> Subject: Re: [ovs-dev] [v1 1/1] Fix "raceful" E2E ovn tests
> Sent by: "dev" <dev-boun...@openvswitch.org>

>
>
>
> "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...

Well, I'm going to stand corrected - I've run this through a bunch
of different scenarios, and it's not up to snuff - I'm still seeing
race conditions when running the following test cases:

3HVs, 1LS, 3 lports/HV
portsecurity: 3 HVs, 1 LS, 3 lports/HV
2 HVs, 2 LS, 1 lport/LS, 2 peer LRs
2 HVs, 3 LS, 1 lport/LS, 2 peer LRs, static routes

So, I think we are going to have to go back to the drawing board
some more...

Ryan
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to