@@ -139,11 +139,124 @@ az_run(struct ic_context *ctx)
return NULL;
}
+static uint32_t
+allocate_ts_dp_key(struct hmap *dp_tnlids)
+{
+ static uint32_t hint = OVN_MIN_DP_KEY_GLOBAL;
+ return ovn_allocate_tnlid(dp_tnlids, "transit switch datapath",
+ OVN_MIN_DP_KEY_GLOBAL, OVN_MAX_DP_KEY_GLOBAL,
+ &hint);
+}
+
+static void
+ts_run(struct ic_context *ctx)
+{
+ const struct inbrec_transit_switch *ts;
+
+ /* Sync INB TS to AZ NB */
+ if (ctx->ovnnb_txn) {
+ struct shash nb_tses = SHASH_INITIALIZER(&nb_tses);
+ const struct nbrec_logical_switch *ls;
+
+ /* Get current NB Logical_Switch with other_config:interconn-ts */
+ NBREC_LOGICAL_SWITCH_FOR_EACH (ls, ctx->ovnnb_idl) {
+ const char *ts_name = smap_get(&ls->other_config, "interconn-ts");
+ if (ts_name) {
+ shash_add(&nb_tses, ts_name, ls);
+ }
+ }
+
+ /* Create NB Logical_Switch for each TS */
+ INBREC_TRANSIT_SWITCH_FOR_EACH (ts, ctx->ovninb_idl) {
+ ls = shash_find_and_delete(&nb_tses, ts->name);
+ if (!ls) {
+ ls = nbrec_logical_switch_insert(ctx->ovnnb_txn);
+ nbrec_logical_switch_set_name(ls, ts->name);
+ nbrec_logical_switch_update_other_config_setkey(ls,
+ "interconn-ts",
+ ts->name);
+ }
+ }
+
+ /* Delete extra NB Logical_Switch with other_config:interconn-ts */
+ struct shash_node *node;
+ SHASH_FOR_EACH (node, &nb_tses) {
+ nbrec_logical_switch_delete(node->data);
+ }
+ shash_destroy(&nb_tses);
+ }
+
+ struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids);
+ struct shash isb_dps = SHASH_INITIALIZER(&isb_dps);
+ const struct isbrec_datapath_binding *isb_dp;
+ ISBREC_DATAPATH_BINDING_FOR_EACH (isb_dp, ctx->ovnisb_idl) {
+ shash_add(&isb_dps, isb_dp->transit_switch, isb_dp);
+ ovn_add_tnlid(&dp_tnlids, isb_dp->tunnel_key);
+ }
+
+ /* Sync ISB TS tunnel key to AZ SB datapath. (AZ SB datapath is created by
+ * northd.) */
+ if (ctx->ovnsb_txn) {
+ const struct sbrec_datapath_binding *sb_dp;
+ SBREC_DATAPATH_BINDING_FOR_EACH (sb_dp, ctx->ovnsb_idl) {
+ const char *ts_name = smap_get(&sb_dp->external_ids,
+ "interconn-ts");
+ if (ts_name) {
+ isb_dp = shash_find_data(&isb_dps, ts_name);
+ if (!isb_dp) {
+ VLOG_DBG("SB datapath "UUID_FMT" with interconn-ts %s not "
+ "found in ISB, ignore.",
+ UUID_ARGS(&sb_dp->header_.uuid),
+ ts_name);
+ continue;
+ }
+ sbrec_datapath_binding_set_tunnel_key(sb_dp,
+ isb_dp->tunnel_key);
+ }
+ }
+ }
+
+ /* Sync TS between INB and ISB. This is performed after syncing with AZ
+ * SB, to avoid uncommitted ISB datapath tunnel key to be synced back to
+ * AZ. */
+ if (ctx->ovnisb_txn) {
+ /* Create ISB Datapath_Binding */
+ INBREC_TRANSIT_SWITCH_FOR_EACH (ts, ctx->ovninb_idl) {
+ isb_dp = shash_find_and_delete(&isb_dps, ts->name);
+ if (!isb_dp) {
+ /* Allocate tunnel key */
+ int64_t dp_key = allocate_ts_dp_key(&dp_tnlids);
+ if (!dp_key) {
+ continue;
+ }
+
+ isb_dp = isbrec_datapath_binding_insert(ctx->ovnisb_txn);
+ isbrec_datapath_binding_set_transit_switch(isb_dp, ts->name);
+ isbrec_datapath_binding_set_tunnel_key(isb_dp, dp_key);
+ }
+ }
+
+ /* Delete extra ISB Datapath_Binding */
+ struct shash_node *node;
+ SHASH_FOR_EACH (node, &isb_dps) {
+ isbrec_datapath_binding_delete(node->data);
+ }
+ }
+ ovn_destroy_tnlids(&dp_tnlids);
+ shash_destroy(&isb_dps);
+}
+
static void
ovn_db_run(struct ic_context *ctx)
{
const struct isbrec_availability_zone *az = az_run(ctx);
VLOG_DBG("Availability zone: %s", az ? az->name : "not created yet.");
+
+ if (!az) {
+ return;
+ }
+
+ ts_run(ctx);
}
static void
@@ -866,6 +866,14 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od)
if (name2 && name2[0]) {
smap_add(&ids, "name2", name2);
}
+
+ /* Set interconn-ts. */
+ if (od->nbs) {
+ const char *ts = smap_get(&od->nbs->other_config, "interconn-ts");
+ if (ts) {
+ smap_add(&ids, "interconn-ts", ts);
+ }
+ }
sbrec_datapath_binding_set_external_ids(od->sb, &ids);
smap_destroy(&ids);
}
@@ -354,6 +354,16 @@
</column>
</group>
+ <group title="Interconnection">
+ <column name="other_config" key="interconn-ts"
+ type='{"type": "string"}'>
+ The <ref table="Transit_Switch" column="name" db="OVN_IC_Northbound"/>
+ of corresponding transit switch in <ref db="OVN_IC_Northbound"/>
+ database. This kind of logical switch is created and controlled
+ by <code>ovn-ic</code>.
+ </column>
+ </group>
+
<group title="Common Columns">
<column name="external_ids">
See <em>External IDs</em> at the beginning of this document.
@@ -2291,6 +2291,15 @@ tcp.flags = RST;
the <ref db="OVN_Northbound"/> database.
</column>
+ <column name="external_ids" key="interconn-ts" type='{"type": "string"}'>
+ For a logical datapath that represents a logical switch that represents
+ a transit switch for interconnection, <code>ovn-northd</code> stores in
+ this key the value of the same <code>interconn-ts</code> key of the <ref
+ column="external_ids" table="Logical_Switch" db="OVN_Northbound"/>
+ column of the corresponding <ref table="Logical_Switch"
+ db="OVN_Northbound"/> row in the <ref db="OVN_Northbound"/> database.
+ </column>
+
<group title="Naming">
<p>
<code>ovn-northd</code> copies these from the name fields in the <ref
@@ -27,3 +27,44 @@ availability-zone az3
OVN_CLEANUP_IC([az1], [az2])
AT_CLEANUP
+
+AT_SETUP([ovn-ic -- transit switch handling])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+
+ovn_init_ic_db
+ovn_start az1
+
+AT_CHECK([ovn-inbctl ts-add ts1])
+AT_CHECK([ovn-inbctl ts-add ts2])
+
+# Check ISB
+OVS_WAIT_UNTIL([ovn-isbctl list datapath | grep ts2])
+AT_CHECK([ovn-isbctl -f csv -d bare --no-headings --columns transit_switch list datapath | sort], [0], [dnl
+ts1
+ts2
+])
+
+# Check NB
+AT_CHECK([ovn-nbctl -f csv -d bare --no-headings --columns name list logical_switch | sort], [0], [dnl
+ts1
+ts2
+])
+
+# Check SB DP key
+ts1_key=$(ovn-isbctl -f csv -d bare --no-headings --columns tunnel_key find datapath transit_switch=ts1)
+sb_ts1_key=$(ovn-sbctl -f csv -d bare --no-headings --columns tunnel_key find datapath_binding external_ids:interconn-ts=ts1)
+AT_CHECK([test $ts1_key = $sb_ts1_key])
+
+# Test delete
+AT_CHECK([ovn-inbctl ts-del ts1])
+OVS_WAIT_WHILE([ovn-isbctl list datapath | grep ts1])
+AT_CHECK([ovn-isbctl -f csv -d bare --no-headings --columns transit_switch list datapath], [0], [dnl
+ts2
+])
+AT_CHECK([ovn-nbctl -f csv -d bare --no-headings --columns name list logical_switch | sort], [0], [dnl
+ts2
+])
+
+OVN_CLEANUP_IC([az1])
+
+AT_CLEANUP
Processing transit switches and sync between INB, ISB and NB. Signed-off-by: Han Zhou <hzhou@ovn.org> --- ic/ovn-ic.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++ northd/ovn-northd.c | 8 ++++ ovn-nb.xml | 10 +++++ ovn-sb.xml | 9 +++++ tests/ovn-ic.at | 41 +++++++++++++++++++ 5 files changed, 181 insertions(+)