diff --git a/NEWS b/NEWS
index 5e93f813a..dcb70f944 100644
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,10 @@ OVN v21.09.0 - xx xxx xxxx
   - Allow static routes without nexthops.
   - Enabled logical dp groups as a default.  CMS should disable it if not
     desired.
+  - Added support for multiple routing tables in Logical Router Static Routes
+    and LRPs. OVN Interconnection supports routes' route tables as well.
+    This requires to update schemas for OVN_Northdbound and OVN_IC_Southbound
+    DBs.
 
 OVN v21.06.0 - 18 Jun 2021
 -------------------------
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 303e93a4f..02bd28b2b 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -63,9 +63,11 @@ struct ic_context {
     struct ovsdb_idl_txn *ovninb_txn;
     struct ovsdb_idl_txn *ovnisb_txn;
     struct ovsdb_idl_index *nbrec_ls_by_name;
+    struct ovsdb_idl_index *nbrec_lrp_by_name;
     struct ovsdb_idl_index *nbrec_port_by_name;
     struct ovsdb_idl_index *sbrec_chassis_by_name;
     struct ovsdb_idl_index *sbrec_port_binding_by_name;
+    struct ovsdb_idl_index *icnbrec_transit_switch_by_name;
     struct ovsdb_idl_index *icsbrec_port_binding_by_az;
     struct ovsdb_idl_index *icsbrec_port_binding_by_ts;
     struct ovsdb_idl_index *icsbrec_port_binding_by_ts_az;
@@ -773,7 +775,7 @@ port_binding_run(struct ic_context *ctx,
         icsbrec_port_binding_index_set_transit_switch(isb_pb_key, ts->name);
 
         ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
-                                            ctx->icsbrec_port_binding_by_ts) {
+                                             ctx->icsbrec_port_binding_by_ts) {
             if (isb_pb->availability_zone == az) {
                 shash_add(&local_pbs, isb_pb->logical_port, isb_pb);
                 shash_find_and_delete(&isb_all_local_pbs,
@@ -844,7 +846,9 @@ port_binding_run(struct ic_context *ctx,
 struct ic_router_info {
     struct hmap_node node;
     const struct nbrec_logical_router *lr; /* key of hmap */
-    const struct icsbrec_port_binding *isb_pb;
+    const struct icsbrec_port_binding **isb_pbs;
+    size_t n_isb_pbs;
+    size_t n_allocated_isb_pbs;
     struct hmap routes_learned;
 };
 
@@ -854,6 +858,7 @@ struct ic_route_info {
     struct in6_addr prefix;
     unsigned int plen;
     struct in6_addr nexthop;
+    const char *route_table;
 
     /* Either nb_route or nb_lrp is set and the other one must be NULL.
      * - For a route that is learned from IC-SB, or a static route that is
@@ -875,13 +880,15 @@ ic_route_hash(const struct in6_addr *prefix, unsigned int plen,
 
 static struct ic_route_info *
 ic_route_find(struct hmap *routes, const struct in6_addr *prefix,
-              unsigned int plen, const struct in6_addr *nexthop)
+              unsigned int plen, const struct in6_addr *nexthop,
+              char *route_table)
 {
     struct ic_route_info *r;
     uint32_t hash = ic_route_hash(prefix, plen, nexthop);
     HMAP_FOR_EACH_WITH_HASH (r, node, hash, routes) {
         if (ipv6_addr_equals(&r->prefix, prefix) &&
             r->plen == plen &&
+            !strcmp(r->route_table ? r->route_table : "", route_table) &&
             ipv6_addr_equals(&r->nexthop, nexthop)) {
             return r;
         }
@@ -926,11 +933,19 @@ add_to_routes_learned(struct hmap *routes_learned,
                      &prefix, &plen, &nexthop)) {
         return false;
     }
+
+    if (ic_route_find(routes_learned, &prefix, plen, &nexthop,
+                      nb_route->route_table)) {
+        /* Route is already added to learned in previous iteration. */
+        return true;
+    }
+
     struct ic_route_info *ic_route = xzalloc(sizeof *ic_route);
     ic_route->prefix = prefix;
     ic_route->plen = plen;
     ic_route->nexthop = nexthop;
     ic_route->nb_route = nb_route;
+    ic_route->route_table = nb_route->route_table;
     hmap_insert(routes_learned, &ic_route->node,
                 ic_route_hash(&prefix, plen, &nexthop));
     return true;
@@ -1069,8 +1084,17 @@ static void
 add_to_routes_ad(struct hmap *routes_ad,
                  const struct nbrec_logical_router_static_route *nb_route,
                  const struct lport_addresses *nexthop_addresses,
-                 const struct smap *nb_options)
+                 const struct smap *nb_options, const char *route_table)
 {
+    if (strcmp(route_table, nb_route->route_table)) {
+        if (VLOG_IS_DBG_ENABLED()) {
+            VLOG_DBG("Skip advertising route %s -> %s as its route table %s !="
+                     " %s of TS port", nb_route->ip_prefix, nb_route->nexthop,
+                     nb_route->route_table, route_table);
+        }
+        return;
+    }
+
     struct in6_addr prefix, nexthop;
     unsigned int plen;
     if (!parse_route(nb_route->ip_prefix, nb_route->nexthop,
@@ -1088,11 +1112,33 @@ add_to_routes_ad(struct hmap *routes_ad,
         return;
     }
 
+    if (VLOG_IS_DBG_ENABLED()) {
+        struct ds msg = DS_EMPTY_INITIALIZER;
+
+        ds_put_format(&msg, "Advertising static route: %s -> %s, ic nexthop: ",
+                      nb_route->ip_prefix, nb_route->nexthop);
+
+        if (IN6_IS_ADDR_V4MAPPED(&nexthop)) {
+            ds_put_format(&msg, IP_FMT,
+                          IP_ARGS(in6_addr_get_mapped_ipv4(&nexthop)));
+        } else {
+            ipv6_format_addr(&nexthop, &msg);
+        }
+
+        ds_put_format(&msg, ", route_table: %s", strlen(nb_route->route_table)
+                                                 ? nb_route->route_table
+                                                 : "global");
+
+        VLOG_DBG("%s", ds_cstr(&msg));
+        ds_destroy(&msg);
+    }
+
     struct ic_route_info *ic_route = xzalloc(sizeof *ic_route);
     ic_route->prefix = prefix;
     ic_route->plen = plen;
     ic_route->nexthop = nexthop;
     ic_route->nb_route = nb_route;
+    ic_route->route_table = nb_route->route_table;
     hmap_insert(routes_ad, &ic_route->node,
                 ic_route_hash(&prefix, plen, &nexthop));
 }
@@ -1124,8 +1170,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
     if (VLOG_IS_DBG_ENABLED()) {
         struct ds msg = DS_EMPTY_INITIALIZER;
 
-        ds_put_format(&msg, "Route ad: direct network %s of lrp %s, nexthop ",
-                      network, nb_lrp->name);
+        ds_put_format(&msg, "Adding direct network route to global routing "
+                      "table: %s of lrp %s, nexthop ", network, nb_lrp->name);
 
         if (IN6_IS_ADDR_V4MAPPED(&nexthop)) {
             ds_put_format(&msg, IP_FMT,
@@ -1143,13 +1189,15 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
     ic_route->plen = plen;
     ic_route->nexthop = nexthop;
     ic_route->nb_lrp = nb_lrp;
+
+    /* directly-connected routes go to global route table */
+    ic_route->route_table = NULL;
     hmap_insert(routes_ad, &ic_route->node,
                 ic_route_hash(&prefix, plen, &nexthop));
 }
 
 static bool
-route_need_learn(struct in6_addr *prefix,
-                 unsigned int plen,
+route_need_learn(struct in6_addr *prefix, unsigned int plen,
                  const struct smap *nb_options)
 {
     if (!smap_get_bool(nb_options, "ic-route-learn", false)) {
@@ -1172,73 +1220,149 @@ route_need_learn(struct in6_addr *prefix,
     return true;
 }
 
+static const char *
+get_lrp_name_by_ts_port_name(struct ic_context *ctx, const char *ts_port_name)
+{
+    const struct nbrec_logical_switch_port *nb_lsp;
+    const struct nbrec_logical_switch_port *nb_lsp_key =
+        nbrec_logical_switch_port_index_init_row(ctx->nbrec_port_by_name);
+    nbrec_logical_switch_port_index_set_name(nb_lsp_key, ts_port_name);
+    nb_lsp = nbrec_logical_switch_port_index_find(ctx->nbrec_port_by_name,
+                                                  nb_lsp_key);
+    nbrec_logical_switch_port_index_destroy_row(nb_lsp_key);
+
+    if (!nb_lsp) {
+        return NULL;
+    }
+
+    return smap_get(&nb_lsp->options, "router-port");
+}
+
+static const char *
+get_route_table_by_lrp_name(struct ic_context *ctx, const char *lrp_name)
+{
+    const struct nbrec_logical_router_port *lrp;
+    const struct nbrec_logical_router_port *lrp_key =
+        nbrec_logical_router_port_index_init_row(ctx->nbrec_lrp_by_name);
+    nbrec_logical_router_port_index_set_name(lrp_key, lrp_name);
+    lrp = nbrec_logical_router_port_index_find(ctx->nbrec_lrp_by_name,
+                                               lrp_key);
+    nbrec_logical_router_port_index_destroy_row(lrp_key);
+
+    if (lrp) {
+        return smap_get_def(&lrp->options, "route_table", "");
+    }
+    return "";  /* Global route table */
+}
+
+static bool
+lrp_is_ts_port(struct ic_context *ctx, struct ic_router_info *ic_lr,
+               const char *lrp_name)
+{
+    const struct icsbrec_port_binding *isb_pb;
+    const char *ts_lrp_name;
+    for (int i = 0; i < ic_lr->n_isb_pbs; i++) {
+        isb_pb = ic_lr->isb_pbs[i];
+        ts_lrp_name = get_lrp_name_by_ts_port_name(ctx, isb_pb->logical_port);
+        if (!strcmp(ts_lrp_name, lrp_name)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 static void
-sync_learned_route(struct ic_context *ctx,
-                   const struct icsbrec_availability_zone *az,
-                   struct ic_router_info *ic_lr)
+sync_learned_routes(struct ic_context *ctx,
+                    const struct icsbrec_availability_zone *az,
+                    struct ic_router_info *ic_lr)
 {
     ovs_assert(ctx->ovnnb_txn);
-    const struct icsbrec_route *isb_route;
-    const struct icsbrec_route *isb_route_key =
-        icsbrec_route_index_init_row(ctx->icsbrec_route_by_ts);
+    const struct icsbrec_route *isb_route, *isb_route_key;
 
-    icsbrec_route_index_set_transit_switch(isb_route_key,
-                                           ic_lr->isb_pb->transit_switch);
+    const struct nbrec_nb_global *nb_global =
+        nbrec_nb_global_first(ctx->ovnnb_idl);
+    ovs_assert(nb_global);
 
-    ICSBREC_ROUTE_FOR_EACH_EQUAL (isb_route, isb_route_key,
-                                  ctx->icsbrec_route_by_ts) {
-        if (isb_route->availability_zone == az) {
-            continue;
-        }
-        struct in6_addr prefix, nexthop;
-        unsigned int plen;
-        if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
-                         &prefix, &plen, &nexthop)) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-            VLOG_WARN_RL(&rl, "Bad route format in IC-SB: %s -> %s. Ignored.",
-                         isb_route->ip_prefix, isb_route->nexthop);
-            continue;
-        }
-        const struct nbrec_nb_global *nb_global =
-            nbrec_nb_global_first(ctx->ovnnb_idl);
-        ovs_assert(nb_global);
-        if (!route_need_learn(&prefix, plen, &nb_global->options)) {
-            continue;
-        }
-        struct ic_route_info *route_learned
-            = ic_route_find(&ic_lr->routes_learned, &prefix, plen, &nexthop);
-        if (route_learned) {
-            /* Sync external-ids */
-            struct uuid ext_id;
-            smap_get_uuid(&route_learned->nb_route->external_ids,
-                          "ic-learned-route", &ext_id);
-            if (!uuid_equals(&ext_id, &isb_route->header_.uuid)) {
+    const char *lrp_name, *ts_route_table;
+    const struct icsbrec_port_binding *isb_pb;
+    for (int i = 0; i < ic_lr->n_isb_pbs; i++) {
+        isb_pb = ic_lr->isb_pbs[i];
+        lrp_name = get_lrp_name_by_ts_port_name(ctx, isb_pb->logical_port);
+        ts_route_table = get_route_table_by_lrp_name(ctx, lrp_name);
+
+        isb_route_key = icsbrec_route_index_init_row(ctx->icsbrec_route_by_ts);
+        icsbrec_route_index_set_transit_switch(isb_route_key,
+                                               isb_pb->transit_switch);
+
+        ICSBREC_ROUTE_FOR_EACH_EQUAL (isb_route, isb_route_key,
+                                      ctx->icsbrec_route_by_ts) {
+            if (isb_route->availability_zone == az) {
+                continue;
+            }
+
+            if (strlen(isb_route->route_table) &&
+                strcmp(isb_route->route_table, ts_route_table)) {
+                if (VLOG_IS_DBG_ENABLED()) {
+                    VLOG_DBG("Skip learning static route %s -> %s as either "
+                             "its route table %s != %s of TS port or ",
+                             isb_route->ip_prefix, isb_route->nexthop,
+                             isb_route->route_table, ts_route_table);
+                }
+                continue;
+            }
+
+            struct in6_addr prefix, nexthop;
+            unsigned int plen;
+            if (!parse_route(isb_route->ip_prefix, isb_route->nexthop,
+                             &prefix, &plen, &nexthop)) {
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+                VLOG_WARN_RL(&rl, "Bad route format in IC-SB: %s -> %s. "
+                             "Ignored.", isb_route->ip_prefix,
+                             isb_route->nexthop);
+                continue;
+            }
+            if (!route_need_learn(&prefix, plen, &nb_global->options)) {
+                continue;
+            }
+            struct ic_route_info *route_learned
+                = ic_route_find(&ic_lr->routes_learned, &prefix, plen,
+                                &nexthop, isb_route->route_table);
+            if (route_learned) {
+                /* Sync external-ids */
+                struct uuid ext_id;
+                smap_get_uuid(&route_learned->nb_route->external_ids,
+                              "ic-learned-route", &ext_id);
+                if (!uuid_equals(&ext_id, &isb_route->header_.uuid)) {
+                    char *uuid_s =
+                        xasprintf(UUID_FMT,
+                                  UUID_ARGS(&isb_route->header_.uuid));
+                    nbrec_logical_router_static_route_update_external_ids_setkey(
+                        route_learned->nb_route, "ic-learned-route", uuid_s);
+                    free(uuid_s);
+                }
+                hmap_remove(&ic_lr->routes_learned, &route_learned->node);
+                free(route_learned);
+            } else {
+                /* Create the missing route in NB. */
+                const struct nbrec_logical_router_static_route *nb_route =
+                    nbrec_logical_router_static_route_insert(ctx->ovnnb_txn);
+                nbrec_logical_router_static_route_set_ip_prefix(nb_route,
+                    isb_route->ip_prefix);
+                nbrec_logical_router_static_route_set_nexthop(nb_route,
+                    isb_route->nexthop);
                 char *uuid_s = xasprintf(UUID_FMT,
                                          UUID_ARGS(&isb_route->header_.uuid));
+                nbrec_logical_router_static_route_set_route_table(nb_route,
+                    isb_route->route_table);
                 nbrec_logical_router_static_route_update_external_ids_setkey(
-                    route_learned->nb_route, "ic-learned-route", uuid_s);
+                    nb_route, "ic-learned-route", uuid_s);
                 free(uuid_s);
+                nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,
+                    nb_route);
             }
-            hmap_remove(&ic_lr->routes_learned, &route_learned->node);
-            free(route_learned);
-        } else {
-            /* Create the missing route in NB. */
-            const struct nbrec_logical_router_static_route *nb_route =
-                nbrec_logical_router_static_route_insert(ctx->ovnnb_txn);
-            nbrec_logical_router_static_route_set_ip_prefix(
-                nb_route, isb_route->ip_prefix);
-            nbrec_logical_router_static_route_set_nexthop(
-                nb_route, isb_route->nexthop);
-            char *uuid_s = xasprintf(UUID_FMT,
-                                     UUID_ARGS(&isb_route->header_.uuid));
-            nbrec_logical_router_static_route_update_external_ids_setkey(
-                nb_route, "ic-learned-route", uuid_s);
-            free(uuid_s);
-            nbrec_logical_router_update_static_routes_addvalue(
-                ic_lr->lr, nb_route);
         }
+        icsbrec_route_index_destroy_row(isb_route_key);
     }
-    icsbrec_route_index_destroy_row(isb_route_key);
 
     /* Delete extra learned routes. */
     struct ic_route_info *route_learned, *next;
@@ -1271,10 +1395,10 @@ ad_route_sync_external_ids(const struct ic_route_info *route_adv,
 
 /* Sync routes from routes_ad to IC-SB. */
 static void
-advertise_route(struct ic_context *ctx,
-                const struct icsbrec_availability_zone *az,
-                const char *ts_name,
-                struct hmap *routes_ad)
+advertise_routes(struct ic_context *ctx,
+                 const struct icsbrec_availability_zone *az,
+                 const char *ts_name,
+                 struct hmap *routes_ad)
 {
     ovs_assert(ctx->ovnisb_txn);
     const struct icsbrec_route *isb_route;
@@ -1298,7 +1422,8 @@ advertise_route(struct ic_context *ctx,
             continue;
         }
         struct ic_route_info *route_adv =
-            ic_route_find(routes_ad, &prefix, plen, &nexthop);
+            ic_route_find(routes_ad, &prefix, plen, &nexthop,
+                          isb_route->route_table);
         if (!route_adv) {
             /* Delete the extra route from IC-SB. */
             VLOG_DBG("Delete route %s -> %s from IC-SB, which is not found"
@@ -1338,6 +1463,9 @@ advertise_route(struct ic_context *ctx,
         }
         icsbrec_route_set_ip_prefix(isb_route, prefix_s);
         icsbrec_route_set_nexthop(isb_route, nexthop_s);
+        icsbrec_route_set_route_table(isb_route, route_adv->route_table
+                                                 ? route_adv->route_table
+                                                 : "");
         free(prefix_s);
         free(nexthop_s);
 
@@ -1348,23 +1476,97 @@ advertise_route(struct ic_context *ctx,
     }
 }
 
-static const char *
-get_lrp_name_by_ts_port_name(struct ic_context *ctx,
-                           const char *ts_port_name)
+static void
+build_ts_routes_to_adv(struct ic_context *ctx,
+                       struct ic_router_info *ic_lr,
+                       struct hmap *routes_ad,
+                       struct lport_addresses *ts_port_addrs,
+                       const struct nbrec_nb_global *nb_global,
+                       const char *ts_route_table)
 {
-    const struct nbrec_logical_switch_port *nb_lsp;
-    const struct nbrec_logical_switch_port *nb_lsp_key =
-        nbrec_logical_switch_port_index_init_row(ctx->nbrec_port_by_name);
-    nbrec_logical_switch_port_index_set_name(nb_lsp_key, ts_port_name);
-    nb_lsp = nbrec_logical_switch_port_index_find(ctx->nbrec_port_by_name,
-                                                  nb_lsp_key);
-    nbrec_logical_switch_port_index_destroy_row(nb_lsp_key);
+    const struct nbrec_logical_router *lr = ic_lr->lr;
+
+    /* Check static routes of the LR */
+    for (int i = 0; i < lr->n_static_routes; i++) {
+        const struct nbrec_logical_router_static_route *nb_route
+            = lr->static_routes[i];
+        struct uuid isb_uuid;
+        if (smap_get_uuid(&nb_route->external_ids, "ic-learned-route",
+                          &isb_uuid)) {
+            /* It is a learned route */
+            if (!add_to_routes_learned(&ic_lr->routes_learned, nb_route)) {
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+                VLOG_WARN_RL(&rl, "Bad format of learned route in NB: "
+                             "%s -> %s. Delete it.", nb_route->ip_prefix,
+                             nb_route->nexthop);
+                nbrec_logical_router_update_static_routes_delvalue(lr,
+                    nb_route);
+            }
+        } else {
+            /* It may be a route to be advertised */
+            add_to_routes_ad(routes_ad, nb_route, ts_port_addrs,
+                             &nb_global->options, ts_route_table);
+        }
+    }
 
-    if (!nb_lsp) {
-        return NULL;
+    /* Check directly-connected subnets of the LR */
+    for (int i = 0; i < lr->n_ports; i++) {
+        const struct nbrec_logical_router_port *lrp = lr->ports[i];
+        if (!lrp_is_ts_port(ctx, ic_lr, lrp->name)) {
+            for (int j = 0; j < lrp->n_networks; j++) {
+                add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,
+                                         ts_port_addrs,
+                                         &nb_global->options);
+            }
+        } else {
+            /* The router port of the TS port is ignored. */
+            VLOG_DBG("Skip advertising direct route of lrp %s (TS port)",
+                     lrp->name);
+        }
     }
+}
 
-    return smap_get(&nb_lsp->options, "router-port");
+static void
+advertise_lr_routes(struct ic_context *ctx,
+                    const struct icsbrec_availability_zone *az,
+                    struct ic_router_info *ic_lr)
+{
+    const struct nbrec_nb_global *nb_global =
+        nbrec_nb_global_first(ctx->ovnnb_idl);
+    ovs_assert(nb_global);
+
+    const struct icsbrec_port_binding *isb_pb;
+    const char *lrp_name, *ts_name, *route_table;
+    struct lport_addresses ts_port_addrs;
+    const struct nbrec_logical_router *lr = ic_lr->lr;
+    const struct icnbrec_transit_switch *key;
+
+    struct hmap routes_ad = HMAP_INITIALIZER(&routes_ad);
+    for (int i = 0; i < ic_lr->n_isb_pbs; i++) {
+        isb_pb = ic_lr->isb_pbs[i];
+        key = icnbrec_transit_switch_index_init_row(
+            ctx->icnbrec_transit_switch_by_name);
+        icnbrec_transit_switch_index_set_name(key, isb_pb->transit_switch);
+        ts_name = icnbrec_transit_switch_index_find(
+            ctx->icnbrec_transit_switch_by_name, key)->name;
+        icnbrec_transit_switch_index_destroy_row(key);
+
+        if (!extract_lsp_addresses(isb_pb->address, &ts_port_addrs)) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+            VLOG_INFO_RL(&rl, "Route sync ignores port %s on ts %s for router"
+                         " %s because the addresses are invalid.",
+                         isb_pb->logical_port, isb_pb->transit_switch,
+                         lr->name);
+            continue;
+        }
+        lrp_name = get_lrp_name_by_ts_port_name(ctx, isb_pb->logical_port);
+        route_table = get_route_table_by_lrp_name(ctx, lrp_name);
+        build_ts_routes_to_adv(ctx, ic_lr, &routes_ad, &ts_port_addrs,
+                               nb_global, route_table);
+        advertise_routes(ctx, az, ts_name, &routes_ad);
+        destroy_lport_addresses(&ts_port_addrs);
+    }
+    hmap_destroy(&routes_ad);
 }
 
 static void
@@ -1375,130 +1577,70 @@ route_run(struct ic_context *ctx,
         return;
     }
 
-    const struct nbrec_nb_global *nb_global =
-        nbrec_nb_global_first(ctx->ovnnb_idl);
-    ovs_assert(nb_global);
-
-    const struct icnbrec_transit_switch *ts;
-    ICNBREC_TRANSIT_SWITCH_FOR_EACH (ts, ctx->ovninb_idl) {
-        struct hmap ic_lrs = HMAP_INITIALIZER(&ic_lrs);
-        struct hmap routes_ad = HMAP_INITIALIZER(&routes_ad);
-
-        const struct icsbrec_port_binding *isb_pb;
-        const struct icsbrec_port_binding *isb_pb_key =
-            icsbrec_port_binding_index_init_row(
-                ctx->icsbrec_port_binding_by_ts_az);
-        icsbrec_port_binding_index_set_transit_switch(isb_pb_key, ts->name);
-        icsbrec_port_binding_index_set_availability_zone(isb_pb_key, az);
-
-        /* Each port on TS maps to a logical router, which is stored in the
-         * external_ids:router-id of the IC SB port_binding record. */
-        ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
-            ctx->icsbrec_port_binding_by_ts_az) {
-            const char *ts_lrp_name =
-                get_lrp_name_by_ts_port_name(ctx, isb_pb->logical_port);
-            if (!ts_lrp_name) {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_WARN_RL(&rl, "Route sync ignores port %s on ts %s "
-                             "because logical router port is not found in NB.",
-                             isb_pb->logical_port, ts->name);
-                continue;
-            }
+    struct hmap ic_lrs = HMAP_INITIALIZER(&ic_lrs);
+    const struct icsbrec_port_binding *isb_pb;
+    const struct icsbrec_port_binding *isb_pb_key =
+        icsbrec_port_binding_index_init_row(ctx->icsbrec_port_binding_by_az);
+    icsbrec_port_binding_index_set_availability_zone(isb_pb_key, az);
 
-            struct uuid lr_uuid;
-            if (!smap_get_uuid(&isb_pb->external_ids, "router-id", &lr_uuid)) {
-                VLOG_DBG("IC-SB Port_Binding %s doesn't have "
-                         "external_ids:router-id set.", isb_pb->logical_port);
-                continue;
-            }
-            const struct nbrec_logical_router *lr
-                = nbrec_logical_router_get_for_uuid(ctx->ovnnb_idl, &lr_uuid);
-            if (!lr) {
-                continue;
-            }
+    /* Each port on TS maps to a logical router, which is stored in the
+     * external_ids:router-id of the IC SB port_binding record.
+     * Here we build info for interconnected Logical Router:
+     * collect IC Port Binding to process routes sync later on. */
+    ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
+                                         ctx->icsbrec_port_binding_by_az)
+    {
+        const char *ts_lrp_name =
+            get_lrp_name_by_ts_port_name(ctx, isb_pb->logical_port);
+        if (!ts_lrp_name) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+            VLOG_WARN_RL(&rl, "Route sync ignores port %s on ts %s because "
+                         "logical router port is not found in NB. Deleting it",
+                         isb_pb->logical_port, isb_pb->transit_switch);
+            icsbrec_port_binding_delete(isb_pb);
+            continue;
+        }
 
-            if (ic_router_find(&ic_lrs, lr)) {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_INFO_RL(&rl, "Route sync ignores port %s on ts %s for "
-                             "router %s because the router has another port "
-                             "connected to same ts.", isb_pb->logical_port,
-                             ts->name, lr->name);
-                continue;
-            }
+        struct uuid lr_uuid;
+        if (!smap_get_uuid(&isb_pb->external_ids, "router-id", &lr_uuid)) {
+            VLOG_DBG("IC-SB Port_Binding %s doesn't have "
+                     "external_ids:router-id set.", isb_pb->logical_port);
+            continue;
+        }
 
-            struct lport_addresses ts_port_addrs;
-            if (!extract_lsp_addresses(isb_pb->address, &ts_port_addrs)) {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_INFO_RL(&rl, "Route sync ignores port %s on ts %s for "
-                             "router %s because the addresses are invalid.",
-                             isb_pb->logical_port, ts->name, lr->name);
-                continue;
-            }
+        const struct nbrec_logical_router *lr
+            = nbrec_logical_router_get_for_uuid(ctx->ovnnb_idl, &lr_uuid);
+        if (!lr) {
+            continue;
+        }
 
-            struct ic_router_info *ic_lr = xzalloc(sizeof *ic_lr);
+        struct ic_router_info *ic_lr = ic_router_find(&ic_lrs, lr);
+        if (!ic_lr) {
+            ic_lr = xzalloc(sizeof *ic_lr);
             ic_lr->lr = lr;
-            ic_lr->isb_pb = isb_pb;
             hmap_init(&ic_lr->routes_learned);
             hmap_insert(&ic_lrs, &ic_lr->node, uuid_hash(&lr->header_.uuid));
-
-            /* Check static routes of the LR */
-            for (int i = 0; i < lr->n_static_routes; i++) {
-                const struct nbrec_logical_router_static_route *nb_route
-                    = lr->static_routes[i];
-                struct uuid isb_uuid;
-                if (smap_get_uuid(&nb_route->external_ids,
-                                  "ic-learned-route", &isb_uuid)) {
-                    /* It is a learned route */
-                    if (!add_to_routes_learned(&ic_lr->routes_learned,
-                                               nb_route)) {
-                        static struct vlog_rate_limit rl =
-                            VLOG_RATE_LIMIT_INIT(5, 1);
-                        VLOG_WARN_RL(&rl, "Bad format of learned route in NB:"
-                                     " %s -> %s. Delete it.",
-                                     nb_route->ip_prefix, nb_route->nexthop);
-                        nbrec_logical_router_update_static_routes_delvalue(
-                            lr, nb_route);
-                    }
-                } else {
-                    /* It may be a route to be advertised */
-                    add_to_routes_ad(&routes_ad, nb_route, &ts_port_addrs,
-                                     &nb_global->options);
-                }
-            }
-
-            /* Check direct-connected subnets of the LR */
-            for (int i = 0; i < lr->n_ports; i++) {
-                const struct nbrec_logical_router_port *lrp = lr->ports[i];
-                if (!strcmp(lrp->name, ts_lrp_name)) {
-                    /* The router port of the TS port is ignored. */
-                    VLOG_DBG("Route ad: skip lrp %s (TS port: %s)",
-                             lrp->name, isb_pb->logical_port);
-                    continue;
-                }
-
-                for (int j = 0; j < lrp->n_networks; j++) {
-                    add_network_to_routes_ad(&routes_ad, lrp->networks[j],
-                                             lrp, &ts_port_addrs,
-                                             &nb_global->options);
-                }
-            }
-
-            destroy_lport_addresses(&ts_port_addrs);
         }
-        icsbrec_port_binding_index_destroy_row(isb_pb_key);
-
-        advertise_route(ctx, az, ts->name, &routes_ad);
-        hmap_destroy(&routes_ad);
 
-        struct ic_router_info *ic_lr, *next;
-        HMAP_FOR_EACH_SAFE (ic_lr, next, node, &ic_lrs) {
-            sync_learned_route(ctx, az, ic_lr);
-            hmap_destroy(&ic_lr->routes_learned);
-            hmap_remove(&ic_lrs, &ic_lr->node);
-            free(ic_lr);
+        if (ic_lr->n_isb_pbs == ic_lr->n_allocated_isb_pbs) {
+            ic_lr->isb_pbs = x2nrealloc(ic_lr->isb_pbs,
+                                        &ic_lr->n_allocated_isb_pbs,
+                                        sizeof *ic_lr->isb_pbs);
         }
-        hmap_destroy(&ic_lrs);
+        ic_lr->isb_pbs[ic_lr->n_isb_pbs++] = isb_pb;
     }
+    icsbrec_port_binding_index_destroy_row(isb_pb_key);
+
+    struct ic_router_info *ic_lr, *next;
+    HMAP_FOR_EACH_SAFE (ic_lr, next, node, &ic_lrs) {
+        advertise_lr_routes(ctx, az, ic_lr);
+        sync_learned_routes(ctx, az, ic_lr);
+        free(ic_lr->isb_pbs);
+        hmap_destroy(&ic_lr->routes_learned);
+        hmap_remove(&ic_lrs, &ic_lr->node);
+        free(ic_lr);
+    }
+    hmap_destroy(&ic_lrs);
 }
 
 static void
@@ -1696,6 +1838,9 @@ main(int argc, char *argv[])
     struct ovsdb_idl_index *nbrec_port_by_name
         = ovsdb_idl_index_create1(ovnnb_idl_loop.idl,
                                   &nbrec_logical_switch_port_col_name);
+    struct ovsdb_idl_index *nbrec_lrp_by_name
+        = ovsdb_idl_index_create1(ovnnb_idl_loop.idl,
+                                  &nbrec_logical_router_port_col_name);
     struct ovsdb_idl_index *sbrec_port_binding_by_name
         = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
                                   &sbrec_port_binding_col_logical_port);
@@ -1703,6 +1848,10 @@ main(int argc, char *argv[])
         = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
                                   &sbrec_chassis_col_name);
 
+    struct ovsdb_idl_index *icnbrec_transit_switch_by_name
+        = ovsdb_idl_index_create1(ovninb_idl_loop.idl,
+                                  &icnbrec_transit_switch_col_name);
+
     struct ovsdb_idl_index *icsbrec_port_binding_by_az
         = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,
                                   &icsbrec_port_binding_col_availability_zone);
@@ -1761,9 +1910,12 @@ main(int argc, char *argv[])
                 .ovnisb_idl = ovnisb_idl_loop.idl,
                 .ovnisb_txn = ovsdb_idl_loop_run(&ovnisb_idl_loop),
                 .nbrec_ls_by_name = nbrec_ls_by_name,
+                .nbrec_lrp_by_name = nbrec_lrp_by_name,
                 .nbrec_port_by_name = nbrec_port_by_name,
                 .sbrec_port_binding_by_name = sbrec_port_binding_by_name,
                 .sbrec_chassis_by_name = sbrec_chassis_by_name,
+                .icnbrec_transit_switch_by_name =
+                    icnbrec_transit_switch_by_name,
                 .icsbrec_port_binding_by_az = icsbrec_port_binding_by_az,
                 .icsbrec_port_binding_by_ts = icsbrec_port_binding_by_ts,
                 .icsbrec_port_binding_by_ts_az = icsbrec_port_binding_by_ts_az,
diff --git a/ovn-ic-sb.ovsschema b/ovn-ic-sb.ovsschema
index 5364b21b4..140ced149 100644
--- a/ovn-ic-sb.ovsschema
+++ b/ovn-ic-sb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_IC_Southbound",
-    "version": "1.0.0",
-    "cksum": "108951192 6585",
+    "version": "1.1.0",
+    "cksum": "3076915724 6636",
     "tables": {
         "IC_SB_Global": {
             "columns": {
@@ -92,6 +92,7 @@
                 "transit_switch": {"type": "string"},
                 "availability_zone": {"type": {"key": {"type": "uuid",
                                       "refTable": "Availability_Zone"}}},
+                "route_table": {"type": "string"},
                 "ip_prefix": {"type": "string"},
                 "nexthop": {"type": "string"},
                 "external_ids": {
diff --git a/ovn-ic-sb.xml b/ovn-ic-sb.xml
index 3582cff47..2f2ecf952 100644
--- a/ovn-ic-sb.xml
+++ b/ovn-ic-sb.xml
@@ -306,6 +306,24 @@
         The availability zone that has advertised the route.
       </column>
 
+      <column name="route_table">
+        Route table within which this route was created.
+        Empty value means "global" routing table.
+        <p>
+        Routes for directly-connected networks will be
+        learned to global routing table and if Logical Routers
+        have more than one Transit Switch, which interconnects
+        them, directly-connected routes will be added via each
+        transit switch port and configured as ECMP routes.
+        </p>
+        <p>
+        Static routes within route tables will be advertised
+        and learned only if interconnecting transit switch's LRPs
+        will have <code>options:route_table</code> same value as
+        route's <code>route_table</code> value.
+        </p>
+      </column>
+
       <column name="ip_prefix">
         IP prefix of this route (e.g. 192.168.100.0/24).
       </column>
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 3aab54362..5803f76e9 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -430,3 +430,443 @@ OVN_CLEANUP_IC([az1], [az2])
 
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- route sync -- route tables])
+
+ovn_init_ic_db
+ovn-ic-nbctl ts-add ts1
+
+for i in 1 2; do
+    ovn_start az$i
+    ovn_as az$i
+
+    # Enable route learning at AZ level
+    ovn-nbctl set nb_global . options:ic-route-learn=true
+    # Enable route advertising at AZ level
+    ovn-nbctl set nb_global . options:ic-route-adv=true
+
+    # Create LRP and connect to TS
+    ovn-nbctl lr-add lr$i
+    ovn-nbctl lrp-add lr$i lrp-lr$i-ts1 aa:aa:aa:aa:aa:0$i 169.254.100.$i/24
+    ovn-nbctl lsp-add ts1 lsp-ts1-lr$i \
+            -- lsp-set-addresses lsp-ts1-lr$i router \
+            -- lsp-set-type lsp-ts1-lr$i router \
+            -- lsp-set-options lsp-ts1-lr$i router-port=lrp-lr$i-ts1
+
+    # Create static routes
+    ovn-nbctl lr-route-add lr$i 10.11.$i.0/24 169.254.0.1
+
+    # Create a src-ip route, which shouldn't be synced
+    ovn-nbctl --policy=src-ip --route-table=rtb1 lr-route-add lr$i 10.22.$i.0/24 169.254.0.2
+done
+
+for i in 1 2; do
+    OVS_WAIT_UNTIL([ovn_as az$i ovn-nbctl lr-route-list lr$i | grep learned])
+done
+
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+IPv4 Routes
+Route Table global:
+             10.11.1.0/24               169.254.0.1 dst-ip
+             10.11.2.0/24             169.254.100.2 dst-ip (learned)
+
+Route Table rtb1:
+             10.22.1.0/24               169.254.0.2 src-ip
+])
+
+# move routes from global route table to rtb1
+for i in 1 2; do
+    ovn_as az$i ovn-nbctl lr-route-del lr$i 10.11.$i.0/24 169.254.0.1
+    ovn_as az$i ovn-nbctl --route-table=rtb1 lr-route-add lr$i 10.11.$i.0/24 169.254.0.1
+done
+
+for i in 1 2; do
+    OVS_WAIT_WHILE([ovn_as az$i ovn-nbctl lr-route-list lr$i | grep learned])
+done
+
+# ensure route from rtb1 is not learned to any route table as route table is
+# not set to TS port
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.1.0/24               169.254.0.1 dst-ip
+             10.22.1.0/24               169.254.0.2 src-ip
+])
+
+# assign route table rtb1 to TS port on AZ2 and check routes are advertised to IC SB DB
+check ovn_as az2 ovn-nbctl lrp-set-options lrp-lr2-ts1 route_table=rtb1
+OVS_WAIT_UNTIL([ovn-ic-sbctl find route route_table=rtb1 | grep 10.11.2.0/24])
+
+# ensure route was not learned as on AZ1 TS port's LRP was not set to route table rtb1
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.1.0/24               169.254.0.1 dst-ip
+             10.22.1.0/24               169.254.0.2 src-ip
+])
+
+# set TS port's LRP to route table rtb1 to learn routes from AZ2 from rtb1
+check ovn_as az1 ovn-nbctl lrp-set-options lrp-lr1-ts1 route_table=rtb1
+
+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr1 | grep learned])
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.1.0/24               169.254.0.1 dst-ip
+             10.11.2.0/24             169.254.100.2 dst-ip (learned)
+             10.22.1.0/24               169.254.0.2 src-ip
+])
+
+# Delete route in AZ1, AZ2's learned route should be deleted.
+ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-del lr1 10.11.1.0/24
+OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl --route-table=rtb1 lr-route-list lr2 | grep learned])
+
+# Add the route back
+ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-add lr1 10.11.1.0/24 169.254.0.1
+OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned])
+
+# Disable route-learning for AZ1
+ovn_as az1 ovn-nbctl set nb_global . options:ic-route-learn=false
+OVS_WAIT_WHILE([ovn_as az1 ovn-nbctl lr-route-list lr1 | grep learned])
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.1.0/24               169.254.0.1 dst-ip
+             10.22.1.0/24               169.254.0.2 src-ip
+])
+
+# AZ1 should still advertise and AZ2 should still learn the route
+AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned], [0], [ignore])
+AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.1.0/24             169.254.100.1 dst-ip (learned)
+             10.11.2.0/24               169.254.0.1 dst-ip
+             10.22.2.0/24               169.254.0.2 src-ip
+])
+
+# Disable route-advertising for AZ1
+ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv=false
+
+# AZ2 shouldn't have the route learned, because AZ1 have stopped advertising.
+OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned])
+
+# Add default route in AZ1
+ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-add lr1 0.0.0.0/0 169.254.0.3
+
+# Re-enable router-advertising & learn for AZ1
+ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv=true
+ovn_as az1 ovn-nbctl set nb_global . options:ic-route-learn=true
+
+for i in 1 2; do
+    OVS_WAIT_UNTIL([ovn_as az$i ovn-nbctl lr-route-list lr$i | grep learned])
+done
+
+# Default route should NOT get advertised or learned, by default.
+AT_CHECK([ovn-ic-sbctl find route ip_prefix="0.0.0.0/0"], [0], [])
+
+# Enable default route advertising in AZ1, ensure it advertised, but not learned
+ovn_as az1 ovn-nbctl set nb_global . options:ic-route-adv-default=true
+OVS_WAIT_UNTIL([ovn-ic-sbctl find route ip_prefix="0.0.0.0/0" route_table=rtb1 | grep 0.0.0.0])
+OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl --route-table=rtb1 lr-route-list lr2 | grep learned | grep 0.0.0.0])
+
+# Enable default route learning in AZ2
+ovn_as az2 ovn-nbctl set nb_global . options:ic-route-learn-default=true
+OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl --route-table=rtb1 lr-route-list lr2 | grep learned | grep 0.0.0.0])
+
+# Test directly connected subnet route advertising. Route should go to global route table.
+ovn_as az1 ovn-nbctl lrp-add lr1 lrp-lr1-ls1 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+OVS_WAIT_UNTIL([ovn-ic-sbctl find route ip_prefix="192.168.0.1/24" route_table="\"\"" | grep 192.168.0.1/24])
+OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned | grep 192.168])
+AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
+IPv4 Routes
+Route Table global:
+           192.168.0.0/24             169.254.100.1 dst-ip (learned)
+
+Route Table rtb1:
+             10.11.1.0/24             169.254.100.1 dst-ip (learned)
+             10.11.2.0/24               169.254.0.1 dst-ip
+             10.22.2.0/24               169.254.0.2 src-ip
+                0.0.0.0/0             169.254.100.1 dst-ip (learned)
+])
+
+# Delete the directly connected subnet from AZ1, learned route should be
+# removed from AZ2.
+ovn_as az1 ovn-nbctl lrp-del lrp-lr1-ls1
+OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned | grep 192.168])
+
+# Test blacklist routes
+# Add back the directly connected 192.168 route.
+ovn_as az1 ovn-nbctl lrp-add lr1 lrp-lr1-ls1 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned | grep 192.168])
+# Now add 10.11.0.0/16 and 192.168.0.0/16 to blacklist in AZ2.
+check ovn_as az2 ovn-nbctl set nb_global . options:ic-route-blacklist="10.11.0.0/16,192.168.0.0/16"
+# AZ2 shouldn't learn 192.168 route any more.
+OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned | grep 192.168])
+# AZ1 shouldn't learn 10.11 any more.
+OVS_WAIT_WHILE([ovn_as az1 ovn-nbctl lr-route-list lr1 | grep learned | grep 10.11])
+AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+             10.11.2.0/24               169.254.0.1 dst-ip
+             10.22.2.0/24               169.254.0.2 src-ip
+                0.0.0.0/0             169.254.100.1 dst-ip (learned)
+])
+
+OVN_CLEANUP_IC([az1], [az2])
+
+AT_CLEANUP
+])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- route sync -- multiple route tables])
+
+ovn_init_ic_db
+ovn-ic-nbctl ts-add ts1
+
+for i in 1 2; do
+    ovn_start az$i
+    ovn_as az$i
+
+    # Enable route learning at AZ level
+    ovn-nbctl set nb_global . options:ic-route-learn=true
+    # Enable route advertising at AZ level
+    ovn-nbctl set nb_global . options:ic-route-adv=true
+done
+
+# Create new transit switches and LRs. Test topology is next:
+# VPC1:
+#                       / transit switch (ts11) \
+# logical router (lr11) - transit switch (ts12) - logical router (lr12)
+#                       \ transit switch (ts13) /
+#
+# VPC2:
+#                       / transit switch (ts21) \
+# logical router (lr21)                           logical router (lr22)
+#                       \ transit switch (ts22) /
+#
+# each LR has one connected subnet except TS port
+
+
+# VPC1
+# create lr11, lr12, ts11, ts12, ts13 and connect them
+# assign route tables rtb1, rtb2, rtb3 to ts ports
+for i in 1 2; do
+    ovn_as az$i
+
+    lr=lr1$i
+    ovn-nbctl lr-add $lr
+
+    for j in 1 2 3; do
+        ts=ts1$j
+        ovn-ic-nbctl --may-exist ts-add $ts
+
+        lrp=lrp-$lr-$ts
+        lsp=lsp-$ts-$lr
+        # Create LRP and connect to TS
+        ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i 169.254.10$j.$i/24
+        ovn-nbctl lrp-set-options $lrp route_table=rtb$j
+        ovn-nbctl lsp-add $ts $lsp \
+                -- lsp-set-addresses $lsp router \
+                -- lsp-set-type $lsp router \
+                -- lsp-set-options $lsp router-port=$lrp
+    done
+done
+
+# VPC2
+# create lr21, lr22, ts21, ts22 and connect them
+# assign route tables rtb1, rtb2, rtb3 to ts ports
+for i in 1 2; do
+    ovn_as az$i
+
+    lr=lr2$i
+    ovn-nbctl lr-add $lr
+
+    for j in 1 2; do
+        ts=ts2$j
+        ovn-ic-nbctl --may-exist ts-add $ts
+
+        lrp=lrp-$lr-$ts
+        lsp=lsp-$ts-$lr
+        # Create LRP and connect to TS
+        ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i 169.254.10$j.$i/24
+        ovn-nbctl lrp-set-options $lrp route_table=rtb$j
+        ovn-nbctl lsp-add $ts $lsp \
+                -- lsp-set-addresses $lsp router \
+                -- lsp-set-type $lsp router \
+                -- lsp-set-options $lsp router-port=$lrp
+    done
+done
+
+# Create directly-connected and static routes in VPC1
+ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+ovn_as az2 ovn-nbctl --route-table=rtb1 lr-route-add lr12 10.10.10.0/24 192.168.0.10
+ovn_as az2 ovn-nbctl --route-table=rtb2 lr-route-add lr12 10.10.10.0/24 192.168.0.11
+ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 10.10.10.0/24 192.168.0.12
+
+# Create directly-connected route in VPC2
+ovn_as az2 ovn-nbctl lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "192.168.0.1/24"
+
+# Test direct routes from lr12 were learned to lr11
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 |
+             grep learned | awk '{print $1, $2, $5}' | sort ], [0], [dnl
+192.168.0.0/24 169.254.101.2 ecmp
+192.168.0.0/24 169.254.102.2 ecmp
+192.168.0.0/24 169.254.103.2 ecmp
+])
+
+# Test static routes from lr12 rtbs rtb1,rtb2,rtb3 were learned to lr11
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11], [0], [dnl
+IPv4 Routes
+Route Table rtb1:
+            10.10.10.0/24             169.254.101.2 dst-ip (learned)
+])
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11], [0], [dnl
+IPv4 Routes
+Route Table rtb2:
+            10.10.10.0/24             169.254.102.2 dst-ip (learned)
+])
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11], [0], [dnl
+IPv4 Routes
+Route Table rtb3:
+            10.10.10.0/24             169.254.103.2 dst-ip (learned)
+])
+
+# Test routes from lr12 didn't leak as learned to lr21
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep 192.168 | sort], [0], [dnl
+           192.168.0.0/24             169.254.101.2 dst-ip (learned) ecmp
+           192.168.0.0/24             169.254.102.2 dst-ip (learned) ecmp
+])
+
+OVN_CLEANUP_IC([az1], [az2])
+
+AT_CLEANUP
+])
+
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- route sync -- multiple route tables IPv6])
+
+ovn_init_ic_db
+ovn-ic-nbctl ts-add ts1
+
+for i in 1 2; do
+    ovn_start az$i
+    ovn_as az$i
+
+    # Enable route learning at AZ level
+    ovn-nbctl set nb_global . options:ic-route-learn=true
+    # Enable route advertising at AZ level
+    ovn-nbctl set nb_global . options:ic-route-adv=true
+done
+
+# Create new transit switches and LRs. Test topology is next:
+# VPC1:
+#                       / transit switch (ts11) \
+# logical router (lr11) - transit switch (ts12) - logical router (lr12)
+#                       \ transit switch (ts13) /
+#
+# VPC2:
+#                       / transit switch (ts21) \
+# logical router (lr21)                           logical router (lr22)
+#                       \ transit switch (ts22) /
+#
+# each LR has one connected subnet except TS port
+
+
+# VPC1
+# create lr11, lr12, ts11, ts12, ts13 and connect them
+# assign route tables rtb1, rtb2, rtb3 to ts ports
+for i in 1 2; do
+    ovn_as az$i
+
+    lr=lr1$i
+    ovn-nbctl lr-add $lr
+
+    for j in 1 2 3; do
+        ts=ts1$j
+        ovn-ic-nbctl --may-exist ts-add $ts
+
+        lrp=lrp-$lr-$ts
+        lsp=lsp-$ts-$lr
+        # Create LRP and connect to TS
+        ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i 2001:db8:$j::$i/64
+        ovn-nbctl lrp-set-options $lrp route_table=rtb$j
+        ovn-nbctl lsp-add $ts $lsp \
+                -- lsp-set-addresses $lsp router \
+                -- lsp-set-type $lsp router \
+                -- lsp-set-options $lsp router-port=$lrp
+    done
+done
+
+# VPC2
+# create lr21, lr22, ts21, ts22 and connect them
+# assign route tables rtb1, rtb2, rtb3 to ts ports
+for i in 1 2; do
+    ovn_as az$i
+
+    lr=lr2$i
+    ovn-nbctl lr-add $lr
+
+    for j in 1 2; do
+        ts=ts2$j
+        ovn-ic-nbctl --may-exist ts-add $ts
+
+        lrp=lrp-$lr-$ts
+        lsp=lsp-$ts-$lr
+        # Create LRP and connect to TS
+        ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a$j:0$i 2001:db8:$j::$i/64
+        ovn-nbctl lrp-set-options $lrp route_table=rtb$j
+        ovn-nbctl lsp-add $ts $lsp \
+                -- lsp-set-addresses $lsp router \
+                -- lsp-set-type $lsp router \
+                -- lsp-set-options $lsp router-port=$lrp
+    done
+done
+
+# Create directly-connected and static routes in VPC1
+ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 "2001:db8:200::1/64"
+ovn_as az2 ovn-nbctl --route-table=rtb1 lr-route-add lr12 2001:db8:aaaa::/64 2001:db8:200::10
+ovn_as az2 ovn-nbctl --route-table=rtb2 lr-route-add lr12 2001:db8:aaaa::/64 2001:db8:200::11
+ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 2001:db8:aaaa::/64 2001:db8:200::12
+
+# Create directly-connected route in VPC2
+ovn_as az2 ovn-nbctl lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "2001:db8:200::1/64"
+
+# Test direct routes from lr12 were learned to lr11
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001:db8:200 |
+             grep learned | awk '{print $1, $2, $5}' | sort], [0], [dnl
+2001:db8:200::/64 2001:db8:1::2 ecmp
+2001:db8:200::/64 2001:db8:2::2 ecmp
+2001:db8:200::/64 2001:db8:3::2 ecmp
+])
+
+# Test static routes from lr12 rtbs rtb1,rtb2,rtb3 were learned to lr11
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11], [0], [dnl
+IPv6 Routes
+Route Table rtb1:
+       2001:db8:aaaa::/64             2001:db8:1::2 dst-ip (learned)
+])
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11], [0], [dnl
+IPv6 Routes
+Route Table rtb2:
+       2001:db8:aaaa::/64             2001:db8:2::2 dst-ip (learned)
+])
+AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11], [0], [dnl
+IPv6 Routes
+Route Table rtb3:
+       2001:db8:aaaa::/64             2001:db8:3::2 dst-ip (learned)
+])
+
+# Test routes from lr12 didn't leak as learned to lr21
+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep 2001 | sort], [0], [dnl
+        2001:db8:200::/64             2001:db8:1::2 dst-ip (learned) ecmp
+        2001:db8:200::/64             2001:db8:2::2 dst-ip (learned) ecmp
+])
+
+OVN_CLEANUP_IC([az1], [az2])
+
+AT_CLEANUP
+])
