@@ -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).
@@ -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);
@@ -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 *);
@@ -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;
@@ -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);
@@ -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>
@@ -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,
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
- "version": "2.2.0",
- "cksum": "2100715070 17222",
+ "version": "2.3.0",
+ "cksum": "3092285199 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": {
@@ -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.
@@ -13652,3 +13652,166 @@ 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 Wait for the changes to be propagated
+ovn-nbctl --wait=sb --timeout=3 sync
+ovn-nbctl --wait=hv --timeout=3 sync
+
+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
+
+dnl Wait for the changes to be propagated
+ovn-nbctl --wait=sb --timeout=3 sync
+ovn-nbctl --wait=hv --timeout=3 sync
+
+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
+
+dnl Wait for the changes to be propagated
+ovn-nbctl --wait=sb --timeout=3 sync
+ovn-nbctl --wait=hv --timeout=3 sync
+
+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