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

Numan Siddique nusiddiq at redhat.com
Wed Apr 17 15:45:33 UTC 2019


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

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
>


More information about the dev mailing list