Consider the scenario where there are 2 AZs using ovn-ic, each AZ has
one LR and its LS. The LRs are interconnected by a transit switch.
On each AZ, we can configure the dynamic routing and exchange routes
via BGP with external BGP speakers.

AZ1
LS1 - LR1 - BGP Speaker1 - Local subnet1
       \
   -----------------------
    transit switch
   -----------------------
AZ2    /
LS2 - LR2 - BGP Speaker2 - Local subnet2

The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will
not be redistributed to BGP Speaker2 and it also happens with LR1.
This scenario uses the network's hub-and-spoke terminology where we can
enable the hub-spoke on the LR for such redistribution.
subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.
Also, consider the same scenario, but LR1 and LR2 learn the same subnet
for redundancy, hub-spoke option is disabled to not adv the subnet learned
from BGP and advertised in ovn-ic in BGP speakers.

Signed-off-by: Lucas Vargas Dias <[email protected]>
---
 NEWS                              |  2 +
 ic/ovn-ic.c                       | 22 ++++---
 lib/ovn-util.h                    |  1 +
 northd/en-advertised-route-sync.c |  2 +
 northd/northd.c                   |  8 +++
 northd/northd.h                   |  5 +-
 northd/ovn-northd.c               |  1 -
 ovn-ic-sb.ovsschema               |  7 ++-
 ovn-ic-sb.xml                     | 14 +++--
 ovn-nb.xml                        | 14 +++++
 tests/ovn-ic.at                   | 99 +++++++++++++++++++++++++++++++
 11 files changed, 156 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index 888946b54..5710716aa 100644
--- a/NEWS
+++ b/NEWS
@@ -52,6 +52,8 @@ OVN v26.03.0 - xxx xx xxxx
        learned routes. This option has priority over its router counterpart.
      * The EVPN support is now considered stable.  Its "experimental" tag has
        been removed.
+     * Add support for hub-and-spoke propagation via the "hub-spoke" option
+       in dynamic-routing-redistribute settings.
    - Add support for Network Function insertion in OVN with stateful traffic
      redirection capability in Logical Switch datapath. The feature introduces
      three new NB database tables:
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 1aa8af9b9..d224d37f7 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -1283,6 +1283,7 @@ struct ic_route_info {
     struct in6_addr prefix;
     unsigned int plen;
     struct in6_addr nexthop;
+    bool is_src_dynamic;
     const char *origin;
     const char *route_table;
     const char *route_tag;
@@ -1565,7 +1566,7 @@ add_to_routes_ad(struct hmap *routes_ad, const struct 
in6_addr prefix,
                  const struct nbrec_logical_router_static_route *nb_route,
                  const struct nbrec_logical_router *nb_lr,
                  const struct nbrec_load_balancer *nb_lb,
-                 const char *route_tag)
+                 const char *route_tag, bool is_src_dynamic)
 {
     ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);
 
@@ -1585,6 +1586,7 @@ add_to_routes_ad(struct hmap *routes_ad, const struct 
in6_addr prefix,
         ic_route->nb_route = nb_route;
         ic_route->origin = origin;
         ic_route->route_table = route_table;
+        ic_route->is_src_dynamic = is_src_dynamic;
         ic_route->nb_lrp = nb_lrp;
         ic_route->nb_lr = nb_lr;
         ic_route->nb_lb = nb_lb;
@@ -1661,7 +1663,7 @@ add_static_to_routes_ad(
 
     add_to_routes_ad(routes_ad, prefix, plen, nexthop, ROUTE_ORIGIN_STATIC,
                      nb_route->route_table, NULL, nb_route, nb_lr,
-                     NULL, route_tag);
+                     NULL, route_tag, false);
 }
 
 static void
@@ -1671,7 +1673,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const 
char *network,
                          const struct smap *nb_options,
                          const struct nbrec_logical_router *nb_lr,
                          const char *route_tag,
-                         const struct nbrec_logical_router_port *ts_lrp)
+                         const struct nbrec_logical_router_port *ts_lrp,
+                         bool is_src_dynamic)
 {
     struct in6_addr prefix, nexthop;
     unsigned int plen;
@@ -1721,9 +1724,12 @@ add_network_to_routes_ad(struct hmap *routes_ad, const 
char *network,
         ds_destroy(&msg);
     }
 
+    const char *origin = is_src_dynamic ? ROUTE_ORIGIN_CONNECTED_DYNAMIC :
+                                          ROUTE_ORIGIN_CONNECTED;
     /* directly-connected routes go to <main> route table */
-    add_to_routes_ad(routes_ad, prefix, plen, nexthop, ROUTE_ORIGIN_CONNECTED,
-                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);
+    add_to_routes_ad(routes_ad, prefix, plen, nexthop, origin,
+                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,
+                     is_src_dynamic);
 }
 
 static void
@@ -1781,7 +1787,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad, const 
char *vip_key,
 
     /* Lb vip routes go to <main> route table */
     add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,
-                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);
+                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);
 out:
     free(vip_str);
 }
@@ -2374,7 +2380,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
                 add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,
                                          ts_port_addrs,
                                          &nb_global->options,
-                                         lr, route_tag, ts_lrp);
+                                         lr, route_tag, ts_lrp, false);
             }
         } else {
             /* The router port of the TS port is ignored. */
@@ -2429,7 +2435,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
         add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,
                                  ts_port_addrs,
                                  &nb_global->options,
-                                 lr, route_tag, ts_lrp);
+                                 lr, route_tag, ts_lrp, true);
     }
     sbrec_learned_route_index_destroy_row(filter);
 }
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index 4c6623bef..4ccf6dc2d 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -33,6 +33,7 @@
 #define ROUTE_ORIGIN_CONNECTED "connected"
 #define ROUTE_ORIGIN_STATIC "static"
 #define ROUTE_ORIGIN_LB "loadbalancer"
+#define ROUTE_ORIGIN_CONNECTED_DYNAMIC "connected-dynamic"
 
 #define ETH_CRC_LENGTH 4
 #define ETHERNET_OVERHEAD (ETH_HEADER_LEN + ETH_CRC_LENGTH)
diff --git a/northd/en-advertised-route-sync.c 
b/northd/en-advertised-route-sync.c
index 8b73810c7..6ae9a9689 100644
--- a/northd/en-advertised-route-sync.c
+++ b/northd/en-advertised-route-sync.c
@@ -683,6 +683,8 @@ should_advertise_route(const struct ovn_datapath 
*advertising_od,
         return drr_mode_LB_is_set(drr);
     case ROUTE_SOURCE_CONNECTED_AS_HOST:
         return drr_mode_CONNECTED_AS_HOST_is_set(drr);
+    case ROUTE_SOURCE_IC_DYNAMIC:
+        return drr_mode_IC_DYNAMIC_is_set(drr);
     case ROUTE_SOURCE_LEARNED:
         OVS_NOT_REACHED();
     default:
diff --git a/northd/northd.c b/northd/northd.c
index b7239f4e2..ce80639ea 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -887,6 +887,10 @@ parse_dynamic_routing_redistribute(
             out |= DRRM_LB;
             continue;
         }
+        if (!strcmp(token, "hub-spoke")) {
+            out |= DRRM_IC_DYNAMIC;
+            continue;
+        }
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
         VLOG_WARN_RL(&rl,
                      "unknown dynamic-routing-redistribute option '%s' on %s",
@@ -12342,6 +12346,9 @@ parsed_routes_add_static(const struct ovn_datapath *od,
     if (!strcmp(smap_get_def(&route->options, "origin", ""),
                 ROUTE_ORIGIN_CONNECTED)) {
         source = ROUTE_SOURCE_CONNECTED;
+    } else if (!strcmp(smap_get_def(&route->options, "origin", ""),
+                ROUTE_ORIGIN_CONNECTED_DYNAMIC)) {
+        source = ROUTE_SOURCE_IC_DYNAMIC;
     } else {
         source = ROUTE_SOURCE_STATIC;
     }
@@ -12436,6 +12443,7 @@ route_source_to_offset(enum route_source source)
 {
     switch (source) {
     case ROUTE_SOURCE_CONNECTED:
+    case ROUTE_SOURCE_IC_DYNAMIC:
         return ROUTE_PRIO_OFFSET_CONNECTED;
     case ROUTE_SOURCE_STATIC:
         return ROUTE_PRIO_OFFSET_STATIC;
diff --git a/northd/northd.h b/northd/northd.h
index 139519006..e86d39f9a 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -365,7 +365,8 @@ struct mcast_port_info {
     DRR_MODE(CONNECTED_AS_HOST, 1) \
     DRR_MODE(STATIC,            2) \
     DRR_MODE(NAT,               3) \
-    DRR_MODE(LB,                4)
+    DRR_MODE(LB,                4) \
+    DRR_MODE(IC_DYNAMIC,        5)
 
 enum dynamic_routing_redistribute_mode_bits {
 #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,
@@ -832,6 +833,8 @@ enum route_source {
     ROUTE_SOURCE_LB,
     /* The route is derived from out_port of connected logical router. */
     ROUTE_SOURCE_CONNECTED_AS_HOST,
+    /* The route is derived from an ovn-controller and advertised to IC. */
+    ROUTE_SOURCE_IC_DYNAMIC,
 };
 
 struct parsed_route {
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 0ed2eb17a..cfaf2f74b 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -905,7 +905,6 @@ main(int argc, char *argv[])
         &nbrec_load_balancer_col_external_ids,
         &nbrec_load_balancer_health_check_col_external_ids,
         &nbrec_logical_router_policy_col_external_ids,
-        &nbrec_logical_router_static_route_col_external_ids,
         &nbrec_meter_col_external_ids,
         &nbrec_meter_band_col_external_ids,
         &nbrec_mirror_col_external_ids,
diff --git a/ovn-ic-sb.ovsschema b/ovn-ic-sb.ovsschema
index 8981a4eef..e0e0fef5e 100644
--- a/ovn-ic-sb.ovsschema
+++ b/ovn-ic-sb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_IC_Southbound",
-    "version": "2.4.0",
-    "cksum": "859073048 9662",
+    "version": "2.5.0",
+    "cksum": "1892994110 9713",
     "tables": {
         "IC_SB_Global": {
             "columns": {
@@ -116,7 +116,8 @@
                 "origin": {"type": {"key": {
                     "type": "string",
                     "enum": ["set",
-                             ["connected", "static", "loadbalancer"]]}}},
+                             ["connected", "static", "loadbalancer",
+                              "connected-dynamic"]]}}},
                 "external_ids": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}}},
diff --git a/ovn-ic-sb.xml b/ovn-ic-sb.xml
index b59fe1d03..3ca115073 100644
--- a/ovn-ic-sb.xml
+++ b/ovn-ic-sb.xml
@@ -378,12 +378,14 @@
       </column>
 
       <column name="origin">
-        Can be one of <code>connected</code>, <code>static</code> or
-        <code>loadbalancer</code>.  Routes to directly-connected subnets -
-        LRP's CIDRs are inserted to OVN IC SB DB with <code>connected</code>
-        value in <ref column="origin"/>.  Static routes are inserted to OVN IC
-        SB DB with <code>static</code> value.  Routes for LB VIPs are inserted
-        in OVN IC SB DB with <code>loadbalancer</code> value.
+        Can be one of <code>connected</code>, <code>static</code>,
+        <code>connected-dynamic</code> or <code>loadbalancer</code>.  Routes
+        to directly-connected subnets - LRP's CIDRs are inserted to OVN IC SB
+        DB with <code>connected</code> value in <ref column="origin"/>.
+          Static routes are inserted to OVN IC SB DB with <code>static</code>
+        value.  Routes for LB VIPs are inserted in OVN IC SB DB with
+        <code>loadbalancer</code> value.  Routes learned from dynamic routing
+        are inserted OVN IC SB DB with <code>connected-dynamic</code> value.
         Next when route is learned to another AZ NB DB by ovn-ic, route origin
         is synced to <ref table="Logical_Router_Static_Route" column="options"
         key="origin"/>.
diff --git a/ovn-nb.xml b/ovn-nb.xml
index f1cd89509..7324e8656 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -3533,6 +3533,13 @@ or
           Logical Switch.
         </p>
 
+        <p>
+          If <code>hub-spoke</code> is in the list then northd will synchronize
+          dynamic routes learned through OVN-IC from other routers into the
+          <ref table="Advertised_Route" db="OVN_Southbound"/> table, enabling
+          hub-and-spoke propagation.
+        </p>
+
         <p>
           This value can be overwritten on a per LRP basis using
           <ref column="options" key="dynamic-routing-redistribute"
@@ -4629,6 +4636,13 @@ or
           via shared Logical Switch.
         </p>
 
+        <p>
+          If <code>hub-spoke</code> is in the list then northd will synchronize
+          dynamic routes learned through OVN-IC from other routers into the
+          <ref table="Advertised_Route" db="OVN_Southbound"/> table, enabling
+          hub-and-spoke propagation.
+        </p>
+
         <p>
           If not set the value from <ref column="options"
           key="dynamic-routing-redistribute" table="Logical_Router"/> on the
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 8bb5a4177..3c7ad8055 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -4692,3 +4692,102 @@ OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-nbctl lr-route-list 
lr12 | grep 192.168 |
 OVN_CLEANUP_IC([az1], [az2], [az3])
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route - hub and 
spoke mode])
+
+ovn_init_ic_db
+
+for i in 1 2; do
+    ovn_start az$i
+    ovn_as az$i
+
+    # Enable route learning at AZ level
+    check ovn-nbctl set nb_global . options:ic-route-learn=true
+    # Enable route advertising at AZ level
+    check ovn-nbctl set nb_global . options:ic-route-adv=true
+done
+
+# Create new transit switches and LRs. Test topology is next:
+#
+#
+# logical router (lr11) - transit switch (ts11) - logical router (lr12)
+#
+#
+
+# Create lr11, lr12 and ts11 and connect them
+for i in 1 2; do
+    ovn_as az$i
+
+    lr=lr1$i
+    check ovn-nbctl lr-add $lr
+
+    ts=ts11
+    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts
+
+    lrp=lrp-$lr-$ts
+    lsp=lsp-$ts-$lr
+    # Create LRP and connect to TS
+    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i 169.254.101.$i/24
+    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp
+done
+
+# Create directly-connected route in lr12
+check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 
"192.168.0.1/24"
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 |
+             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl
+192.168.0.0/24 169.254.101.2
+])
+
+ovn_as az2
+check ovn-nbctl --wait=sb set Logical_Router lr12 option:dynamic-routing=true \
+    option:dynamic-routing-redistribute="connected,static"
+check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1 00:00:00:00:ff:01 
10.0.0.1/24
+dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)
+datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)
+
+check_uuid ovn-sbctl create Learned_Route \
+    datapath=$datapath                    \
+    logical_port=$dr1                     \
+    ip_prefix=192.168.1.0/24              \
+    nexthop=10.0.0.20
+
+# Check Learned_Route adv in ovn-ic
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |
+             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl
+10.0.0.0/24 169.254.101.2
+192.168.0.0/24 169.254.101.2
+192.168.1.0/24 169.254.101.2
+])
+
+ovn_as az1
+check ovn-nbctl --wait=sb set Logical_Router lr11 option:dynamic-routing=true \
+    option:dynamic-routing-redistribute="connected,static"
+# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes
+check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24
+check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24
+check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24
+
+
+ovn_as az1
+check ovn-nbctl --wait=sb set Logical_Router lr11 \
+    option:dynamic-routing-redistribute="connected,static,hub-spoke"
+# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes
+# Route 192.168.1.0/24 is learned by DR from other logical routes (lr12)
+# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing in lr11
+check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24
+check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24
+check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24
+
+ovn_as az1
+check ovn-nbctl --wait=sb set Logical_Router lr11 \
+    option:dynamic-routing-redistribute="connected,static"
+
+check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24
+check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24
+check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24
+
+OVN_CLEANUP_IC([az1], [az2])
+
+AT_CLEANUP
+])
-- 
2.43.0


-- 




_'Esta mensagem é direcionada apenas para os endereços constantes no 
cabeçalho inicial. Se você não está listado nos endereços constantes no 
cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa 
mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão 
imediatamente anuladas e proibidas'._


* **'Apesar do Magazine Luiza tomar 
todas as precauções razoáveis para assegurar que nenhum vírus esteja 
presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por 
quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*



_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to