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 | 6 ++
ic/ovn-ic.c | 28 +++++++---
northd/en-advertised-route-sync.c | 3 +
northd/northd.c | 10 +++-
northd/northd.h | 5 +-
northd/ovn-northd.c | 1 -
ovn-nb.xml | 21 +++++++
tests/ovn-ic.at | 92 +++++++++++++++++++++++++++++++
8 files changed, 156 insertions(+), 10 deletions(-)
diff --git a/NEWS b/NEWS
index b7268c835..7ecc0d1cb 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,8 @@ Post v25.09.0
* Add the "options:dynamic-routing-no-learning" to Logical Routers ports.
If set to true, router port will not learn routes and will forget
learned routes. This option has priority over its router counterpart.
+ * 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:
@@ -93,6 +95,10 @@ Post v25.09.0
other_config column.
- Introduce the capability to specify multiple ips for ovn-evpn-local-ip
option.
+ - Add the external_ids:ic-source-dynamic key for
+ Logical_Router_Static_Route to indicate whether a learned OVN-IC route
+ originated from dynamic routing sources in the advertising availability
+ zone.
OVN v25.09.0 - xxx xx xxxx
--------------------------
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index fd5ecefb3..e9fff2d4d 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;
@@ -1554,7 +1555,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);
@@ -1573,6 +1574,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;
@@ -1649,7 +1651,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
@@ -1659,7 +1661,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;
@@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const
char *network,
/* 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);
+ NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,
+ is_src_dynamic);
}
static void
@@ -1769,7 +1773,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);
}
@@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,
nbrec_logical_router_static_route_update_options_setkey(
nb_route, "origin", isb_route->origin);
free(uuid_s);
+ bool is_src_dynamic = smap_get_bool(&isb_route->external_ids,
+ "ic-source-dynamic", false);
+ char *ic_source_dynamic_str = is_src_dynamic ?
+ "true" : "false";
+ nbrec_logical_router_static_route_update_external_ids_setkey(
+ nb_route, "ic-source-dynamic", ic_source_dynamic_str);
nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,
nb_route);
}
@@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct ic_route_info
*route_adv,
"ic-route-tag");
}
}
+
+ char *ic_src_dynamic_str = route_adv->is_src_dynamic ? "true" : "false";
+ icsbrec_route_update_external_ids_setkey(isb_route, "ic-source-dynamic",
+ ic_src_dynamic_str);
}
/* Sync routes from routes_ad to IC-SB. */
@@ -2372,7 +2386,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. */
@@ -2427,7 +2441,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/northd/en-advertised-route-sync.c
b/northd/en-advertised-route-sync.c
index be771391d..be046769f 100644
--- a/northd/en-advertised-route-sync.c
+++ b/northd/en-advertised-route-sync.c
@@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset
*host_route_lrps,
return drr_mode_NAT_is_set(drr);
case ROUTE_SOURCE_LB:
return drr_mode_LB_is_set(drr);
+ case ROUTE_SOURCE_IC_DYNAMIC:
+ return drr_mode_IC_DYNAMIC_is_set(drr);
case ROUTE_SOURCE_LEARNED:
OVS_NOT_REACHED();
default:
@@ -745,6 +747,7 @@ advertise_route_track_od(struct advertised_route_sync_data
*data,
&tracked_op->od->nbr->header_.uuid);
}
break;
+ case ROUTE_SOURCE_IC_DYNAMIC:
case ROUTE_SOURCE_CONNECTED:
case ROUTE_SOURCE_STATIC:
break;
diff --git a/northd/northd.c b/northd/northd.c
index adaa94e85..ebd9ccc9a 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -868,6 +868,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",
@@ -11894,7 +11898,10 @@ parsed_routes_add_static(const struct ovn_datapath *od,
enum route_source source;
if (!strcmp(smap_get_def(&route->options, "origin", ""),
ROUTE_ORIGIN_CONNECTED)) {
- source = ROUTE_SOURCE_CONNECTED;
+ bool ic_src_dynamic = smap_get_bool(&route->external_ids,
+ "ic-source-dynamic", false);
+ source = ic_src_dynamic ?
+ ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;
} else {
source = ROUTE_SOURCE_STATIC;
}
@@ -11989,6 +11996,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 e4d7de9f9..62e2cf689 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -372,7 +372,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,
@@ -825,6 +826,8 @@ enum route_source {
ROUTE_SOURCE_NAT,
/* The route is derived from a LB's VIP. */
ROUTE_SOURCE_LB,
+ /* 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 7d7568c6f..bc3969053 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-nb.xml b/ovn-nb.xml
index e9ca27413..09386470b 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -3371,6 +3371,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"
@@ -4458,6 +4465,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
@@ -4820,6 +4834,13 @@ or
database.
</column>
+ <column name="external_ids" key="ic-source-dynamic">
+ <code>ovn-ic</code> populates this key for routes learned from
+ <ref db="OVN_IC_Southbound"/>. The value is <code>true</code> if the
+ learned route originated from dynamic sources (e.g. learned routes)
+ in the advertising availability zone, otherwise <code>false</code>.
+ </column>
+
<group title="Common Columns">
<column name="external_ids">
See <em>External IDs</em> at the beginning of this document.
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 370a755be..a62d02da0 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])
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_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