diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index a173a1d..cf9bf96 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -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
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 3873665..174847d 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -875,6 +875,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);
 }
diff --git a/ovn-nb.xml b/ovn-nb.xml
index ca0b2ee..8ddba22 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -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.
diff --git a/ovn-sb.xml b/ovn-sb.xml
index e5fb51a..471310d 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -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
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 1e69820..7e6644d 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -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
