Em sex., 10 de abr. de 2026 às 08:07, Lucas Vargas Dias < [email protected]> escreveu:
> Hi Ales > > Thanks for your review. > > > Em sex., 10 de abr. de 2026 às 06:06, Ales Musil <[email protected]> > escreveu: > >> >> >> On Tue, Feb 3, 2026 at 9:24 PM Lucas Vargas Dias via dev < >> [email protected]> wrote: >> >>> 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]> >>> --- >>> >> >> Hi Lucas, >> >> sorry for the delay. I have a few comments down below. It also needs a >> rebase. >> >> >>> 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 2a2b5e12d..6002820f3 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: >>> @@ -98,6 +100,10 @@ Post v25.09.0 >>> reserving an unused IP from the backend's subnet. This change >>> allows >>> using LRP IPs directly, eliminating the need to reserve additional >>> IPs >>> per backend port. >>> + - 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); >>> >> >> This is never updated for existing routes, should we do that too? >> > > I forgot this for the existing routes. > > Even using the new origin (ROUTE_ORIGIN_CONNECTED_DYNAMIC), do you think it is necessary to fill the external_ids? > >> >>> >>> 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 b4bb4ba6d..fbb75533c 100644 >>> --- a/northd/northd.c >>> +++ b/northd/northd.c >>> @@ -870,6 +870,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", >>> @@ -12034,7 +12038,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; >>> } >>> @@ -12129,6 +12136,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 eb5c15f34..e6ed2cc3e 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, >>> @@ -826,6 +827,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, >>> >> >> This is very dangerous, it means that any change >> of external_ids will wake up northd. I think it will be safer >> to make it an option as we track those already. >> >> On a second thought and looking through the >> is there a reason why we can't just add another origin? >> We check the origin anyway in northd, so having >> something like: >> >> #define ROUTE_ORIGIN_CONNECTED_DYNAMIC "connected-dynamic" >> >> That would avoid the tracking of external_ids, extra definiton >> of an option and would be probably smaller change in the >> ovn-ic overall, WDYT? >> > > I agree, we can add a new origin. I'll adjust. > > > >> >> &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 1acbf202b..5f9b47491 100644 >>> --- a/ovn-nb.xml >>> +++ b/ovn-nb.xml >>> @@ -3374,6 +3374,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" >>> @@ -4461,6 +4468,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 >>> @@ -4823,6 +4837,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 >>> + >>> >> >> I would add an extra check that removed the hub-spoke again just to be >> sure. >> > > I agree > > >> >> >>> +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 >>> >>> >> Regards, >> Ales >> > -- _‘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
