[ovs-dev] [PATCH v4] OVN: Add support for Transport Zones

Lucas Alvares Gomes lucasagomes at gmail.com
Wed Apr 17 15:49:23 UTC 2019


On Wed, Apr 17, 2019 at 4:46 PM Numan Siddique <nusiddiq at redhat.com> wrote:
>
> On Wed, Apr 17, 2019 at 8:21 PM <lmartins at redhat.com> wrote:
>
> > From: Lucas Alvares Gomes <lucasagomes at gmail.com>
> >
> > This patch is adding support for Transport Zones. Transport zones (a.k.a
> > TZs) is way to enable users of OVN to separate Chassis into different
> > logical groups that will only form tunnels between members of the same
> > groups. Each Chassis can belong to one or more Transport Zones. If
> > not set, the Chassis will be considered part of a default group.
> >
> > Configuring Transport Zones is done by creating a key called
> > "ovn-transport-zones" in the external_ids column of the Open_vSwitch
> > table from the local OVS instance. The value is a string with the name
> > of the Transport Zone that this instance is part of. Multiple TZs can
> > be specified with a comma-separated list. For example:
> >
> > $ sudo ovs-vsctl set open . external-ids:ovn-transport-zones=tz1
> >
> > or
> >
> > $ sudo ovs-vsctl set open . external-ids:ovn-transport-zones=tz1,tz2,tz3
> >
> > This configuration is also exposed in the Chassis table of the OVN
> > Southbound Database in a new column called "transport_zones".
> >
> > The use for Transport Zones includes but are not limited to:
> >
> > * Edge computing: As a way to preventing edge sites from trying to create
> >   tunnels with every node on every other edge site while still allowing
> >   these sites to create tunnels with the central node.
> >
> > * Extra security layer: Where users wants to create "trust zones"
> >   and prevent computes in a more secure zone to communicate with a less
> >   secure zone.
> >
> > This patch is also backward compatible so the upgrade guide for OVN [0]
> > is still valid and the ovn-controller service can be upgraded before the
> > OVSDBs.
> >
> > [0] http://docs.openvswitch.org/en/latest/intro/install/ovn-upgrades/
> >
> > Reported-by: Daniel Alvarez Sanchez <dalvarez at redhat.com>
> > Reported-at:
> > https://mail.openvswitch.org/pipermail/ovs-discuss/2019-February/048255.html
> > Signed-off-by: Lucas Alvares Gomes <lucasagomes at gmail.com>
> > ---
> > v3 -> v4
> >  * Stopped using the "external_ids" column of the Chassis table and
> >    instead added a new column called "transport_zones" to hold the set of
> >    transport zones that the Chassis is part of.
> >
> > v2 -> v3
> >  * Enhanced the test to include two more Chassis and assert the case
> >    where Chassis with no TZs set will have tunnels formed between them.
> >  * Rebased the patch on top of the latest master branch.
> >
> > v1 -> v2
> >
> >  * Rename the function check_chassis_tzones to chassis_tzones_overlap.
> >  * Fix a memory leak in chassis_tzones_overlap.
> >  * Pass the transport_zones to encaps_run() as a "const char *"
> >    instead of "struct sbrec_chassis". With this we can also avoid not
> >    running the function in case the Chassis entry is not yet created.
> >
> >  NEWS                                |   3 +
> >  ovn/controller/chassis.c            |  26 ++++-
> >  ovn/controller/chassis.h            |   4 +-
> >  ovn/controller/encaps.c             |  35 ++++++-
> >  ovn/controller/encaps.h             |   4 +-
> >  ovn/controller/ovn-controller.8.xml |   9 ++
> >  ovn/controller/ovn-controller.c     |  19 +++-
> >  ovn/ovn-sb.ovsschema                |   7 +-
> >  ovn/ovn-sb.xml                      |   8 ++
> >  tests/ovn.at                        | 151 ++++++++++++++++++++++++++++
> >  10 files changed, 257 insertions(+), 9 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index c7440b476..e09f59d64 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -33,6 +33,9 @@ Post-v2.11.0
> >       * Added Policy-based routing(PBR) support to create
> > permit/deny/reroute
> >         policies on the logical router. New table(Logical_Router_Policy)
> > added in
> >         OVN-NB schema. New "ovn-nbctl" commands to add/delete/list PBR
> > policies.
> > +     * Support for Transport Zones, a way to separate chassis into
> > +       logical groups which results in tunnels only been formed between
> > +       members of the same transport zone(s).
> >     - New QoS type "linux-netem" on Linux.
> >     - Added support for TLS Server Name Indication (SNI).
> >
> > diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c
> > index 58d5d49d5..0f537f1f7 100644
> > --- a/ovn/controller/chassis.c
> > +++ b/ovn/controller/chassis.c
> > @@ -19,6 +19,7 @@
> >  #include "chassis.h"
> >
> >  #include "lib/smap.h"
> > +#include "lib/sset.h"
> >  #include "lib/vswitch-idl.h"
> >  #include "openvswitch/dynamic-string.h"
> >  #include "openvswitch/vlog.h"
> > @@ -73,13 +74,34 @@ get_cms_options(const struct smap *ext_ids)
> >      return smap_get_def(ext_ids, "ovn-cms-options", "");
> >  }
> >
> > +static void
> > +update_chassis_transport_zones(const struct sset *transport_zones,
> > +                               const struct sbrec_chassis *chassis_rec)
> > +{
> > +    struct sset chassis_tzones_set =
> > SSET_INITIALIZER(&chassis_tzones_set);
> > +    for (int i = 0; i < chassis_rec->n_transport_zones; i++) {
> > +        sset_add(&chassis_tzones_set, chassis_rec->transport_zones[i]);
> > +    }
> > +
> > +    /* Only update the transport zones if something changed */
> > +    if (!sset_equals(transport_zones, &chassis_tzones_set)) {
> > +        const char **ls_arr = sset_array(transport_zones);
> > +        sbrec_chassis_set_transport_zones(chassis_rec, ls_arr,
> > +                                          sset_count(transport_zones));
> > +        free(ls_arr);
> > +    }
> > +
> > +    sset_destroy(&chassis_tzones_set);
> > +}
> > +
> >  /* Returns this chassis's Chassis record, if it is available. */
> >  const struct sbrec_chassis *
> >  chassis_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> >              struct ovsdb_idl_index *sbrec_chassis_by_name,
> >              const struct ovsrec_open_vswitch_table *ovs_table,
> >              const char *chassis_id,
> > -            const struct ovsrec_bridge *br_int)
> > +            const struct ovsrec_bridge *br_int,
> > +            const struct sset *transport_zones)
> >  {
> >      const struct sbrec_chassis *chassis_rec
> >          = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
> > @@ -157,6 +179,8 @@ chassis_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> >              sbrec_chassis_set_hostname(chassis_rec, hostname);
> >          }
> >
> > +        update_chassis_transport_zones(transport_zones, chassis_rec);
> > +
> >          /* Determine new values for Chassis external-ids. */
> >          const char *chassis_bridge_mappings
> >              = get_bridge_mappings(&chassis_rec->external_ids);
> > diff --git a/ovn/controller/chassis.h b/ovn/controller/chassis.h
> > index 6b1c357d2..9847e19f6 100644
> > --- a/ovn/controller/chassis.h
> > +++ b/ovn/controller/chassis.h
> > @@ -25,13 +25,15 @@ struct ovsrec_bridge;
> >  struct ovsrec_open_vswitch_table;
> >  struct sbrec_chassis;
> >  struct sbrec_chassis_table;
> > +struct sset;
> >
> >  void chassis_register_ovs_idl(struct ovsdb_idl *);
> >  const struct sbrec_chassis *chassis_run(
> >      struct ovsdb_idl_txn *ovnsb_idl_txn,
> >      struct ovsdb_idl_index *sbrec_chassis_by_name,
> >      const struct ovsrec_open_vswitch_table *,
> > -    const char *chassis_id, const struct ovsrec_bridge *br_int);
> > +    const char *chassis_id, const struct ovsrec_bridge *br_int,
> > +    const struct sset *transport_zones);
> >  bool chassis_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn,
> >                       const struct sbrec_chassis *);
> >
> > diff --git a/ovn/controller/encaps.c b/ovn/controller/encaps.c
> > index 610b833de..dcf78108d 100644
> > --- a/ovn/controller/encaps.c
> > +++ b/ovn/controller/encaps.c
> > @@ -195,13 +195,36 @@ chassis_tunnel_add(const struct sbrec_chassis
> > *chassis_rec, const struct sbrec_s
> >      return tuncnt;
> >  }
> >
> > +/*
> > +* Returns true if transport_zones and chassis_rec->transport_zones
> > +* have at least one common transport zone.
> > +*/
> > +static bool
> > +chassis_tzones_overlap(const struct sset *transport_zones,
> > +                       const struct sbrec_chassis *chassis_rec)
> > +{
> > +    /* If neither Chassis belongs to any transport zones, return true to
> > +     * form a tunnel between them */
> > +    if (!chassis_rec->n_transport_zones &&
> > sset_is_empty(transport_zones)) {
> > +        return true;
> > +    }
> > +
> > +    for (int i = 0; i < chassis_rec->n_transport_zones; i++) {
> > +        if (sset_contains(transport_zones,
> > chassis_rec->transport_zones[i])) {
> > +            return true;
> > +        }
> > +    }
> > +    return false;
> > +}
> > +
> >  void
> >  encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
> >             const struct ovsrec_bridge_table *bridge_table,
> >             const struct ovsrec_bridge *br_int,
> >             const struct sbrec_chassis_table *chassis_table,
> >             const char *chassis_id,
> > -           const struct sbrec_sb_global *sbg)
> > +           const struct sbrec_sb_global *sbg,
> > +           const struct sset *transport_zones)
> >  {
> >      if (!ovs_idl_txn || !br_int) {
> >          return;
> > @@ -251,7 +274,15 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
> >
> >      SBREC_CHASSIS_TABLE_FOR_EACH (chassis_rec, chassis_table) {
> >          if (strcmp(chassis_rec->name, chassis_id)) {
> > -            /* Create tunnels to the other chassis. */
> > +            /* Create tunnels to the other Chassis belonging to the
> > +             * same transport zone */
> > +            if (!chassis_tzones_overlap(transport_zones, chassis_rec)) {
> > +                VLOG_DBG("Skipping encap creation for Chassis '%s'
> > because "
> > +                         "it belongs to different transport zones",
> > +                         chassis_rec->name);
> > +                continue;
> > +            }
> > +
> >              if (chassis_tunnel_add(chassis_rec, sbg, &tc) == 0) {
> >                  VLOG_INFO("Creating encap for '%s' failed",
> > chassis_rec->name);
> >                  continue;
> > diff --git a/ovn/controller/encaps.h b/ovn/controller/encaps.h
> > index 3e0e110ef..7ed3e0939 100644
> > --- a/ovn/controller/encaps.h
> > +++ b/ovn/controller/encaps.h
> > @@ -25,6 +25,7 @@ struct ovsrec_bridge_table;
> >  struct sbrec_chassis_table;
> >  struct sbrec_sb_global;
> >  struct ovsrec_open_vswitch_table;
> > +struct sset;
> >
> >  void encaps_register_ovs_idl(struct ovsdb_idl *);
> >  void encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
> > @@ -32,7 +33,8 @@ void encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
> >                  const struct ovsrec_bridge *br_int,
> >                  const struct sbrec_chassis_table *,
> >                  const char *chassis_id,
> > -                const struct sbrec_sb_global *);
> > +                const struct sbrec_sb_global *,
> > +                const struct sset *transport_zones);
> >
> >  bool encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn,
> >                      const struct ovsrec_bridge *br_int);
> > diff --git a/ovn/controller/ovn-controller.8.xml
> > b/ovn/controller/ovn-controller.8.xml
> > index fd2e10a7a..072ec5820 100644
> > --- a/ovn/controller/ovn-controller.8.xml
> > +++ b/ovn/controller/ovn-controller.8.xml
> > @@ -167,6 +167,15 @@
> >          specific to this particular chassis. An example would be:
> >          <code>cms_option1,cms_option2:foo</code>.
> >        </dd>
> > +
> > +      <dt><code>external_ids:ovn-transport-zones</code></dt>
> > +      <dd>
> > +        The transport zone(s) that this chassis belongs to. Transport
> > +        zones is a way to group different chassis so that tunnels are only
> > +        formed between members of the same group(s). Multiple transport
> > +        zones may be specified with a comma-separated list. For example:
> > +        tz1,tz2,tz3.
> > +      </dd>
> >      </dl>
> >
> >      <p>
> > diff --git a/ovn/controller/ovn-controller.c
> > b/ovn/controller/ovn-controller.c
> > index cf4907db3..69eeee5dc 100644
> > --- a/ovn/controller/ovn-controller.c
> > +++ b/ovn/controller/ovn-controller.c
> > @@ -512,6 +512,14 @@ get_nb_cfg(const struct sbrec_sb_global_table
> > *sb_global_table)
> >      return sb ? sb->nb_cfg : 0;
> >  }
> >
> > +static const char *
> > +get_transport_zones(const struct ovsrec_open_vswitch_table *ovs_table)
> > +{
> > +    const struct ovsrec_open_vswitch *cfg
> > +        = ovsrec_open_vswitch_table_first(ovs_table);
> > +    return smap_get_def(&cfg->external_ids, "ovn-transport-zones", "");
> > +}
> > +
> >  static void
> >  ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
> >  {
> > @@ -679,6 +687,11 @@ main(int argc, char *argv[])
> >               * <datapath-tunnel-key>_<port-tunnel-key> */
> >              struct sset local_lport_ids =
> > SSET_INITIALIZER(&local_lport_ids);
> >              struct sset active_tunnels =
> > SSET_INITIALIZER(&active_tunnels);
> > +            /* Contains the transport zones that this Chassis belongs to
> > */
> > +            struct sset transport_zones =
> > SSET_INITIALIZER(&transport_zones);
> > +            sset_from_delimited_string(&transport_zones,
> > +                get_transport_zones(ovsrec_open_vswitch_table_get(
> > +                                    ovs_idl_loop.idl)), ",");
> >
> >              const struct ovsrec_bridge *br_int
> >                  = get_br_int(ovs_idl_txn,
> > @@ -693,12 +706,13 @@ main(int argc, char *argv[])
> >                  chassis = chassis_run(
> >                      ovnsb_idl_txn, sbrec_chassis_by_name,
> >                      ovsrec_open_vswitch_table_get(ovs_idl_loop.idl),
> > -                    chassis_id, br_int);
> > +                    chassis_id, br_int, &transport_zones);
> >                  encaps_run(
> >                      ovs_idl_txn,
> >                      ovsrec_bridge_table_get(ovs_idl_loop.idl), br_int,
> >                      sbrec_chassis_table_get(ovnsb_idl_loop.idl),
> > chassis_id,
> > -                    sbrec_sb_global_first(ovnsb_idl_loop.idl));
> > +                    sbrec_sb_global_first(ovnsb_idl_loop.idl),
> > +                    &transport_zones);
> >
> >                  if (ofctrl_is_connected()) {
> >                      /* Calculate the active tunnels only if have an an
> > active
> > @@ -848,6 +862,7 @@ main(int argc, char *argv[])
> >              sset_destroy(&local_lports);
> >              sset_destroy(&local_lport_ids);
> >              sset_destroy(&active_tunnels);
> > +            sset_destroy(&transport_zones);
> >
> >              struct local_datapath *cur_node, *next_node;
> >              HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node,
> > diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema
> > index d87a02e7b..98007cb6e 100644
> > --- a/ovn/ovn-sb.ovsschema
> > +++ b/ovn/ovn-sb.ovsschema
> > @@ -1,7 +1,7 @@
> >  {
> >      "name": "OVN_Southbound",
> >      "version": "2.2.0",
> >
>
> Since you are adding a new column, can you please bump the version to
> "2.2.1" ?
>

Ah bummer,  I missed it!

Thanks for the review, I will update the version.

> With this change
> Acked-by: Numan Siddique <nusiddiq at redhat.com>
>
> Thanks
> Numan
>
> -    "cksum": "2100715070 17222",
> > +    "cksum": "4060521526 17409",
> >      "tables": {
> >          "SB_Global": {
> >              "columns": {
> > @@ -37,7 +37,10 @@
> >                  "nb_cfg": {"type": {"key": "integer"}},
> >                  "external_ids": {
> >                      "type": {"key": "string", "value": "string",
> > -                             "min": 0, "max": "unlimited"}}},
> > +                             "min": 0, "max": "unlimited"}},
> > +                "transport_zones" : {"type": {"key": "string",
> > +                                              "min": 0,
> > +                                              "max": "unlimited"}}},
> >              "isRoot": true,
> >              "indexes": [["name"]]},
> >          "Encap": {
> > diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
> > index 5c4a852a5..e4ac59f1c 100644
> > --- a/ovn/ovn-sb.xml
> > +++ b/ovn/ovn-sb.xml
> > @@ -293,6 +293,14 @@
> >        See <code>ovn-controller</code>(8) for more information.
> >      </column>
> >
> > +    <column name="transport_zones">
> > +      <code>ovn-controller</code> populates this key with the transport
> > +      zones configured in the <ref table="Open_vSwitch"
> > +      column="external_ids:ovn-transport-zones"/> column of the
> > Open_vSwitch
> > +      database's <ref table="Open_vSwitch" db="Open_vSwitch"/> table.
> > +      See <code>ovn-controller</code>(8) for more information.
> > +    </column>
> > +
> >      <group title="Common Columns">
> >        The overall purpose of these columns is described under <code>Common
> >        Columns</code> at the beginning of this document.
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index b3500e8c9..ad4d23caa 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -13652,3 +13652,154 @@ ovn-nbctl list logical_switch_port
> >  ovn-nbctl list logical_router_port
> >
> >  AT_CLEANUP
> > +
> > +AT_SETUP([ovn -- test transport zones])
> > +ovn_start
> > +
> > +net_add n1
> > +for i in 1 2 3 4 5; do
> > +    sim_add hv$i
> > +    as hv$i
> > +    ovs-vsctl add-br br-phys
> > +    ovn_attach n1 br-phys 192.168.$i.1
> > +done
> > +
> > +dnl Assert that each Chassis has a tunnel formed to every other Chassis
> > +as hv1
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv2
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv3
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv4
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv5
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +]])
> > +
> > +dnl Let's now add some Chassis to different transport zones
> > +dnl * hv1: Will be part of two transport zones: tz1 and tz2 so it
> > +dnl   should have tunnels formed between the other two Chassis (hv2 and
> > hv3)
> > +dnl
> > +dnl * hv2: Will be part of one transport zone: tz1. It should have a
> > tunnel
> > +dnl   to hv1 but not to hv3
> > +dnl
> > +dnl * hv3: Will be part of one transport zone: tz2. It should have a
> > tunnel
> > +dnl   to hv1 but not to hv2
> > +dnl
> > +dnl * hv4 and hv5: Will not have any TZ set so they will keep the tunnels
> > +dnl   between themselves and remove the tunnels to other Chassis which now
> > +dnl   belongs to some TZs
> > +dnl
> > +as hv1
> > +ovs-vsctl set open . external-ids:ovn-transport-zones=tz1,tz2
> > +
> > +as hv2
> > +ovs-vsctl set open . external-ids:ovn-transport-zones=tz1
> > +
> > +as hv3
> > +ovs-vsctl set open . external-ids:ovn-transport-zones=tz2
> > +
> > +as hv1
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv2-0
> > +ovn-hv3-0
> > +]])
> > +
> > +as hv2
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +]])
> > +
> > +as hv3
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +]])
> > +
> > +as hv4
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv5-0
> > +]])
> > +
> > +as hv5
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv4-0
> > +]])
> > +
> > +dnl Removing the transport zones should make all Chassis to create
> > +dnl tunnels between every other Chassis again
> > +for i in 1 2 3; do
> > +    as hv$i
> > +    ovs-vsctl remove open . external-ids ovn-transport-zones
> > +done
> > +
> > +as hv1
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv2
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv3
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv4-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv4
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv5-0
> > +]])
> > +
> > +as hv5
> > +AT_CHECK([ovs-vsctl --bare --columns=name find interface type="geneve" |
> > awk NF | sort], [0],
> > +[[ovn-hv1-0
> > +ovn-hv2-0
> > +ovn-hv3-0
> > +ovn-hv4-0
> > +]])
> > +
> > +OVN_CLEANUP([hv1], [hv2], [hv3])
> > +AT_CLEANUP
> > --
> > 2.21.0
> >
> > _______________________________________________
> > dev mailing list
> > dev at openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev


More information about the dev mailing list