diff mbox series

[ovs-dev,v5] OVN: Add support for Transport Zones

Message ID 20190417155524.17087-1-lmartins@redhat.com
State Superseded
Headers show
Series [ovs-dev,v5] OVN: Add support for Transport Zones | expand

Commit Message

Lucas Martins April 17, 2019, 3:55 p.m. UTC
From: Lucas Alvares Gomes <lucasagomes@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@redhat.com>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2019-February/048255.html
Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
Acked-by: Numan Siddique <nusiddiq@redhat.com>
---
v4 -> v5
 * Bumped the version of the ovn-sb.ovsschema to 2.2.1.

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                |   9 +-
 ovn/ovn-sb.xml                      |   8 ++
 tests/ovn.at                        | 151 ++++++++++++++++++++++++++++
 10 files changed, 258 insertions(+), 10 deletions(-)

Comments

Ben Pfaff April 17, 2019, 5:04 p.m. UTC | #1
On Wed, Apr 17, 2019 at 04:55:24PM +0100, lmartins@redhat.com wrote:
> From: Lucas Alvares Gomes <lucasagomes@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.

[...]

> v4 -> v5
>  * Bumped the version of the ovn-sb.ovsschema to 2.2.1.

The version should become 2.3.0, see ovsdb.7:

    An OVSDB schema also has a version of the form ``x.y.z``
    e.g. ``1.2.3``.  Schemas managed within the Open vSwitch project
    manage version numbering in the following way (but OVSDB does not
    mandate this approach).  Whenever we change the database schema in a
    non-backward compatible way (e.g. when we delete a column or a
    table), we increment <x> and set <y> and <z> to 0.  When we change
    the database schema in a backward compatible way (e.g. when we add a
    new column), we increment <y> and set <z> to 0.  When we change the
    database schema cosmetically (e.g. we reindent its syntax), we
    increment <z>.  The ``ovsdb-tool`` commands ``schema-version`` and
    ``db-version`` extract the schema version from a schema or database
    file, respectively.

But the main issue I see here is that I get a consistent test failure in
the new test:

#                             -*- compilation -*-
2693. ovn.at:13656: testing ovn -- test transport zones ...
creating ovn-sb database
creating ovn-nb database
starting ovn-northd
starting backup ovn-northd
adding simulator 'main'
adding simulator 'hv1'
adding simulator 'hv2'
adding simulator 'hv3'
adding simulator 'hv4'
adding simulator 'hv5'
../../tests/ovn.at:13669: ovs-vsctl --bare --columns=name find interface type="geneve" | awk NF | sort
--- -	2019-04-17 10:02:31.402675315 -0700
+++ /home/blp/nicira/ovs/_build/tests/testsuite.dir/at-groups/2693/stdout	2019-04-17 10:02:31.397247995 -0700
@@ -1,5 +1,4 @@
 ovn-hv2-0
 ovn-hv3-0
 ovn-hv4-0
-ovn-hv5-0
 
2693. ovn.at:13656: 2693. ovn -- test transport zones (ovn.at:13656): FAILED (ovn.at:13669)
Lucas Alvares Gomes April 18, 2019, 10:34 a.m. UTC | #2
Hi,

On Wed, Apr 17, 2019 at 6:04 PM Ben Pfaff <blp@ovn.org> wrote:
>
> On Wed, Apr 17, 2019 at 04:55:24PM +0100, lmartins@redhat.com wrote:
> > From: Lucas Alvares Gomes <lucasagomes@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.
>
> [...]
>
> > v4 -> v5
> >  * Bumped the version of the ovn-sb.ovsschema to 2.2.1.
>
> The version should become 2.3.0, see ovsdb.7:
>
>     An OVSDB schema also has a version of the form ``x.y.z``
>     e.g. ``1.2.3``.  Schemas managed within the Open vSwitch project
>     manage version numbering in the following way (but OVSDB does not
>     mandate this approach).  Whenever we change the database schema in a
>     non-backward compatible way (e.g. when we delete a column or a
>     table), we increment <x> and set <y> and <z> to 0.  When we change
>     the database schema in a backward compatible way (e.g. when we add a
>     new column), we increment <y> and set <z> to 0.  When we change the
>     database schema cosmetically (e.g. we reindent its syntax), we
>     increment <z>.  The ``ovsdb-tool`` commands ``schema-version`` and
>     ``db-version`` extract the schema version from a schema or database
>     file, respectively.
>

Ops my bad, I will bump it to 2.3.0. Thanks for the pointer to the
documentation, it's very helpful.

> But the main issue I see here is that I get a consistent test failure in
> the new test:
>
> #                             -*- compilation -*-
> 2693. ovn.at:13656: testing ovn -- test transport zones ...
> creating ovn-sb database
> creating ovn-nb database
> starting ovn-northd
> starting backup ovn-northd
> adding simulator 'main'
> adding simulator 'hv1'
> adding simulator 'hv2'
> adding simulator 'hv3'
> adding simulator 'hv4'
> adding simulator 'hv5'
> ../../tests/ovn.at:13669: ovs-vsctl --bare --columns=name find interface type="geneve" | awk NF | sort
> --- -   2019-04-17 10:02:31.402675315 -0700
> +++ /home/blp/nicira/ovs/_build/tests/testsuite.dir/at-groups/2693/stdout       2019-04-17 10:02:31.397247995 -0700
> @@ -1,5 +1,4 @@
>  ovn-hv2-0
>  ovn-hv3-0
>  ovn-hv4-0
> -ovn-hv5-0
>
> 2693. ovn.at:13656: 2693. ovn -- test transport zones (ovn.at:13656): FAILED (ovn.at:13669)

Thanks for trying it out.

I'm currently investigating the problem but I could not reproduce it
locally. I did run this test multiple times on different distros
(CentOS 7 [0], Fedora 29 [1] and Ubuntu Bionic [2]) and it's passing
for me. I'm doing the following:

$ make check TESTSUITEFLAGS="--list --keywords=ovn" | grep "transport zones"

Then I use the test number from the previous command and run the test as:

$ make check TESTSUITEFLAGS="--verbose 2693"

I will continue the investigation to see if can find the problem.

Also, mind letting me know how you're executing the tests so I can try
it as well ?

[0] https://pastebin.com/3iSyfivL
[1] https://pastebin.com/hjrpB9eD
[2] https://pastebin.com/t3QG383x

Cheers,
Lucas
Lucas Alvares Gomes April 18, 2019, 12:22 p.m. UTC | #3
On Thu, Apr 18, 2019 at 11:34 AM Lucas Alvares Gomes
<lucasagomes@gmail.com> wrote:
>
> Hi,
>
> On Wed, Apr 17, 2019 at 6:04 PM Ben Pfaff <blp@ovn.org> wrote:
> >
> > On Wed, Apr 17, 2019 at 04:55:24PM +0100, lmartins@redhat.com wrote:
> > > From: Lucas Alvares Gomes <lucasagomes@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.
> >
> > [...]
> >
> > > v4 -> v5
> > >  * Bumped the version of the ovn-sb.ovsschema to 2.2.1.
> >
> > The version should become 2.3.0, see ovsdb.7:
> >
> >     An OVSDB schema also has a version of the form ``x.y.z``
> >     e.g. ``1.2.3``.  Schemas managed within the Open vSwitch project
> >     manage version numbering in the following way (but OVSDB does not
> >     mandate this approach).  Whenever we change the database schema in a
> >     non-backward compatible way (e.g. when we delete a column or a
> >     table), we increment <x> and set <y> and <z> to 0.  When we change
> >     the database schema in a backward compatible way (e.g. when we add a
> >     new column), we increment <y> and set <z> to 0.  When we change the
> >     database schema cosmetically (e.g. we reindent its syntax), we
> >     increment <z>.  The ``ovsdb-tool`` commands ``schema-version`` and
> >     ``db-version`` extract the schema version from a schema or database
> >     file, respectively.
> >
>
> Ops my bad, I will bump it to 2.3.0. Thanks for the pointer to the
> documentation, it's very helpful.
>
> > But the main issue I see here is that I get a consistent test failure in
> > the new test:
> >
> > #                             -*- compilation -*-
> > 2693. ovn.at:13656: testing ovn -- test transport zones ...
> > creating ovn-sb database
> > creating ovn-nb database
> > starting ovn-northd
> > starting backup ovn-northd
> > adding simulator 'main'
> > adding simulator 'hv1'
> > adding simulator 'hv2'
> > adding simulator 'hv3'
> > adding simulator 'hv4'
> > adding simulator 'hv5'
> > ../../tests/ovn.at:13669: ovs-vsctl --bare --columns=name find interface type="geneve" | awk NF | sort
> > --- -   2019-04-17 10:02:31.402675315 -0700
> > +++ /home/blp/nicira/ovs/_build/tests/testsuite.dir/at-groups/2693/stdout       2019-04-17 10:02:31.397247995 -0700
> > @@ -1,5 +1,4 @@
> >  ovn-hv2-0
> >  ovn-hv3-0
> >  ovn-hv4-0
> > -ovn-hv5-0
> >
> > 2693. ovn.at:13656: 2693. ovn -- test transport zones (ovn.at:13656): FAILED (ovn.at:13669)
>
> Thanks for trying it out.
>
> I'm currently investigating the problem but I could not reproduce it
> locally. I did run this test multiple times on different distros
> (CentOS 7 [0], Fedora 29 [1] and Ubuntu Bionic [2]) and it's passing
> for me. I'm doing the following:
>
> $ make check TESTSUITEFLAGS="--list --keywords=ovn" | grep "transport zones"
>
> Then I use the test number from the previous command and run the test as:
>
> $ make check TESTSUITEFLAGS="--verbose 2693"
>
> I will continue the investigation to see if can find the problem.
>
> Also, mind letting me know how you're executing the tests so I can try
> it as well ?
>

Update: I was able to reproduce the problem by stressing all CPUs in
the background and running that test.

I will work on a fix for the problem and upload a new version of the
patch with the version and test fixed.

Thanks Ben for finding the problem in the first place.

[0] https://pastebin.com/zPrPVGd7

Cheers,
Lucas
Ben Pfaff April 18, 2019, 2:20 p.m. UTC | #4
On Thu, Apr 18, 2019 at 11:34:03AM +0100, Lucas Alvares Gomes wrote:
> > But the main issue I see here is that I get a consistent test failure in
> > the new test:
> >
> > 2693. ovn.at:13656: testing ovn -- test transport zones ...
> 
> Thanks for trying it out.
> 
> I'm currently investigating the problem but I could not reproduce it
> locally. I did run this test multiple times on different distros
> (CentOS 7 [0], Fedora 29 [1] and Ubuntu Bionic [2]) and it's passing
> for me. I'm doing the following:
> 
> $ make check TESTSUITEFLAGS="--list --keywords=ovn" | grep "transport zones"
> 
> Then I use the test number from the previous command and run the test as:
> 
> $ make check TESTSUITEFLAGS="--verbose 2693"

It should not be necessary to use two steps.  I would expect
    make check TESTSUITEFLAGS='-k transport,zones'
to be sufficient.

> I will continue the investigation to see if can find the problem.
> 
> Also, mind letting me know how you're executing the tests so I can try
> it as well ?

Usually, for ovn, I run
    make -j10 check TESTSUITEFLAGS='-j10 -k ovn'
and then if necessary I investigate and possibly rerun failing tests.
I'm running them on my laptop, which is a fairly up-to-date Debian
"buster" (currently being tested for release) with x86-64 kernel and
userspace.
Ben Pfaff April 18, 2019, 2:23 p.m. UTC | #5
On Thu, Apr 18, 2019 at 01:22:35PM +0100, Lucas Alvares Gomes wrote:
> Update: I was able to reproduce the problem by stressing all CPUs in
> the background and running that test.

I'm a little surprised that stress was necessary; I was running this on
an unloaded system.  But the fix is great regardless!
diff mbox series

Patch

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..e6401c83f 100644
--- a/ovn/ovn-sb.ovsschema
+++ b/ovn/ovn-sb.ovsschema
@@ -1,7 +1,7 @@ 
 {
     "name": "OVN_Southbound",
-    "version": "2.2.0",
-    "cksum": "2100715070 17222",
+    "version": "2.2.1",
+    "cksum": "1575754731 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