[{"id":3646577,"web_url":"http://patchwork.ozlabs.org/comment/3646577/","msgid":"<aYSyWuEQ45DktH7t@lore-rh-laptop>","list_archive_url":null,"date":"2026-02-05T15:08:10","subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","submitter":{"id":73083,"url":"http://patchwork.ozlabs.org/api/people/73083/","name":"Lorenzo Bianconi","email":"lorenzo.bianconi@redhat.com"},"content":"On Feb 03, Lucas Vargas Dias via dev wrote:\n> Consider the scenario where there are 2 AZs using ovn-ic, each AZ has\n> one LR and its LS. The LRs are interconnected by a transit switch.\n> On each AZ, we can configure the dynamic routing and exchange routes\n> via BGP with external BGP speakers.\n> \n> AZ1\n> LS1 - LR1 - BGP Speaker1 - Local subnet1\n>        \\\n>    -----------------------\n>     transit switch\n>    -----------------------\n> AZ2    /\n> LS2 - LR2 - BGP Speaker2 - Local subnet2\n> \n> The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will\n> not be redistributed to BGP Speaker2 and it also happens with LR1.\n> This scenario uses the network's hub-and-spoke terminology where we can\n> enable the hub-spoke on the LR for such redistribution.\n> subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.\n> Also, consider the same scenario, but LR1 and LR2 learn the same subnet\n> for redundancy, hub-spoke option is disabled to not adv the subnet learned\n> from BGP and advertised in ovn-ic in BGP speakers.\n> \n> Signed-off-by: Lucas Vargas Dias <lucas.vdias@luizalabs.com>\n\nAcked-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>\n\n> ---\n>  NEWS                              |  6 ++\n>  ic/ovn-ic.c                       | 28 +++++++---\n>  northd/en-advertised-route-sync.c |  3 +\n>  northd/northd.c                   | 10 +++-\n>  northd/northd.h                   |  5 +-\n>  northd/ovn-northd.c               |  1 -\n>  ovn-nb.xml                        | 21 +++++++\n>  tests/ovn-ic.at                   | 92 +++++++++++++++++++++++++++++++\n>  8 files changed, 156 insertions(+), 10 deletions(-)\n> \n> diff --git a/NEWS b/NEWS\n> index 2a2b5e12d..6002820f3 100644\n> --- a/NEWS\n> +++ b/NEWS\n> @@ -40,6 +40,8 @@ Post v25.09.0\n>       * Add the \"options:dynamic-routing-no-learning\" to Logical Routers ports.\n>         If set to true, router port will not learn routes and will forget\n>         learned routes. This option has priority over its router counterpart.\n> +     * Add support for hub-and-spoke propagation via the \"hub-spoke\" option\n> +       in dynamic-routing-redistribute settings.\n>     - Add support for Network Function insertion in OVN with stateful traffic\n>       redirection capability in Logical Switch datapath. The feature introduces\n>       three new NB database tables:\n> @@ -98,6 +100,10 @@ Post v25.09.0\n>       reserving an unused IP from the backend's subnet. This change allows\n>       using LRP IPs directly, eliminating the need to reserve additional IPs\n>       per backend port.\n> +   - Add the external_ids:ic-source-dynamic key for\n> +     Logical_Router_Static_Route to indicate whether a learned OVN-IC route\n> +     originated from dynamic routing sources in the advertising availability\n> +     zone.\n>  \n>  OVN v25.09.0 - xxx xx xxxx\n>  --------------------------\n> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\n> index fd5ecefb3..e9fff2d4d 100644\n> --- a/ic/ovn-ic.c\n> +++ b/ic/ovn-ic.c\n> @@ -1283,6 +1283,7 @@ struct ic_route_info {\n>      struct in6_addr prefix;\n>      unsigned int plen;\n>      struct in6_addr nexthop;\n> +    bool is_src_dynamic;\n>      const char *origin;\n>      const char *route_table;\n>      const char *route_tag;\n> @@ -1554,7 +1555,7 @@ add_to_routes_ad(struct hmap *routes_ad, const struct in6_addr prefix,\n>                   const struct nbrec_logical_router_static_route *nb_route,\n>                   const struct nbrec_logical_router *nb_lr,\n>                   const struct nbrec_load_balancer *nb_lb,\n> -                 const char *route_tag)\n> +                 const char *route_tag, bool is_src_dynamic)\n>  {\n>      ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);\n>  \n> @@ -1573,6 +1574,7 @@ add_to_routes_ad(struct hmap *routes_ad, const struct in6_addr prefix,\n>          ic_route->nb_route = nb_route;\n>          ic_route->origin = origin;\n>          ic_route->route_table = route_table;\n> +        ic_route->is_src_dynamic = is_src_dynamic;\n>          ic_route->nb_lrp = nb_lrp;\n>          ic_route->nb_lr = nb_lr;\n>          ic_route->nb_lb = nb_lb;\n> @@ -1649,7 +1651,7 @@ add_static_to_routes_ad(\n>  \n>      add_to_routes_ad(routes_ad, prefix, plen, nexthop, ROUTE_ORIGIN_STATIC,\n>                       nb_route->route_table, NULL, nb_route, nb_lr,\n> -                     NULL, route_tag);\n> +                     NULL, route_tag, false);\n>  }\n>  \n>  static void\n> @@ -1659,7 +1661,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,\n>                           const struct smap *nb_options,\n>                           const struct nbrec_logical_router *nb_lr,\n>                           const char *route_tag,\n> -                         const struct nbrec_logical_router_port *ts_lrp)\n> +                         const struct nbrec_logical_router_port *ts_lrp,\n> +                         bool is_src_dynamic)\n>  {\n>      struct in6_addr prefix, nexthop;\n>      unsigned int plen;\n> @@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,\n>  \n>      /* directly-connected routes go to <main> route table */\n>      add_to_routes_ad(routes_ad, prefix, plen, nexthop, ROUTE_ORIGIN_CONNECTED,\n> -                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);\n> +                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,\n> +                     is_src_dynamic);\n>  }\n>  \n>  static void\n> @@ -1769,7 +1773,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad, const char *vip_key,\n>  \n>      /* Lb vip routes go to <main> route table */\n>      add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,\n> -                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);\n> +                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);\n>  out:\n>      free(vip_str);\n>  }\n> @@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,\n>                  nbrec_logical_router_static_route_update_options_setkey(\n>                      nb_route, \"origin\", isb_route->origin);\n>                  free(uuid_s);\n> +                bool is_src_dynamic = smap_get_bool(&isb_route->external_ids,\n> +                    \"ic-source-dynamic\", false);\n> +                char *ic_source_dynamic_str = is_src_dynamic ?\n> +                    \"true\" : \"false\";\n> +                nbrec_logical_router_static_route_update_external_ids_setkey(\n> +                    nb_route, \"ic-source-dynamic\", ic_source_dynamic_str);\n>                  nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,\n>                      nb_route);\n>              }\n> @@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct ic_route_info *route_adv,\n>                                                       \"ic-route-tag\");\n>          }\n>      }\n> +\n> +    char *ic_src_dynamic_str = route_adv->is_src_dynamic ? \"true\" : \"false\";\n> +    icsbrec_route_update_external_ids_setkey(isb_route, \"ic-source-dynamic\",\n> +                                             ic_src_dynamic_str);\n>  }\n>  \n>  /* Sync routes from routes_ad to IC-SB. */\n> @@ -2372,7 +2386,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>                  add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,\n>                                           ts_port_addrs,\n>                                           &nb_global->options,\n> -                                         lr, route_tag, ts_lrp);\n> +                                         lr, route_tag, ts_lrp, false);\n>              }\n>          } else {\n>              /* The router port of the TS port is ignored. */\n> @@ -2427,7 +2441,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>          add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,\n>                                   ts_port_addrs,\n>                                   &nb_global->options,\n> -                                 lr, route_tag, ts_lrp);\n> +                                 lr, route_tag, ts_lrp, true);\n>      }\n>      sbrec_learned_route_index_destroy_row(filter);\n>  }\n> diff --git a/northd/en-advertised-route-sync.c b/northd/en-advertised-route-sync.c\n> index be771391d..be046769f 100644\n> --- a/northd/en-advertised-route-sync.c\n> +++ b/northd/en-advertised-route-sync.c\n> @@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset *host_route_lrps,\n>          return drr_mode_NAT_is_set(drr);\n>      case ROUTE_SOURCE_LB:\n>          return drr_mode_LB_is_set(drr);\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n> +        return drr_mode_IC_DYNAMIC_is_set(drr);\n>      case ROUTE_SOURCE_LEARNED:\n>          OVS_NOT_REACHED();\n>      default:\n> @@ -745,6 +747,7 @@ advertise_route_track_od(struct advertised_route_sync_data *data,\n>                             &tracked_op->od->nbr->header_.uuid);\n>          }\n>          break;\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>      case ROUTE_SOURCE_CONNECTED:\n>      case ROUTE_SOURCE_STATIC:\n>          break;\n> diff --git a/northd/northd.c b/northd/northd.c\n> index b4bb4ba6d..fbb75533c 100644\n> --- a/northd/northd.c\n> +++ b/northd/northd.c\n> @@ -870,6 +870,10 @@ parse_dynamic_routing_redistribute(\n>              out |= DRRM_LB;\n>              continue;\n>          }\n> +        if (!strcmp(token, \"hub-spoke\")) {\n> +            out |= DRRM_IC_DYNAMIC;\n> +            continue;\n> +        }\n>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n>          VLOG_WARN_RL(&rl,\n>                       \"unknown dynamic-routing-redistribute option '%s' on %s\",\n> @@ -12034,7 +12038,10 @@ parsed_routes_add_static(const struct ovn_datapath *od,\n>      enum route_source source;\n>      if (!strcmp(smap_get_def(&route->options, \"origin\", \"\"),\n>                  ROUTE_ORIGIN_CONNECTED)) {\n> -        source = ROUTE_SOURCE_CONNECTED;\n> +        bool ic_src_dynamic = smap_get_bool(&route->external_ids,\n> +                                            \"ic-source-dynamic\", false);\n> +        source = ic_src_dynamic ?\n> +                 ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;\n>      } else {\n>          source = ROUTE_SOURCE_STATIC;\n>      }\n> @@ -12129,6 +12136,7 @@ route_source_to_offset(enum route_source source)\n>  {\n>      switch (source) {\n>      case ROUTE_SOURCE_CONNECTED:\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>          return ROUTE_PRIO_OFFSET_CONNECTED;\n>      case ROUTE_SOURCE_STATIC:\n>          return ROUTE_PRIO_OFFSET_STATIC;\n> diff --git a/northd/northd.h b/northd/northd.h\n> index eb5c15f34..e6ed2cc3e 100644\n> --- a/northd/northd.h\n> +++ b/northd/northd.h\n> @@ -372,7 +372,8 @@ struct mcast_port_info {\n>      DRR_MODE(CONNECTED_AS_HOST, 1) \\\n>      DRR_MODE(STATIC,            2) \\\n>      DRR_MODE(NAT,               3) \\\n> -    DRR_MODE(LB,                4)\n> +    DRR_MODE(LB,                4) \\\n> +    DRR_MODE(IC_DYNAMIC,        5)\n>  \n>  enum dynamic_routing_redistribute_mode_bits {\n>  #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,\n> @@ -826,6 +827,8 @@ enum route_source {\n>      ROUTE_SOURCE_NAT,\n>      /* The route is derived from a LB's VIP. */\n>      ROUTE_SOURCE_LB,\n> +    /* The route is derived from an ovn-controller and advertised to IC. */\n> +    ROUTE_SOURCE_IC_DYNAMIC,\n>  };\n>  \n>  struct parsed_route {\n> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\n> index 7d7568c6f..bc3969053 100644\n> --- a/northd/ovn-northd.c\n> +++ b/northd/ovn-northd.c\n> @@ -905,7 +905,6 @@ main(int argc, char *argv[])\n>          &nbrec_load_balancer_col_external_ids,\n>          &nbrec_load_balancer_health_check_col_external_ids,\n>          &nbrec_logical_router_policy_col_external_ids,\n> -        &nbrec_logical_router_static_route_col_external_ids,\n>          &nbrec_meter_col_external_ids,\n>          &nbrec_meter_band_col_external_ids,\n>          &nbrec_mirror_col_external_ids,\n> diff --git a/ovn-nb.xml b/ovn-nb.xml\n> index 1acbf202b..5f9b47491 100644\n> --- a/ovn-nb.xml\n> +++ b/ovn-nb.xml\n> @@ -3374,6 +3374,13 @@ or\n>            Logical Switch.\n>          </p>\n>  \n> +        <p>\n> +          If <code>hub-spoke</code> is in the list then northd will synchronize\n> +          dynamic routes learned through OVN-IC from other routers into the\n> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table, enabling\n> +          hub-and-spoke propagation.\n> +        </p>\n> +\n>          <p>\n>            This value can be overwritten on a per LRP basis using\n>            <ref column=\"options\" key=\"dynamic-routing-redistribute\"\n> @@ -4461,6 +4468,13 @@ or\n>            via shared Logical Switch.\n>          </p>\n>  \n> +        <p>\n> +          If <code>hub-spoke</code> is in the list then northd will synchronize\n> +          dynamic routes learned through OVN-IC from other routers into the\n> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table, enabling\n> +          hub-and-spoke propagation.\n> +        </p>\n> +\n>          <p>\n>            If not set the value from <ref column=\"options\"\n>            key=\"dynamic-routing-redistribute\" table=\"Logical_Router\"/> on the\n> @@ -4823,6 +4837,13 @@ or\n>        database.\n>      </column>\n>  \n> +    <column name=\"external_ids\" key=\"ic-source-dynamic\">\n> +      <code>ovn-ic</code> populates this key for routes learned from\n> +      <ref db=\"OVN_IC_Southbound\"/>. The value is <code>true</code> if the\n> +      learned route originated from dynamic sources (e.g. learned routes)\n> +      in the advertising availability zone, otherwise <code>false</code>.\n> +    </column>\n> +\n>      <group title=\"Common Columns\">\n>        <column name=\"external_ids\">\n>          See <em>External IDs</em> at the beginning of this document.\n> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\n> index 370a755be..a62d02da0 100644\n> --- a/tests/ovn-ic.at\n> +++ b/tests/ovn-ic.at\n> @@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])\n>  \n>  AT_CLEANUP\n>  ])\n> +\n> +\n> +OVN_FOR_EACH_NORTHD([\n> +AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route - hub and spoke mode])\n> +\n> +ovn_init_ic_db\n> +\n> +for i in 1 2; do\n> +    ovn_start az$i\n> +    ovn_as az$i\n> +\n> +    # Enable route learning at AZ level\n> +    check ovn-nbctl set nb_global . options:ic-route-learn=true\n> +    # Enable route advertising at AZ level\n> +    check ovn-nbctl set nb_global . options:ic-route-adv=true\n> +done\n> +\n> +# Create new transit switches and LRs. Test topology is next:\n> +#\n> +#\n> +# logical router (lr11) - transit switch (ts11) - logical router (lr12)\n> +#\n> +#\n> +\n> +# Create lr11, lr12 and ts11 and connect them\n> +for i in 1 2; do\n> +    ovn_as az$i\n> +\n> +    lr=lr1$i\n> +    check ovn-nbctl lr-add $lr\n> +\n> +    ts=ts11\n> +    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts\n> +\n> +    lrp=lrp-$lr-$ts\n> +    lsp=lsp-$ts-$lr\n> +    # Create LRP and connect to TS\n> +    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i 169.254.101.$i/24\n> +    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp\n> +done\n> +\n> +# Create directly-connected route in lr12\n> +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 \"192.168.0.1/24\"\n> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 |\n> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n> +192.168.0.0/24 169.254.101.2\n> +])\n> +\n> +ovn_as az2\n> +check ovn-nbctl --wait=sb set Logical_Router lr12 option:dynamic-routing=true \\\n> +    option:dynamic-routing-redistribute=\"connected,static\"\n> +check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1 00:00:00:00:ff:01 10.0.0.1/24\n> +dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)\n> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)\n> +\n> +check_uuid ovn-sbctl create Learned_Route \\\n> +    datapath=$datapath                    \\\n> +    logical_port=$dr1                     \\\n> +    ip_prefix=192.168.1.0/24              \\\n> +    nexthop=10.0.0.20\n> +\n> +# Check Learned_Route adv in ovn-ic\n> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |\n> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n> +10.0.0.0/24 169.254.101.2\n> +192.168.0.0/24 169.254.101.2\n> +192.168.1.0/24 169.254.101.2\n> +])\n> +\n> +ovn_as az1\n> +check ovn-nbctl --wait=sb set Logical_Router lr11 option:dynamic-routing=true \\\n> +    option:dynamic-routing-redistribute=\"connected,static\"\n> +# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n> +check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24\n> +\n> +\n> +ovn_as az1\n> +check ovn-nbctl --wait=sb set Logical_Router lr11 \\\n> +    option:dynamic-routing-redistribute=\"connected,static,hub-spoke\"\n> +# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes\n> +# Route 192.168.1.0/24 is learned by DR from other logical routes (lr12)\n> +# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing in lr11\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24\n> +\n> +OVN_CLEANUP_IC([az1], [az2])\n> +\n> +AT_CLEANUP\n> +])\n> -- \n> 2.43.0\n> \n> \n> -- \n> \n> \n> \n> \n> _'Esta mensagem é direcionada apenas para os endereços constantes no \n> cabeçalho inicial. Se você não está listado nos endereços constantes no \n> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa \n> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão \n> imediatamente anuladas e proibidas'._\n> \n> \n> * **'Apesar do Magazine Luiza tomar \n> todas as precauções razoáveis para assegurar que nenhum vírus esteja \n> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por \n> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*\n> \n> \n> \n> _______________________________________________\n> dev mailing list\n> dev@openvswitch.org\n> https://mail.openvswitch.org/mailman/listinfo/ovs-dev\n>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=g6lCECu+;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=google header.b=IGBpVzG5;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp4.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=g6lCECu+;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=google header.b=IGBpVzG5","smtp2.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","smtp2.osuosl.org;\n dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.a=rsa-sha256 header.s=mimecast20190719 header.b=g6lCECu+;\n dkim=pass (2048-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=google header.b=IGBpVzG5"],"Received":["from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f6LFm5fj0z1xvC\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 06 Feb 2026 02:08:27 +1100 (AEDT)","from localhost (localhost [127.0.0.1])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 9ED3F411E6;\n\tThu,  5 Feb 2026 15:08:24 +0000 (UTC)","from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id jmNtdV8q7l_w; Thu,  5 Feb 2026 15:08:22 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp4.osuosl.org (Postfix) with ESMTPS id B39B2411EB;\n\tThu,  5 Feb 2026 15:08:22 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 88CCDC04FB;\n\tThu,  5 Feb 2026 15:08:22 +0000 (UTC)","from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 8DD84C04FA\n for <dev@openvswitch.org>; Thu,  5 Feb 2026 15:08:21 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 771DE40E6A\n for <dev@openvswitch.org>; Thu,  5 Feb 2026 15:08:21 +0000 (UTC)","from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id d2vNDsoGzLbz for <dev@openvswitch.org>;\n Thu,  5 Feb 2026 15:08:20 +0000 (UTC)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by smtp2.osuosl.org (Postfix) with ESMTPS id D3F9D4032C\n for <dev@openvswitch.org>; Thu,  5 Feb 2026 15:08:19 +0000 (UTC)","from mail-wr1-f70.google.com (mail-wr1-f70.google.com\n [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-440-pYQy5iJ5Oz277Xb2eUj1Kw-1; Thu, 05 Feb 2026 10:08:16 -0500","by mail-wr1-f70.google.com with SMTP id\n ffacd0b85a97d-43614ed5d3bso825573f8f.1\n for <dev@openvswitch.org>; Thu, 05 Feb 2026 07:08:15 -0800 (PST)","from localhost (77-32-99-124.dyn.eolo.it. [77.32.99.124])\n by smtp.gmail.com with ESMTPSA id\n ffacd0b85a97d-43618057f7csm14549479f8f.23.2026.02.05.07.08.12\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 05 Feb 2026 07:08:12 -0800 (PST)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp4.osuosl.org B39B2411EB","OpenDKIM Filter v2.11.0 smtp2.osuosl.org D3F9D4032C"],"Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124;\n helo=us-smtp-delivery-124.mimecast.com;\n envelope-from=lorenzo.bianconi@redhat.com; receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp2.osuosl.org D3F9D4032C","DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1770304098;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=cUSvfGdu+f2o8xpOpUxFiQi96Nz1eK380baCexVqfJc=;\n b=g6lCECu+zFhrSgrB5xgXjgmlF7B5XpHNqKQcYrARD6/1x9Ddo/J/0oOcpll37e8pjh91bR\n qqs7wdb2gAfVl6KLvW+cJBt373gk4/rD5x1GQFvTewxGx8NIdcosq9BjWPHjXGynpQ6kWh\n rUfDXyzT1ZmslQhodmNLDVnGl3kLssw=","v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=redhat.com; s=google; t=1770304095; x=1770908895; darn=openvswitch.org;\n h=in-reply-to:content-disposition:mime-version:references:message-id\n :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to;\n bh=cUSvfGdu+f2o8xpOpUxFiQi96Nz1eK380baCexVqfJc=;\n b=IGBpVzG5tFgOmEXKvaoutGgN3ska72XIxjD4/ed/W9Lfk/tjJ84Ynmcy6aLU5tyUU4\n ywirrTR4yRvnGiV2qwHXofeVYLRWseWLLXQyqWNTR9+KYxrc/Ivj4h5DAbo6DGORs0/N\n C+Gdo3ZUgszH9dEBlv4K64bquy+zlnXj80dSrVZqq99XfmS1n1aJfWAPAW91BbfLmXYe\n M5F9Gn7yeQqrFblEogWO/l4R/Mh1JdTZRksa4PiJGYxpKycq4h6Zrw9ll+pm3es3zAXH\n 50q4D3JkQMluKp6XnfSseSE49pSttHSh5ee2z2sgIZFunRMpET/K3zjTm43hJMz4N7ZQ\n wVGQ=="],"X-MC-Unique":"pYQy5iJ5Oz277Xb2eUj1Kw-1","X-Mimecast-MFC-AGG-ID":"pYQy5iJ5Oz277Xb2eUj1Kw_1770304095","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1770304095; x=1770908895;\n h=in-reply-to:content-disposition:mime-version:references:message-id\n :subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=cUSvfGdu+f2o8xpOpUxFiQi96Nz1eK380baCexVqfJc=;\n b=Ee81MwUtk7s2ZF28OHCDywIxS1MKYsgrd0PFLDOH+EDg85wcfUbvFPxPzHIsyE3rB4\n GY3xLCKWyGVXC3U/3u6XiqigjiocCowNbRDCDBGOm3k36Z6profBUA7jm/3nn94WN+5k\n BnwdZdJdcUgw6YsX9dWemfpY1fQAWpwEaU1X8FQ/OE0GvSr9fMttzfh+iducMs/mffqR\n 1cjWWNJyBnnaU+MxXXmSMV3/747PeZuFC4DJl4fJaPhufPa6Q0XPFCSswiBfPt3Rzs0T\n I7tBmYClFWXT6sbkpzBLyfW5RsZd5krvqXgCTv+YtBUkj/Qn5aXMI+0BuQi0+wIN4Jfc\n 80Ow==","X-Gm-Message-State":"AOJu0YwXceiWHHrW0d9TgQIT/k74/Kc5XVUEXleFQ+zZEEgFKHZ6hlI8\n X9HqOjhUaGXRkly++1QIHWMOgMJhQs+2ev/Q4gRXkOpb0bM1HJBDIIpUy5t3Q5pr9Hi5wl/Ivz8\n ibsuwhv1hL3TUQFRjVIPoW4Uyu+kmdJqebbMMLgXYwkvj8mZ2BfZizw==","X-Gm-Gg":"AZuq6aJGRwdZBdfXRQPXAgEZ1lIww3xaid4pTsYen8Ww/+9bw4cuDzU1tpZ47/Ue7RK\n O5cKpS1QhkbmNiNbn/tpeKA1H84IbvL101/0RSrkQdam/zbgLL4swzeTA+xXgmKT+w3aNtaePOl\n c5+6AjZTsLwVrrirLzVGcmIg4fYEd8EkOejYmPHTOtGM2Vfx60OeCmRYvIIHTL0bX8HmntMyqXa\n E7vFdoAr0FI0Ezo8qaeQyiyQvVv5xBhenmgyP8rBgyka3lL7PE8OGJTlWDRZMoiTpeOux6ikL69\n QrdEICDyBpSvgvRTLjmW53iudRf2tBb84qgjt6fs3UjGTgpNaMLtkGVvLWs0wWfWp1Kj2lFu7y6\n 9/7S6J5mywUy5j1UYAIhk/iddFThDIltyUKzhM2k=","X-Received":["by 2002:a05:6000:4201:b0:435:b674:c9b1 with SMTP id\n ffacd0b85a97d-436213d80b0mr5581124f8f.11.1770304094364;\n Thu, 05 Feb 2026 07:08:14 -0800 (PST)","by 2002:a05:6000:4201:b0:435:b674:c9b1 with SMTP id\n ffacd0b85a97d-436213d80b0mr5581050f8f.11.1770304093649;\n Thu, 05 Feb 2026 07:08:13 -0800 (PST)"],"Date":"Thu, 5 Feb 2026 16:08:10 +0100","To":"Lucas Vargas Dias <lucas.vdias@luizalabs.com>","Cc":"dev@openvswitch.org","Message-ID":"<aYSyWuEQ45DktH7t@lore-rh-laptop>","References":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>","MIME-Version":"1.0","In-Reply-To":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>","X-Content-Filtered-By":"Mailman/MimeDel 2.1.30","Subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Lorenzo Bianconi via dev <ovs-dev@openvswitch.org>","Reply-To":"Lorenzo Bianconi <lorenzo.bianconi@redhat.com>","Content-Type":"multipart/mixed; boundary=\"===============3644488502261022801==\"","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"}},{"id":3675744,"web_url":"http://patchwork.ozlabs.org/comment/3675744/","msgid":"<CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>","list_archive_url":null,"date":"2026-04-10T09:05:57","subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","submitter":{"id":83634,"url":"http://patchwork.ozlabs.org/api/people/83634/","name":"Ales Musil","email":"amusil@redhat.com"},"content":"On Tue, Feb 3, 2026 at 9:24 PM Lucas Vargas Dias via dev <\novs-dev@openvswitch.org> wrote:\n\n> Consider the scenario where there are 2 AZs using ovn-ic, each AZ has\n> one LR and its LS. The LRs are interconnected by a transit switch.\n> On each AZ, we can configure the dynamic routing and exchange routes\n> via BGP with external BGP speakers.\n>\n> AZ1\n> LS1 - LR1 - BGP Speaker1 - Local subnet1\n>        \\\n>    -----------------------\n>     transit switch\n>    -----------------------\n> AZ2    /\n> LS2 - LR2 - BGP Speaker2 - Local subnet2\n>\n> The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will\n> not be redistributed to BGP Speaker2 and it also happens with LR1.\n> This scenario uses the network's hub-and-spoke terminology where we can\n> enable the hub-spoke on the LR for such redistribution.\n> subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.\n> Also, consider the same scenario, but LR1 and LR2 learn the same subnet\n> for redundancy, hub-spoke option is disabled to not adv the subnet learned\n> from BGP and advertised in ovn-ic in BGP speakers.\n>\n> Signed-off-by: Lucas Vargas Dias <lucas.vdias@luizalabs.com>\n> ---\n>\n\nHi Lucas,\n\nsorry for the delay. I have a few comments down below. It also needs a\nrebase.\n\n\n>  NEWS                              |  6 ++\n>  ic/ovn-ic.c                       | 28 +++++++---\n>  northd/en-advertised-route-sync.c |  3 +\n>  northd/northd.c                   | 10 +++-\n>  northd/northd.h                   |  5 +-\n>  northd/ovn-northd.c               |  1 -\n>  ovn-nb.xml                        | 21 +++++++\n>  tests/ovn-ic.at                   | 92 +++++++++++++++++++++++++++++++\n>  8 files changed, 156 insertions(+), 10 deletions(-)\n>\n> diff --git a/NEWS b/NEWS\n> index 2a2b5e12d..6002820f3 100644\n> --- a/NEWS\n> +++ b/NEWS\n> @@ -40,6 +40,8 @@ Post v25.09.0\n>       * Add the \"options:dynamic-routing-no-learning\" to Logical Routers\n> ports.\n>         If set to true, router port will not learn routes and will forget\n>         learned routes. This option has priority over its router\n> counterpart.\n> +     * Add support for hub-and-spoke propagation via the \"hub-spoke\"\n> option\n> +       in dynamic-routing-redistribute settings.\n>     - Add support for Network Function insertion in OVN with stateful\n> traffic\n>       redirection capability in Logical Switch datapath. The feature\n> introduces\n>       three new NB database tables:\n> @@ -98,6 +100,10 @@ Post v25.09.0\n>       reserving an unused IP from the backend's subnet. This change allows\n>       using LRP IPs directly, eliminating the need to reserve additional\n> IPs\n>       per backend port.\n> +   - Add the external_ids:ic-source-dynamic key for\n> +     Logical_Router_Static_Route to indicate whether a learned OVN-IC\n> route\n> +     originated from dynamic routing sources in the advertising\n> availability\n> +     zone.\n>\n>  OVN v25.09.0 - xxx xx xxxx\n>  --------------------------\n> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\n> index fd5ecefb3..e9fff2d4d 100644\n> --- a/ic/ovn-ic.c\n> +++ b/ic/ovn-ic.c\n> @@ -1283,6 +1283,7 @@ struct ic_route_info {\n>      struct in6_addr prefix;\n>      unsigned int plen;\n>      struct in6_addr nexthop;\n> +    bool is_src_dynamic;\n>      const char *origin;\n>      const char *route_table;\n>      const char *route_tag;\n> @@ -1554,7 +1555,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n> struct in6_addr prefix,\n>                   const struct nbrec_logical_router_static_route *nb_route,\n>                   const struct nbrec_logical_router *nb_lr,\n>                   const struct nbrec_load_balancer *nb_lb,\n> -                 const char *route_tag)\n> +                 const char *route_tag, bool is_src_dynamic)\n>  {\n>      ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);\n>\n> @@ -1573,6 +1574,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n> struct in6_addr prefix,\n>          ic_route->nb_route = nb_route;\n>          ic_route->origin = origin;\n>          ic_route->route_table = route_table;\n> +        ic_route->is_src_dynamic = is_src_dynamic;\n>          ic_route->nb_lrp = nb_lrp;\n>          ic_route->nb_lr = nb_lr;\n>          ic_route->nb_lb = nb_lb;\n> @@ -1649,7 +1651,7 @@ add_static_to_routes_ad(\n>\n>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n> ROUTE_ORIGIN_STATIC,\n>                       nb_route->route_table, NULL, nb_route, nb_lr,\n> -                     NULL, route_tag);\n> +                     NULL, route_tag, false);\n>  }\n>\n>  static void\n> @@ -1659,7 +1661,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n> const char *network,\n>                           const struct smap *nb_options,\n>                           const struct nbrec_logical_router *nb_lr,\n>                           const char *route_tag,\n> -                         const struct nbrec_logical_router_port *ts_lrp)\n> +                         const struct nbrec_logical_router_port *ts_lrp,\n> +                         bool is_src_dynamic)\n>  {\n>      struct in6_addr prefix, nexthop;\n>      unsigned int plen;\n> @@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n> const char *network,\n>\n>      /* directly-connected routes go to <main> route table */\n>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n> ROUTE_ORIGIN_CONNECTED,\n> -                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);\n> +                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,\n> +                     is_src_dynamic);\n>  }\n>\n>  static void\n> @@ -1769,7 +1773,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad,\n> const char *vip_key,\n>\n>      /* Lb vip routes go to <main> route table */\n>      add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,\n> -                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);\n> +                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);\n>  out:\n>      free(vip_str);\n>  }\n> @@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,\n>                  nbrec_logical_router_static_route_update_options_setkey(\n>                      nb_route, \"origin\", isb_route->origin);\n>                  free(uuid_s);\n> +                bool is_src_dynamic =\n> smap_get_bool(&isb_route->external_ids,\n> +                    \"ic-source-dynamic\", false);\n> +                char *ic_source_dynamic_str = is_src_dynamic ?\n> +                    \"true\" : \"false\";\n> +\n> nbrec_logical_router_static_route_update_external_ids_setkey(\n> +                    nb_route, \"ic-source-dynamic\", ic_source_dynamic_str);\n>\n\nThis is never updated for existing routes, should we do that too?\n\n\n>\n>  nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,\n>                      nb_route);\n>              }\n> @@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct\n> ic_route_info *route_adv,\n>                                                       \"ic-route-tag\");\n>          }\n>      }\n> +\n> +    char *ic_src_dynamic_str = route_adv->is_src_dynamic ? \"true\" :\n> \"false\";\n> +    icsbrec_route_update_external_ids_setkey(isb_route,\n> \"ic-source-dynamic\",\n> +                                             ic_src_dynamic_str);\n>  }\n>\n>  /* Sync routes from routes_ad to IC-SB. */\n> @@ -2372,7 +2386,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>                  add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,\n>                                           ts_port_addrs,\n>                                           &nb_global->options,\n> -                                         lr, route_tag, ts_lrp);\n> +                                         lr, route_tag, ts_lrp, false);\n>              }\n>          } else {\n>              /* The router port of the TS port is ignored. */\n> @@ -2427,7 +2441,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>          add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,\n>                                   ts_port_addrs,\n>                                   &nb_global->options,\n> -                                 lr, route_tag, ts_lrp);\n> +                                 lr, route_tag, ts_lrp, true);\n>      }\n>      sbrec_learned_route_index_destroy_row(filter);\n>  }\n> diff --git a/northd/en-advertised-route-sync.c\n> b/northd/en-advertised-route-sync.c\n> index be771391d..be046769f 100644\n> --- a/northd/en-advertised-route-sync.c\n> +++ b/northd/en-advertised-route-sync.c\n> @@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset\n> *host_route_lrps,\n>          return drr_mode_NAT_is_set(drr);\n>      case ROUTE_SOURCE_LB:\n>          return drr_mode_LB_is_set(drr);\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n> +        return drr_mode_IC_DYNAMIC_is_set(drr);\n>      case ROUTE_SOURCE_LEARNED:\n>          OVS_NOT_REACHED();\n>      default:\n> @@ -745,6 +747,7 @@ advertise_route_track_od(struct\n> advertised_route_sync_data *data,\n>                             &tracked_op->od->nbr->header_.uuid);\n>          }\n>          break;\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>      case ROUTE_SOURCE_CONNECTED:\n>      case ROUTE_SOURCE_STATIC:\n>          break;\n> diff --git a/northd/northd.c b/northd/northd.c\n> index b4bb4ba6d..fbb75533c 100644\n> --- a/northd/northd.c\n> +++ b/northd/northd.c\n> @@ -870,6 +870,10 @@ parse_dynamic_routing_redistribute(\n>              out |= DRRM_LB;\n>              continue;\n>          }\n> +        if (!strcmp(token, \"hub-spoke\")) {\n> +            out |= DRRM_IC_DYNAMIC;\n> +            continue;\n> +        }\n>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n>          VLOG_WARN_RL(&rl,\n>                       \"unknown dynamic-routing-redistribute option '%s' on\n> %s\",\n> @@ -12034,7 +12038,10 @@ parsed_routes_add_static(const struct\n> ovn_datapath *od,\n>      enum route_source source;\n>      if (!strcmp(smap_get_def(&route->options, \"origin\", \"\"),\n>                  ROUTE_ORIGIN_CONNECTED)) {\n> -        source = ROUTE_SOURCE_CONNECTED;\n> +        bool ic_src_dynamic = smap_get_bool(&route->external_ids,\n> +                                            \"ic-source-dynamic\", false);\n> +        source = ic_src_dynamic ?\n> +                 ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;\n>      } else {\n>          source = ROUTE_SOURCE_STATIC;\n>      }\n> @@ -12129,6 +12136,7 @@ route_source_to_offset(enum route_source source)\n>  {\n>      switch (source) {\n>      case ROUTE_SOURCE_CONNECTED:\n> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>          return ROUTE_PRIO_OFFSET_CONNECTED;\n>      case ROUTE_SOURCE_STATIC:\n>          return ROUTE_PRIO_OFFSET_STATIC;\n> diff --git a/northd/northd.h b/northd/northd.h\n> index eb5c15f34..e6ed2cc3e 100644\n> --- a/northd/northd.h\n> +++ b/northd/northd.h\n> @@ -372,7 +372,8 @@ struct mcast_port_info {\n>      DRR_MODE(CONNECTED_AS_HOST, 1) \\\n>      DRR_MODE(STATIC,            2) \\\n>      DRR_MODE(NAT,               3) \\\n> -    DRR_MODE(LB,                4)\n> +    DRR_MODE(LB,                4) \\\n> +    DRR_MODE(IC_DYNAMIC,        5)\n>\n>  enum dynamic_routing_redistribute_mode_bits {\n>  #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,\n> @@ -826,6 +827,8 @@ enum route_source {\n>      ROUTE_SOURCE_NAT,\n>      /* The route is derived from a LB's VIP. */\n>      ROUTE_SOURCE_LB,\n> +    /* The route is derived from an ovn-controller and advertised to IC.\n> */\n> +    ROUTE_SOURCE_IC_DYNAMIC,\n>  };\n>\n>  struct parsed_route {\n> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\n> index 7d7568c6f..bc3969053 100644\n> --- a/northd/ovn-northd.c\n> +++ b/northd/ovn-northd.c\n> @@ -905,7 +905,6 @@ main(int argc, char *argv[])\n>          &nbrec_load_balancer_col_external_ids,\n>          &nbrec_load_balancer_health_check_col_external_ids,\n>          &nbrec_logical_router_policy_col_external_ids,\n> -        &nbrec_logical_router_static_route_col_external_ids,\n>\n\nThis is very dangerous, it means that any change\nof external_ids will wake up northd. I think it will be safer\nto make it an option as we track those already.\n\nOn a second thought and looking through the\nis there a reason why we can't just add another origin?\nWe check the origin anyway in northd, so having\nsomething like:\n\n#define ROUTE_ORIGIN_CONNECTED_DYNAMIC \"connected-dynamic\"\n\nThat would avoid the tracking of external_ids, extra definiton\nof an option and would be probably smaller change in the\novn-ic overall, WDYT?\n\n         &nbrec_meter_col_external_ids,\n>          &nbrec_meter_band_col_external_ids,\n>          &nbrec_mirror_col_external_ids,\n> diff --git a/ovn-nb.xml b/ovn-nb.xml\n> index 1acbf202b..5f9b47491 100644\n> --- a/ovn-nb.xml\n> +++ b/ovn-nb.xml\n> @@ -3374,6 +3374,13 @@ or\n>            Logical Switch.\n>          </p>\n>\n> +        <p>\n> +          If <code>hub-spoke</code> is in the list then northd will\n> synchronize\n> +          dynamic routes learned through OVN-IC from other routers into\n> the\n> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n> enabling\n> +          hub-and-spoke propagation.\n> +        </p>\n> +\n>          <p>\n>            This value can be overwritten on a per LRP basis using\n>            <ref column=\"options\" key=\"dynamic-routing-redistribute\"\n> @@ -4461,6 +4468,13 @@ or\n>            via shared Logical Switch.\n>          </p>\n>\n> +        <p>\n> +          If <code>hub-spoke</code> is in the list then northd will\n> synchronize\n> +          dynamic routes learned through OVN-IC from other routers into\n> the\n> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n> enabling\n> +          hub-and-spoke propagation.\n> +        </p>\n> +\n>          <p>\n>            If not set the value from <ref column=\"options\"\n>            key=\"dynamic-routing-redistribute\" table=\"Logical_Router\"/> on\n> the\n> @@ -4823,6 +4837,13 @@ or\n>        database.\n>      </column>\n>\n> +    <column name=\"external_ids\" key=\"ic-source-dynamic\">\n> +      <code>ovn-ic</code> populates this key for routes learned from\n> +      <ref db=\"OVN_IC_Southbound\"/>. The value is <code>true</code> if the\n> +      learned route originated from dynamic sources (e.g. learned routes)\n> +      in the advertising availability zone, otherwise <code>false</code>.\n> +    </column>\n> +\n>      <group title=\"Common Columns\">\n>        <column name=\"external_ids\">\n>          See <em>External IDs</em> at the beginning of this document.\n> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\n> index 370a755be..a62d02da0 100644\n> --- a/tests/ovn-ic.at\n> +++ b/tests/ovn-ic.at\n> @@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])\n>\n>  AT_CLEANUP\n>  ])\n> +\n> +\n> +OVN_FOR_EACH_NORTHD([\n> +AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route -\n> hub and spoke mode])\n> +\n> +ovn_init_ic_db\n> +\n> +for i in 1 2; do\n> +    ovn_start az$i\n> +    ovn_as az$i\n> +\n> +    # Enable route learning at AZ level\n> +    check ovn-nbctl set nb_global . options:ic-route-learn=true\n> +    # Enable route advertising at AZ level\n> +    check ovn-nbctl set nb_global . options:ic-route-adv=true\n> +done\n> +\n> +# Create new transit switches and LRs. Test topology is next:\n> +#\n> +#\n> +# logical router (lr11) - transit switch (ts11) - logical router (lr12)\n> +#\n> +#\n> +\n> +# Create lr11, lr12 and ts11 and connect them\n> +for i in 1 2; do\n> +    ovn_as az$i\n> +\n> +    lr=lr1$i\n> +    check ovn-nbctl lr-add $lr\n> +\n> +    ts=ts11\n> +    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts\n> +\n> +    lrp=lrp-$lr-$ts\n> +    lsp=lsp-$ts-$lr\n> +    # Create LRP and connect to TS\n> +    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i 169.254.101.$i/24\n> +    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp\n> +done\n> +\n> +# Create directly-connected route in lr12\n> +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 \"\n> 192.168.0.1/24\"\n> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep\n> 192.168 |\n> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n> +192.168.0.0/24 169.254.101.2\n> +])\n> +\n> +ovn_as az2\n> +check ovn-nbctl --wait=sb set Logical_Router lr12\n> option:dynamic-routing=true \\\n> +    option:dynamic-routing-redistribute=\"connected,static\"\n> +check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1\n> 00:00:00:00:ff:01 10.0.0.1/24\n> +dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)\n> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)\n> +\n> +check_uuid ovn-sbctl create Learned_Route \\\n> +    datapath=$datapath                    \\\n> +    logical_port=$dr1                     \\\n> +    ip_prefix=192.168.1.0/24              \\\n> +    nexthop=10.0.0.20\n> +\n> +# Check Learned_Route adv in ovn-ic\n> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |\n> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n> +10.0.0.0/24 169.254.101.2\n> +192.168.0.0/24 169.254.101.2\n> +192.168.1.0/24 169.254.101.2\n> +])\n> +\n> +ovn_as az1\n> +check ovn-nbctl --wait=sb set Logical_Router lr11\n> option:dynamic-routing=true \\\n> +    option:dynamic-routing-redistribute=\"connected,static\"\n> +# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n> +check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24\n> +\n> +\n> +ovn_as az1\n> +check ovn-nbctl --wait=sb set Logical_Router lr11 \\\n> +    option:dynamic-routing-redistribute=\"connected,static,hub-spoke\"\n> +# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes\n> +# Route 192.168.1.0/24 is learned by DR from other logical routes (lr12)\n> +# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing in\n> lr11\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n> +check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24\n> +\n>\n\nI would add an extra check that removed the hub-spoke again just to be sure.\n\n\n> +OVN_CLEANUP_IC([az1], [az2])\n> +\n> +AT_CLEANUP\n> +])\n> --\n> 2.43.0\n>\n>\n> --\n>\n>\n>\n>\n> _'Esta mensagem é direcionada apenas para os endereços constantes no\n> cabeçalho inicial. Se você não está listado nos endereços constantes no\n> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa\n> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas\n> estão\n> imediatamente anuladas e proibidas'._\n>\n>\n> * **'Apesar do Magazine Luiza tomar\n> todas as precauções razoáveis para assegurar que nenhum vírus esteja\n> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por\n> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*\n>\n>\n>\n> _______________________________________________\n> dev mailing list\n> dev@openvswitch.org\n> https://mail.openvswitch.org/mailman/listinfo/ovs-dev\n>\n>\nRegards,\nAles","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=D8LePfZX;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp1.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=D8LePfZX","smtp4.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","smtp4.osuosl.org;\n dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.a=rsa-sha256 header.s=mimecast20190719 header.b=D8LePfZX"],"Received":["from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fsWBW2lsCz1yGb\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 19:06:27 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id 725C881763;\n\tFri, 10 Apr 2026 09:06:20 +0000 (UTC)","from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id WWagKHXyJ9MJ; Fri, 10 Apr 2026 09:06:19 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp1.osuosl.org (Postfix) with ESMTPS id EF4B6829FE;\n\tFri, 10 Apr 2026 09:06:18 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id B4CA2C054A;\n\tFri, 10 Apr 2026 09:06:18 +0000 (UTC)","from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 66BF7C0549\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 09:06:17 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp4.osuosl.org (Postfix) with ESMTP id 5100A40C96\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 09:06:17 +0000 (UTC)","from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id NYvuqwTuttNg for <dev@openvswitch.org>;\n Fri, 10 Apr 2026 09:06:15 +0000 (UTC)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by smtp4.osuosl.org (Postfix) with ESMTPS id 07DB040C86\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 09:06:13 +0000 (UTC)","from mail-yw1-f199.google.com (mail-yw1-f199.google.com\n [209.85.128.199]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-470-5qcLgvaXM56Vk2zW9IFkOg-1; Fri, 10 Apr 2026 05:06:10 -0400","by mail-yw1-f199.google.com with SMTP id\n 00721157ae682-794b240c0d3so59056997b3.0\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 02:06:10 -0700 (PDT)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections -\n client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp1.osuosl.org EF4B6829FE","OpenDKIM Filter v2.11.0 smtp4.osuosl.org 07DB040C86"],"Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com;\n receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp4.osuosl.org 07DB040C86","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1775811972;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=gElTjOTzOpZ8YfrV1f4F4te2QnIjPqPUjSzYkuMRDtU=;\n b=D8LePfZXWvgh7Ib1tPaWKWNpPV5MvBJF7whC8+yBqvJsJPCJHMQQGoumVDuWZLBJF8k/Oh\n TqyTYYSeN90oV9zgObvHmBzW+l5eU3Py9yPiBNult24cTFpZxCJgFmW8lvEKY4fwehTCZv\n YA4y3eV2OmhHy4hBeL/FMapxANUb/Ao=","X-MC-Unique":"5qcLgvaXM56Vk2zW9IFkOg-1","X-Mimecast-MFC-AGG-ID":"5qcLgvaXM56Vk2zW9IFkOg_1775811970","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775811970; x=1776416770;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=gElTjOTzOpZ8YfrV1f4F4te2QnIjPqPUjSzYkuMRDtU=;\n b=cxPwumnsYButcjQJ7FOQYnyztDgaDLaILFuKiNo5fMfbWJ0id+GZjTU2stihyhRFCK\n OI2o7g/yPqcoctAfAoxUK3BFMs6kJH84Q2ByVlCdjiWibHit3D+cD4qlGduxmbUAFdbR\n PAL81PqXyM+vgBz/hjlXe6ymRwoHpguH8eURSurKKevPb4ZlMFDjVhzOIo/QrAFZfAvp\n S8eYaBecqAaKQP+NHDArwvSdmeUCPphhgYiInX0LovduE/4i8lGGzGcarV19jVh1NjYH\n YniO6V1zfG4GqoZdPibhyf89BDJnDV1IbMJexlnbZaTgMhzZAnQKBXo3LFmxXHmdNxrR\n nELw==","X-Gm-Message-State":"AOJu0Yx3XfNO+cbVbcMoqB2RdBOGYDln4j/AbFGDJYsNrN4wbvUWrutW\n HvNiiWEEQP1Tx9U1MKi4Kj+CvM/cMy0U/3oErrc7v+Y2Cy2wF4xWrQ09InIrPy+Y+yewyGzCDt6\n j1ZfF8ikJVqratLCxjTtAyqrZcxeQeo9KoQf8NiweDuBPRAgtAhw+rJPlRBnrbpan1zMdJ1jZuJ\n ynXtrwdMDU+sXmA1itr8qD7bZXaYPIWb2Rr7Wyv6Y=","X-Gm-Gg":"AeBDies2AsuLQAlOlHfaMwvk47PhUNL67rmW/WeEXKh+JMBqzAUE2PIh+KuXwGzkshm\n cYspI1q8HvFYY4CSsIZqCYJ+fT6mQCf5T5UXJfUVytv1JP87SuYA7+JwAkrClXDXLRfFji2PAvd\n GNugerZ788U17gOqgU6lCNT/y2ykW4C4AGDSTBmPR/jizKJPHpZhGc9G6VHAHGVDa4eSb6+K5e8\n q9CNnp0hYOsVavNHJslTUBXaSX3cyKLxp2fsjW/pBfy/oQGLYwhB4RjQZxB1j8HbKog3qAUGyUI\n /r0mChfZcriU26aypGQnM2zdxWjYdq9dy0Vfq+7PrvG12yqZrg3c3I+cHJP4X5cJU0xNtiwC3NE\n 0A32cNB2fMAd/jzcDLKgFGGd24hOz/1UZgt33oqBVoJhyVk8=","X-Received":["by 2002:a05:690c:e3cd:b0:7a1:b7f3:fd35 with SMTP id\n 00721157ae682-7af775bfb01mr17850957b3.8.1775811969903;\n Fri, 10 Apr 2026 02:06:09 -0700 (PDT)","by 2002:a05:690c:e3cd:b0:7a1:b7f3:fd35 with SMTP id\n 00721157ae682-7af775bfb01mr17850747b3.8.1775811969309; Fri, 10 Apr 2026\n 02:06:09 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>","In-Reply-To":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>","Date":"Fri, 10 Apr 2026 11:05:57 +0200","X-Gm-Features":"AQROBzD30oCORZHxeJj8tmaptS6MoHQgyfEko4td10dyUuJgAKqpzQUTPOn1jfk","Message-ID":"\n <CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>","To":"Lucas Vargas Dias <lucas.vdias@luizalabs.com>","Cc":"dev@openvswitch.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"xeyNUtfXHiuX6okbb7L3Suig_i3TIrif_RIcXVznzsw_1775811970","X-Mimecast-Originator":"redhat.com","X-Content-Filtered-By":"Mailman/MimeDel 2.1.30","Subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Ales Musil via dev <ovs-dev@openvswitch.org>","Reply-To":"Ales Musil <amusil@redhat.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"}},{"id":3675809,"web_url":"http://patchwork.ozlabs.org/comment/3675809/","msgid":"<CACAUutPSeTajT9SZO_6o0zn+J4eeN9-oztNtb=1Bzy=PTTE1KQ@mail.gmail.com>","list_archive_url":null,"date":"2026-04-10T11:07:09","subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","submitter":{"id":90169,"url":"http://patchwork.ozlabs.org/api/people/90169/","name":"Lucas Vargas Dias","email":"lucas.vdias@luizalabs.com"},"content":"Hi Ales\n\nThanks for your review.\n\n\nEm sex., 10 de abr. de 2026 às 06:06, Ales Musil <amusil@redhat.com>\nescreveu:\n\n>\n>\n> On Tue, Feb 3, 2026 at 9:24 PM Lucas Vargas Dias via dev <\n> ovs-dev@openvswitch.org> wrote:\n>\n>> Consider the scenario where there are 2 AZs using ovn-ic, each AZ has\n>> one LR and its LS. The LRs are interconnected by a transit switch.\n>> On each AZ, we can configure the dynamic routing and exchange routes\n>> via BGP with external BGP speakers.\n>>\n>> AZ1\n>> LS1 - LR1 - BGP Speaker1 - Local subnet1\n>>        \\\n>>    -----------------------\n>>     transit switch\n>>    -----------------------\n>> AZ2    /\n>> LS2 - LR2 - BGP Speaker2 - Local subnet2\n>>\n>> The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will\n>> not be redistributed to BGP Speaker2 and it also happens with LR1.\n>> This scenario uses the network's hub-and-spoke terminology where we can\n>> enable the hub-spoke on the LR for such redistribution.\n>> subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.\n>> Also, consider the same scenario, but LR1 and LR2 learn the same subnet\n>> for redundancy, hub-spoke option is disabled to not adv the subnet learned\n>> from BGP and advertised in ovn-ic in BGP speakers.\n>>\n>> Signed-off-by: Lucas Vargas Dias <lucas.vdias@luizalabs.com>\n>> ---\n>>\n>\n> Hi Lucas,\n>\n> sorry for the delay. I have a few comments down below. It also needs a\n> rebase.\n>\n>\n>>  NEWS                              |  6 ++\n>>  ic/ovn-ic.c                       | 28 +++++++---\n>>  northd/en-advertised-route-sync.c |  3 +\n>>  northd/northd.c                   | 10 +++-\n>>  northd/northd.h                   |  5 +-\n>>  northd/ovn-northd.c               |  1 -\n>>  ovn-nb.xml                        | 21 +++++++\n>>  tests/ovn-ic.at                   | 92 +++++++++++++++++++++++++++++++\n>>  8 files changed, 156 insertions(+), 10 deletions(-)\n>>\n>> diff --git a/NEWS b/NEWS\n>> index 2a2b5e12d..6002820f3 100644\n>> --- a/NEWS\n>> +++ b/NEWS\n>> @@ -40,6 +40,8 @@ Post v25.09.0\n>>       * Add the \"options:dynamic-routing-no-learning\" to Logical Routers\n>> ports.\n>>         If set to true, router port will not learn routes and will forget\n>>         learned routes. This option has priority over its router\n>> counterpart.\n>> +     * Add support for hub-and-spoke propagation via the \"hub-spoke\"\n>> option\n>> +       in dynamic-routing-redistribute settings.\n>>     - Add support for Network Function insertion in OVN with stateful\n>> traffic\n>>       redirection capability in Logical Switch datapath. The feature\n>> introduces\n>>       three new NB database tables:\n>> @@ -98,6 +100,10 @@ Post v25.09.0\n>>       reserving an unused IP from the backend's subnet. This change allows\n>>       using LRP IPs directly, eliminating the need to reserve additional\n>> IPs\n>>       per backend port.\n>> +   - Add the external_ids:ic-source-dynamic key for\n>> +     Logical_Router_Static_Route to indicate whether a learned OVN-IC\n>> route\n>> +     originated from dynamic routing sources in the advertising\n>> availability\n>> +     zone.\n>>\n>>  OVN v25.09.0 - xxx xx xxxx\n>>  --------------------------\n>> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\n>> index fd5ecefb3..e9fff2d4d 100644\n>> --- a/ic/ovn-ic.c\n>> +++ b/ic/ovn-ic.c\n>> @@ -1283,6 +1283,7 @@ struct ic_route_info {\n>>      struct in6_addr prefix;\n>>      unsigned int plen;\n>>      struct in6_addr nexthop;\n>> +    bool is_src_dynamic;\n>>      const char *origin;\n>>      const char *route_table;\n>>      const char *route_tag;\n>> @@ -1554,7 +1555,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>> struct in6_addr prefix,\n>>                   const struct nbrec_logical_router_static_route\n>> *nb_route,\n>>                   const struct nbrec_logical_router *nb_lr,\n>>                   const struct nbrec_load_balancer *nb_lb,\n>> -                 const char *route_tag)\n>> +                 const char *route_tag, bool is_src_dynamic)\n>>  {\n>>      ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);\n>>\n>> @@ -1573,6 +1574,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>> struct in6_addr prefix,\n>>          ic_route->nb_route = nb_route;\n>>          ic_route->origin = origin;\n>>          ic_route->route_table = route_table;\n>> +        ic_route->is_src_dynamic = is_src_dynamic;\n>>          ic_route->nb_lrp = nb_lrp;\n>>          ic_route->nb_lr = nb_lr;\n>>          ic_route->nb_lb = nb_lb;\n>> @@ -1649,7 +1651,7 @@ add_static_to_routes_ad(\n>>\n>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>> ROUTE_ORIGIN_STATIC,\n>>                       nb_route->route_table, NULL, nb_route, nb_lr,\n>> -                     NULL, route_tag);\n>> +                     NULL, route_tag, false);\n>>  }\n>>\n>>  static void\n>> @@ -1659,7 +1661,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>> const char *network,\n>>                           const struct smap *nb_options,\n>>                           const struct nbrec_logical_router *nb_lr,\n>>                           const char *route_tag,\n>> -                         const struct nbrec_logical_router_port *ts_lrp)\n>> +                         const struct nbrec_logical_router_port *ts_lrp,\n>> +                         bool is_src_dynamic)\n>>  {\n>>      struct in6_addr prefix, nexthop;\n>>      unsigned int plen;\n>> @@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>> const char *network,\n>>\n>>      /* directly-connected routes go to <main> route table */\n>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>> ROUTE_ORIGIN_CONNECTED,\n>> -                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);\n>> +                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,\n>> +                     is_src_dynamic);\n>>  }\n>>\n>>  static void\n>> @@ -1769,7 +1773,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad,\n>> const char *vip_key,\n>>\n>>      /* Lb vip routes go to <main> route table */\n>>      add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,\n>> -                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);\n>> +                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);\n>>  out:\n>>      free(vip_str);\n>>  }\n>> @@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,\n>>                  nbrec_logical_router_static_route_update_options_setkey(\n>>                      nb_route, \"origin\", isb_route->origin);\n>>                  free(uuid_s);\n>> +                bool is_src_dynamic =\n>> smap_get_bool(&isb_route->external_ids,\n>> +                    \"ic-source-dynamic\", false);\n>> +                char *ic_source_dynamic_str = is_src_dynamic ?\n>> +                    \"true\" : \"false\";\n>> +\n>> nbrec_logical_router_static_route_update_external_ids_setkey(\n>> +                    nb_route, \"ic-source-dynamic\",\n>> ic_source_dynamic_str);\n>>\n>\n> This is never updated for existing routes, should we do that too?\n>\n\nI forgot this for the existing routes.\n\n\n>\n>\n>>\n>>  nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,\n>>                      nb_route);\n>>              }\n>> @@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct\n>> ic_route_info *route_adv,\n>>                                                       \"ic-route-tag\");\n>>          }\n>>      }\n>> +\n>> +    char *ic_src_dynamic_str = route_adv->is_src_dynamic ? \"true\" :\n>> \"false\";\n>> +    icsbrec_route_update_external_ids_setkey(isb_route,\n>> \"ic-source-dynamic\",\n>> +                                             ic_src_dynamic_str);\n>>  }\n>>\n>>  /* Sync routes from routes_ad to IC-SB. */\n>> @@ -2372,7 +2386,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>                  add_network_to_routes_ad(routes_ad, lrp->networks[j],\n>> lrp,\n>>                                           ts_port_addrs,\n>>                                           &nb_global->options,\n>> -                                         lr, route_tag, ts_lrp);\n>> +                                         lr, route_tag, ts_lrp, false);\n>>              }\n>>          } else {\n>>              /* The router port of the TS port is ignored. */\n>> @@ -2427,7 +2441,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>          add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,\n>>                                   ts_port_addrs,\n>>                                   &nb_global->options,\n>> -                                 lr, route_tag, ts_lrp);\n>> +                                 lr, route_tag, ts_lrp, true);\n>>      }\n>>      sbrec_learned_route_index_destroy_row(filter);\n>>  }\n>> diff --git a/northd/en-advertised-route-sync.c\n>> b/northd/en-advertised-route-sync.c\n>> index be771391d..be046769f 100644\n>> --- a/northd/en-advertised-route-sync.c\n>> +++ b/northd/en-advertised-route-sync.c\n>> @@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset\n>> *host_route_lrps,\n>>          return drr_mode_NAT_is_set(drr);\n>>      case ROUTE_SOURCE_LB:\n>>          return drr_mode_LB_is_set(drr);\n>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>> +        return drr_mode_IC_DYNAMIC_is_set(drr);\n>>      case ROUTE_SOURCE_LEARNED:\n>>          OVS_NOT_REACHED();\n>>      default:\n>> @@ -745,6 +747,7 @@ advertise_route_track_od(struct\n>> advertised_route_sync_data *data,\n>>                             &tracked_op->od->nbr->header_.uuid);\n>>          }\n>>          break;\n>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>      case ROUTE_SOURCE_CONNECTED:\n>>      case ROUTE_SOURCE_STATIC:\n>>          break;\n>> diff --git a/northd/northd.c b/northd/northd.c\n>> index b4bb4ba6d..fbb75533c 100644\n>> --- a/northd/northd.c\n>> +++ b/northd/northd.c\n>> @@ -870,6 +870,10 @@ parse_dynamic_routing_redistribute(\n>>              out |= DRRM_LB;\n>>              continue;\n>>          }\n>> +        if (!strcmp(token, \"hub-spoke\")) {\n>> +            out |= DRRM_IC_DYNAMIC;\n>> +            continue;\n>> +        }\n>>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n>>          VLOG_WARN_RL(&rl,\n>>                       \"unknown dynamic-routing-redistribute option '%s'\n>> on %s\",\n>> @@ -12034,7 +12038,10 @@ parsed_routes_add_static(const struct\n>> ovn_datapath *od,\n>>      enum route_source source;\n>>      if (!strcmp(smap_get_def(&route->options, \"origin\", \"\"),\n>>                  ROUTE_ORIGIN_CONNECTED)) {\n>> -        source = ROUTE_SOURCE_CONNECTED;\n>> +        bool ic_src_dynamic = smap_get_bool(&route->external_ids,\n>> +                                            \"ic-source-dynamic\", false);\n>> +        source = ic_src_dynamic ?\n>> +                 ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;\n>>      } else {\n>>          source = ROUTE_SOURCE_STATIC;\n>>      }\n>> @@ -12129,6 +12136,7 @@ route_source_to_offset(enum route_source source)\n>>  {\n>>      switch (source) {\n>>      case ROUTE_SOURCE_CONNECTED:\n>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>          return ROUTE_PRIO_OFFSET_CONNECTED;\n>>      case ROUTE_SOURCE_STATIC:\n>>          return ROUTE_PRIO_OFFSET_STATIC;\n>> diff --git a/northd/northd.h b/northd/northd.h\n>> index eb5c15f34..e6ed2cc3e 100644\n>> --- a/northd/northd.h\n>> +++ b/northd/northd.h\n>> @@ -372,7 +372,8 @@ struct mcast_port_info {\n>>      DRR_MODE(CONNECTED_AS_HOST, 1) \\\n>>      DRR_MODE(STATIC,            2) \\\n>>      DRR_MODE(NAT,               3) \\\n>> -    DRR_MODE(LB,                4)\n>> +    DRR_MODE(LB,                4) \\\n>> +    DRR_MODE(IC_DYNAMIC,        5)\n>>\n>>  enum dynamic_routing_redistribute_mode_bits {\n>>  #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,\n>> @@ -826,6 +827,8 @@ enum route_source {\n>>      ROUTE_SOURCE_NAT,\n>>      /* The route is derived from a LB's VIP. */\n>>      ROUTE_SOURCE_LB,\n>> +    /* The route is derived from an ovn-controller and advertised to IC.\n>> */\n>> +    ROUTE_SOURCE_IC_DYNAMIC,\n>>  };\n>>\n>>  struct parsed_route {\n>> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\n>> index 7d7568c6f..bc3969053 100644\n>> --- a/northd/ovn-northd.c\n>> +++ b/northd/ovn-northd.c\n>> @@ -905,7 +905,6 @@ main(int argc, char *argv[])\n>>          &nbrec_load_balancer_col_external_ids,\n>>          &nbrec_load_balancer_health_check_col_external_ids,\n>>          &nbrec_logical_router_policy_col_external_ids,\n>> -        &nbrec_logical_router_static_route_col_external_ids,\n>>\n>\n> This is very dangerous, it means that any change\n> of external_ids will wake up northd. I think it will be safer\n> to make it an option as we track those already.\n>\n> On a second thought and looking through the\n> is there a reason why we can't just add another origin?\n> We check the origin anyway in northd, so having\n> something like:\n>\n> #define ROUTE_ORIGIN_CONNECTED_DYNAMIC \"connected-dynamic\"\n>\n> That would avoid the tracking of external_ids, extra definiton\n> of an option and would be probably smaller change in the\n> ovn-ic overall, WDYT?\n>\n\nI agree, we can add a new origin. I'll adjust.\n\n\n\n>\n>          &nbrec_meter_col_external_ids,\n>>          &nbrec_meter_band_col_external_ids,\n>>          &nbrec_mirror_col_external_ids,\n>> diff --git a/ovn-nb.xml b/ovn-nb.xml\n>> index 1acbf202b..5f9b47491 100644\n>> --- a/ovn-nb.xml\n>> +++ b/ovn-nb.xml\n>> @@ -3374,6 +3374,13 @@ or\n>>            Logical Switch.\n>>          </p>\n>>\n>> +        <p>\n>> +          If <code>hub-spoke</code> is in the list then northd will\n>> synchronize\n>> +          dynamic routes learned through OVN-IC from other routers into\n>> the\n>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>> enabling\n>> +          hub-and-spoke propagation.\n>> +        </p>\n>> +\n>>          <p>\n>>            This value can be overwritten on a per LRP basis using\n>>            <ref column=\"options\" key=\"dynamic-routing-redistribute\"\n>> @@ -4461,6 +4468,13 @@ or\n>>            via shared Logical Switch.\n>>          </p>\n>>\n>> +        <p>\n>> +          If <code>hub-spoke</code> is in the list then northd will\n>> synchronize\n>> +          dynamic routes learned through OVN-IC from other routers into\n>> the\n>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>> enabling\n>> +          hub-and-spoke propagation.\n>> +        </p>\n>> +\n>>          <p>\n>>            If not set the value from <ref column=\"options\"\n>>            key=\"dynamic-routing-redistribute\" table=\"Logical_Router\"/> on\n>> the\n>> @@ -4823,6 +4837,13 @@ or\n>>        database.\n>>      </column>\n>>\n>> +    <column name=\"external_ids\" key=\"ic-source-dynamic\">\n>> +      <code>ovn-ic</code> populates this key for routes learned from\n>> +      <ref db=\"OVN_IC_Southbound\"/>. The value is <code>true</code> if\n>> the\n>> +      learned route originated from dynamic sources (e.g. learned routes)\n>> +      in the advertising availability zone, otherwise <code>false</code>.\n>> +    </column>\n>> +\n>>      <group title=\"Common Columns\">\n>>        <column name=\"external_ids\">\n>>          See <em>External IDs</em> at the beginning of this document.\n>> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\n>> index 370a755be..a62d02da0 100644\n>> --- a/tests/ovn-ic.at\n>> +++ b/tests/ovn-ic.at\n>> @@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])\n>>\n>>  AT_CLEANUP\n>>  ])\n>> +\n>> +\n>> +OVN_FOR_EACH_NORTHD([\n>> +AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route -\n>> hub and spoke mode])\n>> +\n>> +ovn_init_ic_db\n>> +\n>> +for i in 1 2; do\n>> +    ovn_start az$i\n>> +    ovn_as az$i\n>> +\n>> +    # Enable route learning at AZ level\n>> +    check ovn-nbctl set nb_global . options:ic-route-learn=true\n>> +    # Enable route advertising at AZ level\n>> +    check ovn-nbctl set nb_global . options:ic-route-adv=true\n>> +done\n>> +\n>> +# Create new transit switches and LRs. Test topology is next:\n>> +#\n>> +#\n>> +# logical router (lr11) - transit switch (ts11) - logical router (lr12)\n>> +#\n>> +#\n>> +\n>> +# Create lr11, lr12 and ts11 and connect them\n>> +for i in 1 2; do\n>> +    ovn_as az$i\n>> +\n>> +    lr=lr1$i\n>> +    check ovn-nbctl lr-add $lr\n>> +\n>> +    ts=ts11\n>> +    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts\n>> +\n>> +    lrp=lrp-$lr-$ts\n>> +    lsp=lsp-$ts-$lr\n>> +    # Create LRP and connect to TS\n>> +    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i 169.254.101.$i/24\n>> +    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp\n>> +done\n>> +\n>> +# Create directly-connected route in lr12\n>> +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 \"\n>> 192.168.0.1/24\"\n>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep\n>> 192.168 |\n>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>> +192.168.0.0/24 169.254.101.2\n>> +])\n>> +\n>> +ovn_as az2\n>> +check ovn-nbctl --wait=sb set Logical_Router lr12\n>> option:dynamic-routing=true \\\n>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>> +check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1\n>> 00:00:00:00:ff:01 10.0.0.1/24\n>> +dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)\n>> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)\n>> +\n>> +check_uuid ovn-sbctl create Learned_Route \\\n>> +    datapath=$datapath                    \\\n>> +    logical_port=$dr1                     \\\n>> +    ip_prefix=192.168.1.0/24              \\\n>> +    nexthop=10.0.0.20\n>> +\n>> +# Check Learned_Route adv in ovn-ic\n>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |\n>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>> +10.0.0.0/24 169.254.101.2\n>> +192.168.0.0/24 169.254.101.2\n>> +192.168.1.0/24 169.254.101.2\n>> +])\n>> +\n>> +ovn_as az1\n>> +check ovn-nbctl --wait=sb set Logical_Router lr11\n>> option:dynamic-routing=true \\\n>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>> +# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes\n>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>> +check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24\n>> +\n>> +\n>> +ovn_as az1\n>> +check ovn-nbctl --wait=sb set Logical_Router lr11 \\\n>> +    option:dynamic-routing-redistribute=\"connected,static,hub-spoke\"\n>> +# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes\n>> +# Route 192.168.1.0/24 is learned by DR from other logical routes (lr12)\n>> +# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing\n>> in lr11\n>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>> +check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24\n>> +\n>>\n>\n> I would add an extra check that removed the hub-spoke again just to be\n> sure.\n>\n\nI agree\n\n\n>\n>\n>> +OVN_CLEANUP_IC([az1], [az2])\n>> +\n>> +AT_CLEANUP\n>> +])\n>> --\n>> 2.43.0\n>>\n>>\n>> --\n>>\n>>\n>>\n>>\n>> _'Esta mensagem é direcionada apenas para os endereços constantes no\n>> cabeçalho inicial. Se você não está listado nos endereços constantes no\n>> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa\n>> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas\n>> estão\n>> imediatamente anuladas e proibidas'._\n>>\n>>\n>> * **'Apesar do Magazine Luiza tomar\n>> todas as precauções razoáveis para assegurar que nenhum vírus esteja\n>> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade\n>> por\n>> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*\n>>\n>>\n>>\n>> _______________________________________________\n>> dev mailing list\n>> dev@openvswitch.org\n>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev\n>>\n>>\n> Regards,\n> Ales\n>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=luizalabs.com header.i=@luizalabs.com\n header.a=rsa-sha256 header.s=google header.b=PGMDnN9m;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp1.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=luizalabs.com header.i=@luizalabs.com header.a=rsa-sha256\n header.s=google header.b=PGMDnN9m","smtp1.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=luizalabs.com"],"Received":["from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fsYtB0QzXz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 21:07:29 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id EE7E182F19;\n\tFri, 10 Apr 2026 11:07:27 +0000 (UTC)","from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id SG3Vhd7p-2M7; Fri, 10 Apr 2026 11:07:26 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp1.osuosl.org (Postfix) with ESMTPS id 79B1D80BA8;\n\tFri, 10 Apr 2026 11:07:26 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 52DF1C054A;\n\tFri, 10 Apr 2026 11:07:26 +0000 (UTC)","from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 0FE65C0549\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:07:25 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp1.osuosl.org (Postfix) with ESMTP id 01BCA80CDB\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:07:25 +0000 (UTC)","from smtp1.osuosl.org ([127.0.0.1])\n by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id Gr4v3JH19m_8 for <dev@openvswitch.org>;\n Fri, 10 Apr 2026 11:07:23 +0000 (UTC)","from mail-oi1-x22d.google.com (mail-oi1-x22d.google.com\n [IPv6:2607:f8b0:4864:20::22d])\n by smtp1.osuosl.org (Postfix) with ESMTPS id 9C2BD80BA8\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:07:22 +0000 (UTC)","by mail-oi1-x22d.google.com with SMTP id\n 5614622812f47-4670464029eso1074026b6e.2\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 04:07:22 -0700 (PDT)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp1.osuosl.org 79B1D80BA8","OpenDKIM Filter v2.11.0 smtp1.osuosl.org 9C2BD80BA8"],"Received-SPF":"Pass (mailfrom) identity=mailfrom;\n client-ip=2607:f8b0:4864:20::22d; helo=mail-oi1-x22d.google.com;\n envelope-from=lucas.vdias@luizalabs.com; receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp1.osuosl.org 9C2BD80BA8","ARC-Seal":"i=1; a=rsa-sha256; t=1775819241; cv=none;\n d=google.com; s=arc-20240605;\n b=QqwTEuGiXa5BzrZuEge1iEKOsN9hu34zXpgkzT95C2Ni5iaQfayKVfwepmEHGiZI4v\n LIhijy9ZdDnZWV/In4VB2jH0g+ru0XB4lK0WjeAWtwJeBPb+FNfIm0aihPqOJYKznxak\n n2vDCIwu/3Vv5LQvgqjiglcJhGPD5TkLDXGtOq//0g/w3VDOKuCnC5fdZCpyTNlcLiYY\n dFcFokWYvgtuIbbZFBmyXRTWZkHuuOm9rZz6XVfg6A/S18eTz+si7rZ1gFRU41X46iHi\n m05PcjJhKVsvdZj81dYnT/kWKPL/A+jIA7Wtp1ivg1aSzcxSZ+EvChAF97pA2U51LIY4\n e9qA==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:dkim-signature;\n bh=CIS3DfAEXHCHfi2Xnpp+xMVLQW+5m2ggCdoPbnx8z7Q=;\n fh=8kKxe5qJyJFg8uGJ6dGu+ueszPwToZJGpmjLMzx6TXA=;\n b=H1E/fq+LZUtpZONfENAjF+mYIJ9Ug3h2Y4+Imn+hXdKDwMmn07p+2byybX2xkBOr9b\n HkjYerz/doTgV2hqIgKEva/VUujtkCbBhGUwRYHhKaCm2mHRJ44Tnrg8mtYgZjeYy7bc\n BqFjAObxd+WJnWePdM88NZcKEGri+CEMpa619xljIXi0ROJbh4rcpVoNfLXghzFofZBr\n I3OqKTsrazgc79cvKyIT3okdtkSmYuzS2vFra2f9iEWu4aB1qEJPHXkP6bRsLyai/rX6\n Sfj0fiMfQPRQ7huF568OtVHZHvXe1HfLVQ5x9KDZ2Lef6hPwLGawrN8rMdanDFSA/4nd\n KKlg==; darn=openvswitch.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=luizalabs.com; s=google; t=1775819241; x=1776424041; darn=openvswitch.org;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:from:to:cc:subject:date:message-id:reply-to;\n bh=CIS3DfAEXHCHfi2Xnpp+xMVLQW+5m2ggCdoPbnx8z7Q=;\n b=PGMDnN9m+6q7y6wJAmqdgq0s+DQO/kAEMv+EORLfobzrs7Qwls7c/0llJ/Xds9aVYr\n 22vB5J01n/xRsgXnz1D3kVqbczaNcieeGylIWDm18oNEpv3q6FNdR11aUnlh1HLJ4APT\n 5KsapLDn4wbtkftEop8/VuX3E+jfr/PBbfGxw=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775819241; x=1776424041;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=CIS3DfAEXHCHfi2Xnpp+xMVLQW+5m2ggCdoPbnx8z7Q=;\n b=bV6Kf2U/g08SzhnK0E7lI2Z48O4ilUTYuGTo2xhaGfD3M5XnojyPwORFtGf/6d3Myz\n Zs3Nyw/8cyFGf7SFF8nGT93zcy1Z7TX20pxmpgHZLGI3r6nhZBdqTgg8CvGc8JBN9lme\n 0QjjA3WWdXWmbD3++CDbxsZNLSbPOnL1R2gqFsos4fUgOKdG80Ez0nGhpYdqyG6XfvPQ\n W9XWWUqCGzXQKYwh6i/jZxHQZSNYdRNQtgBRYayZu2arZp7Fe/vESEG5y5tbT8UykN1M\n c46BEn/k7zZWEEvcW8E+g94Vmz51eZUC0jednkEEC/tt5AI3qvC65El4Ot2qOOM99zty\n B9og==","X-Gm-Message-State":"AOJu0YwEKkNoFwNNoBu9hiXi9zUoeOixXnbzKTuYvob+ueZkM+jBjEDW\n BflhV3SUQxxFPlRgo9Qzn7TWBI+mWJP7tbcm4TU0QlTnS9p3SGlPmgrUlTu050EWp5dBIkMZ+/s\n 4A4aw4MZ7wH0bF3TSZpjZiDdKfc2mzkh5u13mcg+Xz174zCAjyiIKLsbV4vKfcR1Q9M8xVom6XD\n 4RiH32Lh4aUZdJnxyTSBwWtg==","X-Gm-Gg":"AeBDietwoBvRgseZq50V1taSO9WeAFfzT23ga2sKQ7LhL2FrGQlv8oZWxWZgGkP5vaa\n 6sPiu0EHFE99qpyKW6m/jAcaaK8uxYlu7N0ZOOFnOYArYlNwA4RACTpVT9PLpqGruAWJAj9WcUF\n RoZzCwvZ+5a2yoKqkjZ5DfwXtHPCJ4GtuY/+U39OqU7rjUGwr4kWPL0FzfMyq3n1PqM9WLJqBYY\n PmICsS1Dj5yF8wLCBa68JDcDuiS2SgAM5l9EO4DJmXGgUQH3gs1Q4GhVi5BYCGV87dOK/wnkDrd\n AhBOJefrOw==","X-Received":"by 2002:a05:6808:6610:b0:46a:5201:aa36 with SMTP id\n 5614622812f47-4789f703b55mr1392171b6e.42.1775819241098; Fri, 10 Apr 2026\n 04:07:21 -0700 (PDT)","MIME-Version":"1.0","References":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>\n <CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>","In-Reply-To":"\n <CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>","Date":"Fri, 10 Apr 2026 08:07:09 -0300","X-Gm-Features":"AQROBzAxCdHyyPY7XzSqb7FYfu1TwgrbfxjD5OL28i42lTVwzyYVWMdGBNHvP98","Message-ID":"\n <CACAUutPSeTajT9SZO_6o0zn+J4eeN9-oztNtb=1Bzy=PTTE1KQ@mail.gmail.com>","To":"Ales Musil <amusil@redhat.com>","Cc":"dev@openvswitch.org","X-Content-Filtered-By":"Mailman/MimeDel 2.1.30","Subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Lucas Vargas Dias via dev <ovs-dev@openvswitch.org>","Reply-To":"Lucas Vargas Dias <lucas.vdias@luizalabs.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"}},{"id":3675832,"web_url":"http://patchwork.ozlabs.org/comment/3675832/","msgid":"<CACAUutMYqnbFhRZ_1Pc-2-hfRRrcBY_HVd9ExryAkF8fityOfQ@mail.gmail.com>","list_archive_url":null,"date":"2026-04-10T11:22:24","subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","submitter":{"id":90169,"url":"http://patchwork.ozlabs.org/api/people/90169/","name":"Lucas Vargas Dias","email":"lucas.vdias@luizalabs.com"},"content":"Em sex., 10 de abr. de 2026 às 08:07, Lucas Vargas Dias <\nlucas.vdias@luizalabs.com> escreveu:\n\n> Hi Ales\n>\n> Thanks for your review.\n>\n>\n> Em sex., 10 de abr. de 2026 às 06:06, Ales Musil <amusil@redhat.com>\n> escreveu:\n>\n>>\n>>\n>> On Tue, Feb 3, 2026 at 9:24 PM Lucas Vargas Dias via dev <\n>> ovs-dev@openvswitch.org> wrote:\n>>\n>>> Consider the scenario where there are 2 AZs using ovn-ic, each AZ has\n>>> one LR and its LS. The LRs are interconnected by a transit switch.\n>>> On each AZ, we can configure the dynamic routing and exchange routes\n>>> via BGP with external BGP speakers.\n>>>\n>>> AZ1\n>>> LS1 - LR1 - BGP Speaker1 - Local subnet1\n>>>        \\\n>>>    -----------------------\n>>>     transit switch\n>>>    -----------------------\n>>> AZ2    /\n>>> LS2 - LR2 - BGP Speaker2 - Local subnet2\n>>>\n>>> The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will\n>>> not be redistributed to BGP Speaker2 and it also happens with LR1.\n>>> This scenario uses the network's hub-and-spoke terminology where we can\n>>> enable the hub-spoke on the LR for such redistribution.\n>>> subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.\n>>> Also, consider the same scenario, but LR1 and LR2 learn the same subnet\n>>> for redundancy, hub-spoke option is disabled to not adv the subnet\n>>> learned\n>>> from BGP and advertised in ovn-ic in BGP speakers.\n>>>\n>>> Signed-off-by: Lucas Vargas Dias <lucas.vdias@luizalabs.com>\n>>> ---\n>>>\n>>\n>> Hi Lucas,\n>>\n>> sorry for the delay. I have a few comments down below. It also needs a\n>> rebase.\n>>\n>>\n>>>  NEWS                              |  6 ++\n>>>  ic/ovn-ic.c                       | 28 +++++++---\n>>>  northd/en-advertised-route-sync.c |  3 +\n>>>  northd/northd.c                   | 10 +++-\n>>>  northd/northd.h                   |  5 +-\n>>>  northd/ovn-northd.c               |  1 -\n>>>  ovn-nb.xml                        | 21 +++++++\n>>>  tests/ovn-ic.at                   | 92 +++++++++++++++++++++++++++++++\n>>>  8 files changed, 156 insertions(+), 10 deletions(-)\n>>>\n>>> diff --git a/NEWS b/NEWS\n>>> index 2a2b5e12d..6002820f3 100644\n>>> --- a/NEWS\n>>> +++ b/NEWS\n>>> @@ -40,6 +40,8 @@ Post v25.09.0\n>>>       * Add the \"options:dynamic-routing-no-learning\" to Logical Routers\n>>> ports.\n>>>         If set to true, router port will not learn routes and will forget\n>>>         learned routes. This option has priority over its router\n>>> counterpart.\n>>> +     * Add support for hub-and-spoke propagation via the \"hub-spoke\"\n>>> option\n>>> +       in dynamic-routing-redistribute settings.\n>>>     - Add support for Network Function insertion in OVN with stateful\n>>> traffic\n>>>       redirection capability in Logical Switch datapath. The feature\n>>> introduces\n>>>       three new NB database tables:\n>>> @@ -98,6 +100,10 @@ Post v25.09.0\n>>>       reserving an unused IP from the backend's subnet. This change\n>>> allows\n>>>       using LRP IPs directly, eliminating the need to reserve additional\n>>> IPs\n>>>       per backend port.\n>>> +   - Add the external_ids:ic-source-dynamic key for\n>>> +     Logical_Router_Static_Route to indicate whether a learned OVN-IC\n>>> route\n>>> +     originated from dynamic routing sources in the advertising\n>>> availability\n>>> +     zone.\n>>>\n>>>  OVN v25.09.0 - xxx xx xxxx\n>>>  --------------------------\n>>> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\n>>> index fd5ecefb3..e9fff2d4d 100644\n>>> --- a/ic/ovn-ic.c\n>>> +++ b/ic/ovn-ic.c\n>>> @@ -1283,6 +1283,7 @@ struct ic_route_info {\n>>>      struct in6_addr prefix;\n>>>      unsigned int plen;\n>>>      struct in6_addr nexthop;\n>>> +    bool is_src_dynamic;\n>>>      const char *origin;\n>>>      const char *route_table;\n>>>      const char *route_tag;\n>>> @@ -1554,7 +1555,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>>> struct in6_addr prefix,\n>>>                   const struct nbrec_logical_router_static_route\n>>> *nb_route,\n>>>                   const struct nbrec_logical_router *nb_lr,\n>>>                   const struct nbrec_load_balancer *nb_lb,\n>>> -                 const char *route_tag)\n>>> +                 const char *route_tag, bool is_src_dynamic)\n>>>  {\n>>>      ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);\n>>>\n>>> @@ -1573,6 +1574,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>>> struct in6_addr prefix,\n>>>          ic_route->nb_route = nb_route;\n>>>          ic_route->origin = origin;\n>>>          ic_route->route_table = route_table;\n>>> +        ic_route->is_src_dynamic = is_src_dynamic;\n>>>          ic_route->nb_lrp = nb_lrp;\n>>>          ic_route->nb_lr = nb_lr;\n>>>          ic_route->nb_lb = nb_lb;\n>>> @@ -1649,7 +1651,7 @@ add_static_to_routes_ad(\n>>>\n>>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>>> ROUTE_ORIGIN_STATIC,\n>>>                       nb_route->route_table, NULL, nb_route, nb_lr,\n>>> -                     NULL, route_tag);\n>>> +                     NULL, route_tag, false);\n>>>  }\n>>>\n>>>  static void\n>>> @@ -1659,7 +1661,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>>> const char *network,\n>>>                           const struct smap *nb_options,\n>>>                           const struct nbrec_logical_router *nb_lr,\n>>>                           const char *route_tag,\n>>> -                         const struct nbrec_logical_router_port *ts_lrp)\n>>> +                         const struct nbrec_logical_router_port *ts_lrp,\n>>> +                         bool is_src_dynamic)\n>>>  {\n>>>      struct in6_addr prefix, nexthop;\n>>>      unsigned int plen;\n>>> @@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>>> const char *network,\n>>>\n>>>      /* directly-connected routes go to <main> route table */\n>>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>>> ROUTE_ORIGIN_CONNECTED,\n>>> -                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);\n>>> +                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,\n>>> +                     is_src_dynamic);\n>>>  }\n>>>\n>>>  static void\n>>> @@ -1769,7 +1773,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad,\n>>> const char *vip_key,\n>>>\n>>>      /* Lb vip routes go to <main> route table */\n>>>      add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,\n>>> -                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);\n>>> +                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);\n>>>  out:\n>>>      free(vip_str);\n>>>  }\n>>> @@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,\n>>>                  nbrec_logical_router_static_route_update_options_setkey(\n>>>                      nb_route, \"origin\", isb_route->origin);\n>>>                  free(uuid_s);\n>>> +                bool is_src_dynamic =\n>>> smap_get_bool(&isb_route->external_ids,\n>>> +                    \"ic-source-dynamic\", false);\n>>> +                char *ic_source_dynamic_str = is_src_dynamic ?\n>>> +                    \"true\" : \"false\";\n>>> +\n>>> nbrec_logical_router_static_route_update_external_ids_setkey(\n>>> +                    nb_route, \"ic-source-dynamic\",\n>>> ic_source_dynamic_str);\n>>>\n>>\n>> This is never updated for existing routes, should we do that too?\n>>\n>\n> I forgot this for the existing routes.\n>\n>\n\nEven using the  new origin (ROUTE_ORIGIN_CONNECTED_DYNAMIC), do you think\nit is necessary to fill the external_ids?\n\n\n>\n>>\n>>>\n>>>  nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,\n>>>                      nb_route);\n>>>              }\n>>> @@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct\n>>> ic_route_info *route_adv,\n>>>                                                       \"ic-route-tag\");\n>>>          }\n>>>      }\n>>> +\n>>> +    char *ic_src_dynamic_str = route_adv->is_src_dynamic ? \"true\" :\n>>> \"false\";\n>>> +    icsbrec_route_update_external_ids_setkey(isb_route,\n>>> \"ic-source-dynamic\",\n>>> +                                             ic_src_dynamic_str);\n>>>  }\n>>>\n>>>  /* Sync routes from routes_ad to IC-SB. */\n>>> @@ -2372,7 +2386,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>>                  add_network_to_routes_ad(routes_ad, lrp->networks[j],\n>>> lrp,\n>>>                                           ts_port_addrs,\n>>>                                           &nb_global->options,\n>>> -                                         lr, route_tag, ts_lrp);\n>>> +                                         lr, route_tag, ts_lrp, false);\n>>>              }\n>>>          } else {\n>>>              /* The router port of the TS port is ignored. */\n>>> @@ -2427,7 +2441,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>>          add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,\n>>>                                   ts_port_addrs,\n>>>                                   &nb_global->options,\n>>> -                                 lr, route_tag, ts_lrp);\n>>> +                                 lr, route_tag, ts_lrp, true);\n>>>      }\n>>>      sbrec_learned_route_index_destroy_row(filter);\n>>>  }\n>>> diff --git a/northd/en-advertised-route-sync.c\n>>> b/northd/en-advertised-route-sync.c\n>>> index be771391d..be046769f 100644\n>>> --- a/northd/en-advertised-route-sync.c\n>>> +++ b/northd/en-advertised-route-sync.c\n>>> @@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset\n>>> *host_route_lrps,\n>>>          return drr_mode_NAT_is_set(drr);\n>>>      case ROUTE_SOURCE_LB:\n>>>          return drr_mode_LB_is_set(drr);\n>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>> +        return drr_mode_IC_DYNAMIC_is_set(drr);\n>>>      case ROUTE_SOURCE_LEARNED:\n>>>          OVS_NOT_REACHED();\n>>>      default:\n>>> @@ -745,6 +747,7 @@ advertise_route_track_od(struct\n>>> advertised_route_sync_data *data,\n>>>                             &tracked_op->od->nbr->header_.uuid);\n>>>          }\n>>>          break;\n>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>>      case ROUTE_SOURCE_CONNECTED:\n>>>      case ROUTE_SOURCE_STATIC:\n>>>          break;\n>>> diff --git a/northd/northd.c b/northd/northd.c\n>>> index b4bb4ba6d..fbb75533c 100644\n>>> --- a/northd/northd.c\n>>> +++ b/northd/northd.c\n>>> @@ -870,6 +870,10 @@ parse_dynamic_routing_redistribute(\n>>>              out |= DRRM_LB;\n>>>              continue;\n>>>          }\n>>> +        if (!strcmp(token, \"hub-spoke\")) {\n>>> +            out |= DRRM_IC_DYNAMIC;\n>>> +            continue;\n>>> +        }\n>>>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n>>>          VLOG_WARN_RL(&rl,\n>>>                       \"unknown dynamic-routing-redistribute option '%s'\n>>> on %s\",\n>>> @@ -12034,7 +12038,10 @@ parsed_routes_add_static(const struct\n>>> ovn_datapath *od,\n>>>      enum route_source source;\n>>>      if (!strcmp(smap_get_def(&route->options, \"origin\", \"\"),\n>>>                  ROUTE_ORIGIN_CONNECTED)) {\n>>> -        source = ROUTE_SOURCE_CONNECTED;\n>>> +        bool ic_src_dynamic = smap_get_bool(&route->external_ids,\n>>> +                                            \"ic-source-dynamic\", false);\n>>> +        source = ic_src_dynamic ?\n>>> +                 ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;\n>>>      } else {\n>>>          source = ROUTE_SOURCE_STATIC;\n>>>      }\n>>> @@ -12129,6 +12136,7 @@ route_source_to_offset(enum route_source source)\n>>>  {\n>>>      switch (source) {\n>>>      case ROUTE_SOURCE_CONNECTED:\n>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>>          return ROUTE_PRIO_OFFSET_CONNECTED;\n>>>      case ROUTE_SOURCE_STATIC:\n>>>          return ROUTE_PRIO_OFFSET_STATIC;\n>>> diff --git a/northd/northd.h b/northd/northd.h\n>>> index eb5c15f34..e6ed2cc3e 100644\n>>> --- a/northd/northd.h\n>>> +++ b/northd/northd.h\n>>> @@ -372,7 +372,8 @@ struct mcast_port_info {\n>>>      DRR_MODE(CONNECTED_AS_HOST, 1) \\\n>>>      DRR_MODE(STATIC,            2) \\\n>>>      DRR_MODE(NAT,               3) \\\n>>> -    DRR_MODE(LB,                4)\n>>> +    DRR_MODE(LB,                4) \\\n>>> +    DRR_MODE(IC_DYNAMIC,        5)\n>>>\n>>>  enum dynamic_routing_redistribute_mode_bits {\n>>>  #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,\n>>> @@ -826,6 +827,8 @@ enum route_source {\n>>>      ROUTE_SOURCE_NAT,\n>>>      /* The route is derived from a LB's VIP. */\n>>>      ROUTE_SOURCE_LB,\n>>> +    /* The route is derived from an ovn-controller and advertised to\n>>> IC. */\n>>> +    ROUTE_SOURCE_IC_DYNAMIC,\n>>>  };\n>>>\n>>>  struct parsed_route {\n>>> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\n>>> index 7d7568c6f..bc3969053 100644\n>>> --- a/northd/ovn-northd.c\n>>> +++ b/northd/ovn-northd.c\n>>> @@ -905,7 +905,6 @@ main(int argc, char *argv[])\n>>>          &nbrec_load_balancer_col_external_ids,\n>>>          &nbrec_load_balancer_health_check_col_external_ids,\n>>>          &nbrec_logical_router_policy_col_external_ids,\n>>> -        &nbrec_logical_router_static_route_col_external_ids,\n>>>\n>>\n>> This is very dangerous, it means that any change\n>> of external_ids will wake up northd. I think it will be safer\n>> to make it an option as we track those already.\n>>\n>> On a second thought and looking through the\n>> is there a reason why we can't just add another origin?\n>> We check the origin anyway in northd, so having\n>> something like:\n>>\n>> #define ROUTE_ORIGIN_CONNECTED_DYNAMIC \"connected-dynamic\"\n>>\n>> That would avoid the tracking of external_ids, extra definiton\n>> of an option and would be probably smaller change in the\n>> ovn-ic overall, WDYT?\n>>\n>\n> I agree, we can add a new origin. I'll adjust.\n>\n>\n>\n>>\n>>          &nbrec_meter_col_external_ids,\n>>>          &nbrec_meter_band_col_external_ids,\n>>>          &nbrec_mirror_col_external_ids,\n>>> diff --git a/ovn-nb.xml b/ovn-nb.xml\n>>> index 1acbf202b..5f9b47491 100644\n>>> --- a/ovn-nb.xml\n>>> +++ b/ovn-nb.xml\n>>> @@ -3374,6 +3374,13 @@ or\n>>>            Logical Switch.\n>>>          </p>\n>>>\n>>> +        <p>\n>>> +          If <code>hub-spoke</code> is in the list then northd will\n>>> synchronize\n>>> +          dynamic routes learned through OVN-IC from other routers into\n>>> the\n>>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>>> enabling\n>>> +          hub-and-spoke propagation.\n>>> +        </p>\n>>> +\n>>>          <p>\n>>>            This value can be overwritten on a per LRP basis using\n>>>            <ref column=\"options\" key=\"dynamic-routing-redistribute\"\n>>> @@ -4461,6 +4468,13 @@ or\n>>>            via shared Logical Switch.\n>>>          </p>\n>>>\n>>> +        <p>\n>>> +          If <code>hub-spoke</code> is in the list then northd will\n>>> synchronize\n>>> +          dynamic routes learned through OVN-IC from other routers into\n>>> the\n>>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>>> enabling\n>>> +          hub-and-spoke propagation.\n>>> +        </p>\n>>> +\n>>>          <p>\n>>>            If not set the value from <ref column=\"options\"\n>>>            key=\"dynamic-routing-redistribute\" table=\"Logical_Router\"/>\n>>> on the\n>>> @@ -4823,6 +4837,13 @@ or\n>>>        database.\n>>>      </column>\n>>>\n>>> +    <column name=\"external_ids\" key=\"ic-source-dynamic\">\n>>> +      <code>ovn-ic</code> populates this key for routes learned from\n>>> +      <ref db=\"OVN_IC_Southbound\"/>. The value is <code>true</code> if\n>>> the\n>>> +      learned route originated from dynamic sources (e.g. learned\n>>> routes)\n>>> +      in the advertising availability zone, otherwise\n>>> <code>false</code>.\n>>> +    </column>\n>>> +\n>>>      <group title=\"Common Columns\">\n>>>        <column name=\"external_ids\">\n>>>          See <em>External IDs</em> at the beginning of this document.\n>>> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\n>>> index 370a755be..a62d02da0 100644\n>>> --- a/tests/ovn-ic.at\n>>> +++ b/tests/ovn-ic.at\n>>> @@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])\n>>>\n>>>  AT_CLEANUP\n>>>  ])\n>>> +\n>>> +\n>>> +OVN_FOR_EACH_NORTHD([\n>>> +AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route -\n>>> hub and spoke mode])\n>>> +\n>>> +ovn_init_ic_db\n>>> +\n>>> +for i in 1 2; do\n>>> +    ovn_start az$i\n>>> +    ovn_as az$i\n>>> +\n>>> +    # Enable route learning at AZ level\n>>> +    check ovn-nbctl set nb_global . options:ic-route-learn=true\n>>> +    # Enable route advertising at AZ level\n>>> +    check ovn-nbctl set nb_global . options:ic-route-adv=true\n>>> +done\n>>> +\n>>> +# Create new transit switches and LRs. Test topology is next:\n>>> +#\n>>> +#\n>>> +# logical router (lr11) - transit switch (ts11) - logical router (lr12)\n>>> +#\n>>> +#\n>>> +\n>>> +# Create lr11, lr12 and ts11 and connect them\n>>> +for i in 1 2; do\n>>> +    ovn_as az$i\n>>> +\n>>> +    lr=lr1$i\n>>> +    check ovn-nbctl lr-add $lr\n>>> +\n>>> +    ts=ts11\n>>> +    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts\n>>> +\n>>> +    lrp=lrp-$lr-$ts\n>>> +    lsp=lsp-$ts-$lr\n>>> +    # Create LRP and connect to TS\n>>> +    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i\n>>> 169.254.101.$i/24\n>>> +    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp\n>>> +done\n>>> +\n>>> +# Create directly-connected route in lr12\n>>> +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 \"\n>>> 192.168.0.1/24\"\n>>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep\n>>> 192.168 |\n>>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>>> +192.168.0.0/24 169.254.101.2\n>>> +])\n>>> +\n>>> +ovn_as az2\n>>> +check ovn-nbctl --wait=sb set Logical_Router lr12\n>>> option:dynamic-routing=true \\\n>>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>>> +check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1\n>>> 00:00:00:00:ff:01 10.0.0.1/24\n>>> +dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)\n>>> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)\n>>> +\n>>> +check_uuid ovn-sbctl create Learned_Route \\\n>>> +    datapath=$datapath                    \\\n>>> +    logical_port=$dr1                     \\\n>>> +    ip_prefix=192.168.1.0/24              \\\n>>> +    nexthop=10.0.0.20\n>>> +\n>>> +# Check Learned_Route adv in ovn-ic\n>>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |\n>>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>>> +10.0.0.0/24 169.254.101.2\n>>> +192.168.0.0/24 169.254.101.2\n>>> +192.168.1.0/24 169.254.101.2\n>>> +])\n>>> +\n>>> +ovn_as az1\n>>> +check ovn-nbctl --wait=sb set Logical_Router lr11\n>>> option:dynamic-routing=true \\\n>>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>>> +# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes\n>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>>> +check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24\n>>> +\n>>> +\n>>> +ovn_as az1\n>>> +check ovn-nbctl --wait=sb set Logical_Router lr11 \\\n>>> +    option:dynamic-routing-redistribute=\"connected,static,hub-spoke\"\n>>> +# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes\n>>> +# Route 192.168.1.0/24 is learned by DR from other logical routes\n>>> (lr12)\n>>> +# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing\n>>> in lr11\n>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24\n>>> +\n>>>\n>>\n>> I would add an extra check that removed the hub-spoke again just to be\n>> sure.\n>>\n>\n> I agree\n>\n>\n>>\n>>\n>>> +OVN_CLEANUP_IC([az1], [az2])\n>>> +\n>>> +AT_CLEANUP\n>>> +])\n>>> --\n>>> 2.43.0\n>>>\n>>>\n>>> --\n>>>\n>>>\n>>>\n>>>\n>>> _'Esta mensagem é direcionada apenas para os endereços constantes no\n>>> cabeçalho inicial. Se você não está listado nos endereços constantes no\n>>> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa\n>>> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas\n>>> estão\n>>> imediatamente anuladas e proibidas'._\n>>>\n>>>\n>>> * **'Apesar do Magazine Luiza tomar\n>>> todas as precauções razoáveis para assegurar que nenhum vírus esteja\n>>> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade\n>>> por\n>>> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*\n>>>\n>>>\n>>>\n>>> _______________________________________________\n>>> dev mailing list\n>>> dev@openvswitch.org\n>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev\n>>>\n>>>\n>> Regards,\n>> Ales\n>>\n>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=luizalabs.com header.i=@luizalabs.com\n header.a=rsa-sha256 header.s=google header.b=oFMDq4fg;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp2.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=luizalabs.com header.i=@luizalabs.com header.a=rsa-sha256\n header.s=google header.b=oFMDq4fg","smtp2.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=luizalabs.com"],"Received":["from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fsZCv5VNpz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 21:22:51 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp2.osuosl.org (Postfix) with ESMTP id 6146940823;\n\tFri, 10 Apr 2026 11:22:44 +0000 (UTC)","from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id BQ-Hbev4oOw0; Fri, 10 Apr 2026 11:22:42 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp2.osuosl.org (Postfix) with ESMTPS id 0719740523;\n\tFri, 10 Apr 2026 11:22:42 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id D40A1C054A;\n\tFri, 10 Apr 2026 11:22:41 +0000 (UTC)","from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 1FAA5C0549\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:22:41 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 0559840523\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:22:41 +0000 (UTC)","from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id zBycny7P6bDE for <dev@openvswitch.org>;\n Fri, 10 Apr 2026 11:22:39 +0000 (UTC)","from mail-ot1-x32f.google.com (mail-ot1-x32f.google.com\n [IPv6:2607:f8b0:4864:20::32f])\n by smtp2.osuosl.org (Postfix) with ESMTPS id D16C840399\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 11:22:38 +0000 (UTC)","by mail-ot1-x32f.google.com with SMTP id\n 46e09a7af769-7dbca22dbfeso952307a34.1\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 04:22:38 -0700 (PDT)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp2.osuosl.org 0719740523","OpenDKIM Filter v2.11.0 smtp2.osuosl.org D16C840399"],"Received-SPF":"Pass (mailfrom) identity=mailfrom;\n client-ip=2607:f8b0:4864:20::32f; helo=mail-ot1-x32f.google.com;\n envelope-from=lucas.vdias@luizalabs.com; receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp2.osuosl.org D16C840399","ARC-Seal":"i=1; a=rsa-sha256; t=1775820157; cv=none;\n d=google.com; s=arc-20240605;\n b=bjTCJyOQPzIchIAfwFfslSEu1CuKzK7UyQX8W4EP+TQBs6kEJCd1QLb8Xe5aAsle5g\n 0u0dO/kHhe8jsXUBt9ypQS++kOkRJYfS+DtXFSPJutM4qDiYPIrgw8x6Ro6PEc+xiwpU\n SQAjxh2vxFMXdtQ7Diahdg5l/22briMwgozpEE++fjTmwkpo0CkNY9BSBjbx9tOForVQ\n HzcmZIxhXTMtfJK5VqwbdsGnSDgdU9aYK0hUjNNGokPwL+40Pi3QPbwRbBrnNviiEipH\n eDiuv6T0iPS2n0J6ccbEqCTqDyPTwJLwAbOXQuZsLkOJE4XoXA/FHI8iKc0oyGoPFv1n\n rD5A==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:dkim-signature;\n bh=q5l2XOrnSZTEMitcaipeLyig2u5GbCszWxMDwr1Vw9E=;\n fh=8kKxe5qJyJFg8uGJ6dGu+ueszPwToZJGpmjLMzx6TXA=;\n b=GuGfPM8cUwHwFQLl/FhFctunVCJ1dfHbPZJh8/8MFmYBSQo5wis6Ue0WuDj0H16DLa\n p5wGgETayvcUMkw7WkWCkxcy1GObQQ0oRC7FkIbiM51emRTw6Ccsh6NiyNxpXiM0y7vM\n UwCJHPsa5ti/YNH8QKbaRPSF7Wxli5fDUmub4F9WwggxUJfjzgiWLjaCfGBk6fmH2DUI\n qg4PSk9m/bnE/7uJqUKjYNDJW3jOIIbUKx/FnbfNv7NAeHpmsZF1/ONRh0M3u0q5BBcd\n 0JvTuGrmBPIwvhpHZGsGRriJ+QGMZ4pAzw+6f/0+wPH/lifSbwzOs4/kjX7cz7oa9vB3\n vgmQ==; darn=openvswitch.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=luizalabs.com; s=google; t=1775820157; x=1776424957; darn=openvswitch.org;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:from:to:cc:subject:date:message-id:reply-to;\n bh=q5l2XOrnSZTEMitcaipeLyig2u5GbCszWxMDwr1Vw9E=;\n b=oFMDq4fga3Sj8bB4yqKJsPzUcoMOvxDdhGd9jSvsZT+aSjYwlqBbox2e1RtUKcN7a4\n d8DOhKnHfbFpjb4tJbXSKGzz/hxbvpU9BfsFOLojdjur4r94qUBRzgl+1LC7nTk5QiIl\n QrR5ObTHyWHgGGlU9ZrXzVHYMmSd1a9CDctlE=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775820157; x=1776424957;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=q5l2XOrnSZTEMitcaipeLyig2u5GbCszWxMDwr1Vw9E=;\n b=mgfVPSSsScoKq5N/VF4nHlyfokr3bqrTkuM8pEx2L7Ay40UgfYK54BRPgERHBUuClV\n SLYUFNLuSEWezOMxK/wrZROQvz2JUrxNG5h6OEVtYq7s+VlgvTsLcpafMEg9m1Y+Re4r\n H45L7bgl81Xx5JGXeEXGBRo+ki9InWEF3zuIAhFpmI8pDG6a6IR3y0I56lzDMPtr/oCk\n zJ3Rps31lP2FVc33fTJaLPVHCeZnpii9uRloXs3q/5HZNrmbw6Q88FC+Jwkk6CkCz6cI\n WrOB4YG5ZsnoEcoVCxzKuOyCMRhbcT9XZCU5G7O2jfMYFxV0Eup/oEeHpN4+CL1F/Ayr\n 5LjA==","X-Gm-Message-State":"AOJu0YxorIjlc3Um02P6IGRJal5tSSJCLa2yL6ywbUQp13bKb6VE3hrv\n nleSliIF+/+7n7ym/3sv69XCRPjnmE8wLGXh66OYEXhQUdAUH6KCYyyR5fS98ozzzGRH/kSMp7a\n 9avIp7DVQiFx+Ey8iatOnrpqRZ6rX6i09CITgPywaG+FD6l3O4oM8CNk+3+jTRb3e4y9Upn3uER\n l5O3WpzXvukQrwTG5W7x+nkA==","X-Gm-Gg":"AeBDies3Ytkz51jvcvNlxRzkeONlztN6EicU/nH0CarsHDn2keP5pm/CyQQSaz++1Sp\n XGbJJrs/vOyNPDCPY9FmsDEca5Q2qrEvMZon4Fb+AdWGLzt28wcDI46CkgZIGnNnQcOdUwRiXfe\n 921DsYQWFK4TJjsfI/5sZnfOqE3kW50wMgtNZ8gAnniY90rl/DGlsoguBo4uiRcyLgW5bbFrglG\n oeXITy8NFlR61mVOEABS1HRzkAOApHhllEbiPXQ/TpdZzF2qpIDOdapsTMs7Ydou1l0k0BOlWzR\n y8LQuJrkWw==","X-Received":"by 2002:a05:6820:5183:b0:688:6d55:190 with SMTP id\n 006d021491bc7-68be8cd8892mr758555eaf.55.1775820157041; Fri, 10 Apr 2026\n 04:22:37 -0700 (PDT)","MIME-Version":"1.0","References":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>\n <CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>\n <CACAUutPSeTajT9SZO_6o0zn+J4eeN9-oztNtb=1Bzy=PTTE1KQ@mail.gmail.com>","In-Reply-To":"\n <CACAUutPSeTajT9SZO_6o0zn+J4eeN9-oztNtb=1Bzy=PTTE1KQ@mail.gmail.com>","Date":"Fri, 10 Apr 2026 08:22:24 -0300","X-Gm-Features":"AQROBzDvgI1tpTvgbo9-ACCZjbLoyGOsQhm3i75O0oLy76g1wV_q35SUWHSOcrM","Message-ID":"\n <CACAUutMYqnbFhRZ_1Pc-2-hfRRrcBY_HVd9ExryAkF8fityOfQ@mail.gmail.com>","To":"Ales Musil <amusil@redhat.com>","Cc":"dev@openvswitch.org","X-Content-Filtered-By":"Mailman/MimeDel 2.1.30","Subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Lucas Vargas Dias via dev <ovs-dev@openvswitch.org>","Reply-To":"Lucas Vargas Dias <lucas.vdias@luizalabs.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"}},{"id":3675862,"web_url":"http://patchwork.ozlabs.org/comment/3675862/","msgid":"<CALVEqe7H6QZRpTDp7omdWQiuyW0=-8wsTppyA=AgfiywC=FhTQ@mail.gmail.com>","list_archive_url":null,"date":"2026-04-10T12:22:52","subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","submitter":{"id":83634,"url":"http://patchwork.ozlabs.org/api/people/83634/","name":"Ales Musil","email":"amusil@redhat.com"},"content":"On Fri, Apr 10, 2026 at 1:22 PM Lucas Vargas Dias <lucas.vdias@luizalabs.com>\nwrote:\n\n>\n>\n> Em sex., 10 de abr. de 2026 às 08:07, Lucas Vargas Dias <\n> lucas.vdias@luizalabs.com> escreveu:\n>\n>> Hi Ales\n>>\n>> Thanks for your review.\n>>\n>>\n>> Em sex., 10 de abr. de 2026 às 06:06, Ales Musil <amusil@redhat.com>\n>> escreveu:\n>>\n>>>\n>>>\n>>> On Tue, Feb 3, 2026 at 9:24 PM Lucas Vargas Dias via dev <\n>>> ovs-dev@openvswitch.org> wrote:\n>>>\n>>>> Consider the scenario where there are 2 AZs using ovn-ic, each AZ has\n>>>> one LR and its LS. The LRs are interconnected by a transit switch.\n>>>> On each AZ, we can configure the dynamic routing and exchange routes\n>>>> via BGP with external BGP speakers.\n>>>>\n>>>> AZ1\n>>>> LS1 - LR1 - BGP Speaker1 - Local subnet1\n>>>>        \\\n>>>>    -----------------------\n>>>>     transit switch\n>>>>    -----------------------\n>>>> AZ2    /\n>>>> LS2 - LR2 - BGP Speaker2 - Local subnet2\n>>>>\n>>>> The LR2 will learn the subnet1 prefix via ovn-ic but this prefix will\n>>>> not be redistributed to BGP Speaker2 and it also happens with LR1.\n>>>> This scenario uses the network's hub-and-spoke terminology where we can\n>>>> enable the hub-spoke on the LR for such redistribution.\n>>>> subnet1 and subnet2 are configured as ic-source-dynamic=true in ovn-ic.\n>>>> Also, consider the same scenario, but LR1 and LR2 learn the same subnet\n>>>> for redundancy, hub-spoke option is disabled to not adv the subnet\n>>>> learned\n>>>> from BGP and advertised in ovn-ic in BGP speakers.\n>>>>\n>>>> Signed-off-by: Lucas Vargas Dias <lucas.vdias@luizalabs.com>\n>>>> ---\n>>>>\n>>>\n>>> Hi Lucas,\n>>>\n>>> sorry for the delay. I have a few comments down below. It also needs a\n>>> rebase.\n>>>\n>>>\n>>>>  NEWS                              |  6 ++\n>>>>  ic/ovn-ic.c                       | 28 +++++++---\n>>>>  northd/en-advertised-route-sync.c |  3 +\n>>>>  northd/northd.c                   | 10 +++-\n>>>>  northd/northd.h                   |  5 +-\n>>>>  northd/ovn-northd.c               |  1 -\n>>>>  ovn-nb.xml                        | 21 +++++++\n>>>>  tests/ovn-ic.at                   | 92 +++++++++++++++++++++++++++++++\n>>>>  8 files changed, 156 insertions(+), 10 deletions(-)\n>>>>\n>>>> diff --git a/NEWS b/NEWS\n>>>> index 2a2b5e12d..6002820f3 100644\n>>>> --- a/NEWS\n>>>> +++ b/NEWS\n>>>> @@ -40,6 +40,8 @@ Post v25.09.0\n>>>>       * Add the \"options:dynamic-routing-no-learning\" to Logical\n>>>> Routers ports.\n>>>>         If set to true, router port will not learn routes and will\n>>>> forget\n>>>>         learned routes. This option has priority over its router\n>>>> counterpart.\n>>>> +     * Add support for hub-and-spoke propagation via the \"hub-spoke\"\n>>>> option\n>>>> +       in dynamic-routing-redistribute settings.\n>>>>     - Add support for Network Function insertion in OVN with stateful\n>>>> traffic\n>>>>       redirection capability in Logical Switch datapath. The feature\n>>>> introduces\n>>>>       three new NB database tables:\n>>>> @@ -98,6 +100,10 @@ Post v25.09.0\n>>>>       reserving an unused IP from the backend's subnet. This change\n>>>> allows\n>>>>       using LRP IPs directly, eliminating the need to reserve\n>>>> additional IPs\n>>>>       per backend port.\n>>>> +   - Add the external_ids:ic-source-dynamic key for\n>>>> +     Logical_Router_Static_Route to indicate whether a learned OVN-IC\n>>>> route\n>>>> +     originated from dynamic routing sources in the advertising\n>>>> availability\n>>>> +     zone.\n>>>>\n>>>>  OVN v25.09.0 - xxx xx xxxx\n>>>>  --------------------------\n>>>> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\n>>>> index fd5ecefb3..e9fff2d4d 100644\n>>>> --- a/ic/ovn-ic.c\n>>>> +++ b/ic/ovn-ic.c\n>>>> @@ -1283,6 +1283,7 @@ struct ic_route_info {\n>>>>      struct in6_addr prefix;\n>>>>      unsigned int plen;\n>>>>      struct in6_addr nexthop;\n>>>> +    bool is_src_dynamic;\n>>>>      const char *origin;\n>>>>      const char *route_table;\n>>>>      const char *route_tag;\n>>>> @@ -1554,7 +1555,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>>>> struct in6_addr prefix,\n>>>>                   const struct nbrec_logical_router_static_route\n>>>> *nb_route,\n>>>>                   const struct nbrec_logical_router *nb_lr,\n>>>>                   const struct nbrec_load_balancer *nb_lb,\n>>>> -                 const char *route_tag)\n>>>> +                 const char *route_tag, bool is_src_dynamic)\n>>>>  {\n>>>>      ovs_assert(nb_route || nb_lrp || nb_lb || nb_lr);\n>>>>\n>>>> @@ -1573,6 +1574,7 @@ add_to_routes_ad(struct hmap *routes_ad, const\n>>>> struct in6_addr prefix,\n>>>>          ic_route->nb_route = nb_route;\n>>>>          ic_route->origin = origin;\n>>>>          ic_route->route_table = route_table;\n>>>> +        ic_route->is_src_dynamic = is_src_dynamic;\n>>>>          ic_route->nb_lrp = nb_lrp;\n>>>>          ic_route->nb_lr = nb_lr;\n>>>>          ic_route->nb_lb = nb_lb;\n>>>> @@ -1649,7 +1651,7 @@ add_static_to_routes_ad(\n>>>>\n>>>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>>>> ROUTE_ORIGIN_STATIC,\n>>>>                       nb_route->route_table, NULL, nb_route, nb_lr,\n>>>> -                     NULL, route_tag);\n>>>> +                     NULL, route_tag, false);\n>>>>  }\n>>>>\n>>>>  static void\n>>>> @@ -1659,7 +1661,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>>>> const char *network,\n>>>>                           const struct smap *nb_options,\n>>>>                           const struct nbrec_logical_router *nb_lr,\n>>>>                           const char *route_tag,\n>>>> -                         const struct nbrec_logical_router_port\n>>>> *ts_lrp)\n>>>> +                         const struct nbrec_logical_router_port\n>>>> *ts_lrp,\n>>>> +                         bool is_src_dynamic)\n>>>>  {\n>>>>      struct in6_addr prefix, nexthop;\n>>>>      unsigned int plen;\n>>>> @@ -1711,7 +1714,8 @@ add_network_to_routes_ad(struct hmap *routes_ad,\n>>>> const char *network,\n>>>>\n>>>>      /* directly-connected routes go to <main> route table */\n>>>>      add_to_routes_ad(routes_ad, prefix, plen, nexthop,\n>>>> ROUTE_ORIGIN_CONNECTED,\n>>>> -                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag);\n>>>> +                     NULL, nb_lrp, NULL, nb_lr, NULL, route_tag,\n>>>> +                     is_src_dynamic);\n>>>>  }\n>>>>\n>>>>  static void\n>>>> @@ -1769,7 +1773,7 @@ add_lb_vip_to_routes_ad(struct hmap *routes_ad,\n>>>> const char *vip_key,\n>>>>\n>>>>      /* Lb vip routes go to <main> route table */\n>>>>      add_to_routes_ad(routes_ad, vip_ip, plen, nexthop, ROUTE_ORIGIN_LB,\n>>>> -                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag);\n>>>> +                     NULL, NULL, NULL, nb_lr, nb_lb, route_tag, false);\n>>>>  out:\n>>>>      free(vip_str);\n>>>>  }\n>>>> @@ -2187,6 +2191,12 @@ sync_learned_routes(struct ic_context *ctx,\n>>>>\n>>>>  nbrec_logical_router_static_route_update_options_setkey(\n>>>>                      nb_route, \"origin\", isb_route->origin);\n>>>>                  free(uuid_s);\n>>>> +                bool is_src_dynamic =\n>>>> smap_get_bool(&isb_route->external_ids,\n>>>> +                    \"ic-source-dynamic\", false);\n>>>> +                char *ic_source_dynamic_str = is_src_dynamic ?\n>>>> +                    \"true\" : \"false\";\n>>>> +\n>>>> nbrec_logical_router_static_route_update_external_ids_setkey(\n>>>> +                    nb_route, \"ic-source-dynamic\",\n>>>> ic_source_dynamic_str);\n>>>>\n>>>\n>>> This is never updated for existing routes, should we do that too?\n>>>\n>>\n>> I forgot this for the existing routes.\n>>\n>>\n>\n> Even using the  new origin (ROUTE_ORIGIN_CONNECTED_DYNAMIC), do you think\n> it is necessary to fill the external_ids?\n>\n\nIf we use origin, it's already there, so it shouldn't be needed.\n\n\n>\n>>\n>>>\n>>>>\n>>>>  nbrec_logical_router_update_static_routes_addvalue(ic_lr->lr,\n>>>>                      nb_route);\n>>>>              }\n>>>> @@ -2243,6 +2253,10 @@ ad_route_sync_external_ids(const struct\n>>>> ic_route_info *route_adv,\n>>>>                                                       \"ic-route-tag\");\n>>>>          }\n>>>>      }\n>>>> +\n>>>> +    char *ic_src_dynamic_str = route_adv->is_src_dynamic ? \"true\" :\n>>>> \"false\";\n>>>> +    icsbrec_route_update_external_ids_setkey(isb_route,\n>>>> \"ic-source-dynamic\",\n>>>> +                                             ic_src_dynamic_str);\n>>>>  }\n>>>>\n>>>>  /* Sync routes from routes_ad to IC-SB. */\n>>>> @@ -2372,7 +2386,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>>>                  add_network_to_routes_ad(routes_ad, lrp->networks[j],\n>>>> lrp,\n>>>>                                           ts_port_addrs,\n>>>>                                           &nb_global->options,\n>>>> -                                         lr, route_tag, ts_lrp);\n>>>> +                                         lr, route_tag, ts_lrp, false);\n>>>>              }\n>>>>          } else {\n>>>>              /* The router port of the TS port is ignored. */\n>>>> @@ -2427,7 +2441,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,\n>>>>          add_network_to_routes_ad(routes_ad, sb_route->ip_prefix, NULL,\n>>>>                                   ts_port_addrs,\n>>>>                                   &nb_global->options,\n>>>> -                                 lr, route_tag, ts_lrp);\n>>>> +                                 lr, route_tag, ts_lrp, true);\n>>>>      }\n>>>>      sbrec_learned_route_index_destroy_row(filter);\n>>>>  }\n>>>> diff --git a/northd/en-advertised-route-sync.c\n>>>> b/northd/en-advertised-route-sync.c\n>>>> index be771391d..be046769f 100644\n>>>> --- a/northd/en-advertised-route-sync.c\n>>>> +++ b/northd/en-advertised-route-sync.c\n>>>> @@ -675,6 +675,8 @@ should_advertise_route(const struct uuidset\n>>>> *host_route_lrps,\n>>>>          return drr_mode_NAT_is_set(drr);\n>>>>      case ROUTE_SOURCE_LB:\n>>>>          return drr_mode_LB_is_set(drr);\n>>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>>> +        return drr_mode_IC_DYNAMIC_is_set(drr);\n>>>>      case ROUTE_SOURCE_LEARNED:\n>>>>          OVS_NOT_REACHED();\n>>>>      default:\n>>>> @@ -745,6 +747,7 @@ advertise_route_track_od(struct\n>>>> advertised_route_sync_data *data,\n>>>>                             &tracked_op->od->nbr->header_.uuid);\n>>>>          }\n>>>>          break;\n>>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>>>      case ROUTE_SOURCE_CONNECTED:\n>>>>      case ROUTE_SOURCE_STATIC:\n>>>>          break;\n>>>> diff --git a/northd/northd.c b/northd/northd.c\n>>>> index b4bb4ba6d..fbb75533c 100644\n>>>> --- a/northd/northd.c\n>>>> +++ b/northd/northd.c\n>>>> @@ -870,6 +870,10 @@ parse_dynamic_routing_redistribute(\n>>>>              out |= DRRM_LB;\n>>>>              continue;\n>>>>          }\n>>>> +        if (!strcmp(token, \"hub-spoke\")) {\n>>>> +            out |= DRRM_IC_DYNAMIC;\n>>>> +            continue;\n>>>> +        }\n>>>>          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n>>>>          VLOG_WARN_RL(&rl,\n>>>>                       \"unknown dynamic-routing-redistribute option '%s'\n>>>> on %s\",\n>>>> @@ -12034,7 +12038,10 @@ parsed_routes_add_static(const struct\n>>>> ovn_datapath *od,\n>>>>      enum route_source source;\n>>>>      if (!strcmp(smap_get_def(&route->options, \"origin\", \"\"),\n>>>>                  ROUTE_ORIGIN_CONNECTED)) {\n>>>> -        source = ROUTE_SOURCE_CONNECTED;\n>>>> +        bool ic_src_dynamic = smap_get_bool(&route->external_ids,\n>>>> +                                            \"ic-source-dynamic\",\n>>>> false);\n>>>> +        source = ic_src_dynamic ?\n>>>> +                 ROUTE_SOURCE_IC_DYNAMIC : ROUTE_SOURCE_CONNECTED;\n>>>>      } else {\n>>>>          source = ROUTE_SOURCE_STATIC;\n>>>>      }\n>>>> @@ -12129,6 +12136,7 @@ route_source_to_offset(enum route_source source)\n>>>>  {\n>>>>      switch (source) {\n>>>>      case ROUTE_SOURCE_CONNECTED:\n>>>> +    case ROUTE_SOURCE_IC_DYNAMIC:\n>>>>          return ROUTE_PRIO_OFFSET_CONNECTED;\n>>>>      case ROUTE_SOURCE_STATIC:\n>>>>          return ROUTE_PRIO_OFFSET_STATIC;\n>>>> diff --git a/northd/northd.h b/northd/northd.h\n>>>> index eb5c15f34..e6ed2cc3e 100644\n>>>> --- a/northd/northd.h\n>>>> +++ b/northd/northd.h\n>>>> @@ -372,7 +372,8 @@ struct mcast_port_info {\n>>>>      DRR_MODE(CONNECTED_AS_HOST, 1) \\\n>>>>      DRR_MODE(STATIC,            2) \\\n>>>>      DRR_MODE(NAT,               3) \\\n>>>> -    DRR_MODE(LB,                4)\n>>>> +    DRR_MODE(LB,                4) \\\n>>>> +    DRR_MODE(IC_DYNAMIC,        5)\n>>>>\n>>>>  enum dynamic_routing_redistribute_mode_bits {\n>>>>  #define DRR_MODE(PROTOCOL, BIT) DRRM_##PROTOCOL##_BIT = BIT,\n>>>> @@ -826,6 +827,8 @@ enum route_source {\n>>>>      ROUTE_SOURCE_NAT,\n>>>>      /* The route is derived from a LB's VIP. */\n>>>>      ROUTE_SOURCE_LB,\n>>>> +    /* The route is derived from an ovn-controller and advertised to\n>>>> IC. */\n>>>> +    ROUTE_SOURCE_IC_DYNAMIC,\n>>>>  };\n>>>>\n>>>>  struct parsed_route {\n>>>> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\n>>>> index 7d7568c6f..bc3969053 100644\n>>>> --- a/northd/ovn-northd.c\n>>>> +++ b/northd/ovn-northd.c\n>>>> @@ -905,7 +905,6 @@ main(int argc, char *argv[])\n>>>>          &nbrec_load_balancer_col_external_ids,\n>>>>          &nbrec_load_balancer_health_check_col_external_ids,\n>>>>          &nbrec_logical_router_policy_col_external_ids,\n>>>> -        &nbrec_logical_router_static_route_col_external_ids,\n>>>>\n>>>\n>>> This is very dangerous, it means that any change\n>>> of external_ids will wake up northd. I think it will be safer\n>>> to make it an option as we track those already.\n>>>\n>>> On a second thought and looking through the\n>>> is there a reason why we can't just add another origin?\n>>> We check the origin anyway in northd, so having\n>>> something like:\n>>>\n>>> #define ROUTE_ORIGIN_CONNECTED_DYNAMIC \"connected-dynamic\"\n>>>\n>>> That would avoid the tracking of external_ids, extra definiton\n>>> of an option and would be probably smaller change in the\n>>> ovn-ic overall, WDYT?\n>>>\n>>\n>> I agree, we can add a new origin. I'll adjust.\n>>\n>>\n>>\n>>>\n>>>          &nbrec_meter_col_external_ids,\n>>>>          &nbrec_meter_band_col_external_ids,\n>>>>          &nbrec_mirror_col_external_ids,\n>>>> diff --git a/ovn-nb.xml b/ovn-nb.xml\n>>>> index 1acbf202b..5f9b47491 100644\n>>>> --- a/ovn-nb.xml\n>>>> +++ b/ovn-nb.xml\n>>>> @@ -3374,6 +3374,13 @@ or\n>>>>            Logical Switch.\n>>>>          </p>\n>>>>\n>>>> +        <p>\n>>>> +          If <code>hub-spoke</code> is in the list then northd will\n>>>> synchronize\n>>>> +          dynamic routes learned through OVN-IC from other routers\n>>>> into the\n>>>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>>>> enabling\n>>>> +          hub-and-spoke propagation.\n>>>> +        </p>\n>>>> +\n>>>>          <p>\n>>>>            This value can be overwritten on a per LRP basis using\n>>>>            <ref column=\"options\" key=\"dynamic-routing-redistribute\"\n>>>> @@ -4461,6 +4468,13 @@ or\n>>>>            via shared Logical Switch.\n>>>>          </p>\n>>>>\n>>>> +        <p>\n>>>> +          If <code>hub-spoke</code> is in the list then northd will\n>>>> synchronize\n>>>> +          dynamic routes learned through OVN-IC from other routers\n>>>> into the\n>>>> +          <ref table=\"Advertised_Route\" db=\"OVN_Southbound\"/> table,\n>>>> enabling\n>>>> +          hub-and-spoke propagation.\n>>>> +        </p>\n>>>> +\n>>>>          <p>\n>>>>            If not set the value from <ref column=\"options\"\n>>>>            key=\"dynamic-routing-redistribute\" table=\"Logical_Router\"/>\n>>>> on the\n>>>> @@ -4823,6 +4837,13 @@ or\n>>>>        database.\n>>>>      </column>\n>>>>\n>>>> +    <column name=\"external_ids\" key=\"ic-source-dynamic\">\n>>>> +      <code>ovn-ic</code> populates this key for routes learned from\n>>>> +      <ref db=\"OVN_IC_Southbound\"/>. The value is <code>true</code> if\n>>>> the\n>>>> +      learned route originated from dynamic sources (e.g. learned\n>>>> routes)\n>>>> +      in the advertising availability zone, otherwise\n>>>> <code>false</code>.\n>>>> +    </column>\n>>>> +\n>>>>      <group title=\"Common Columns\">\n>>>>        <column name=\"external_ids\">\n>>>>          See <em>External IDs</em> at the beginning of this document.\n>>>> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at\n>>>> index 370a755be..a62d02da0 100644\n>>>> --- a/tests/ovn-ic.at\n>>>> +++ b/tests/ovn-ic.at\n>>>> @@ -4586,3 +4586,95 @@ OVN_CLEANUP_IC([az1], [az2])\n>>>>\n>>>>  AT_CLEANUP\n>>>>  ])\n>>>> +\n>>>> +\n>>>> +OVN_FOR_EACH_NORTHD([\n>>>> +AT_SETUP([ovn-ic -- Check ovn-ic adv and learn from SB Learned Route -\n>>>> hub and spoke mode])\n>>>> +\n>>>> +ovn_init_ic_db\n>>>> +\n>>>> +for i in 1 2; do\n>>>> +    ovn_start az$i\n>>>> +    ovn_as az$i\n>>>> +\n>>>> +    # Enable route learning at AZ level\n>>>> +    check ovn-nbctl set nb_global . options:ic-route-learn=true\n>>>> +    # Enable route advertising at AZ level\n>>>> +    check ovn-nbctl set nb_global . options:ic-route-adv=true\n>>>> +done\n>>>> +\n>>>> +# Create new transit switches and LRs. Test topology is next:\n>>>> +#\n>>>> +#\n>>>> +# logical router (lr11) - transit switch (ts11) - logical router (lr12)\n>>>> +#\n>>>> +#\n>>>> +\n>>>> +# Create lr11, lr12 and ts11 and connect them\n>>>> +for i in 1 2; do\n>>>> +    ovn_as az$i\n>>>> +\n>>>> +    lr=lr1$i\n>>>> +    check ovn-nbctl lr-add $lr\n>>>> +\n>>>> +    ts=ts11\n>>>> +    check ovn-ic-nbctl --wait=sb --may-exist ts-add $ts\n>>>> +\n>>>> +    lrp=lrp-$lr-$ts\n>>>> +    lsp=lsp-$ts-$lr\n>>>> +    # Create LRP and connect to TS\n>>>> +    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:a1:0$i\n>>>> 169.254.101.$i/24\n>>>> +    check ovn-nbctl lsp-add-router-port $ts $lsp $lrp\n>>>> +done\n>>>> +\n>>>> +# Create directly-connected route in lr12\n>>>> +check ovn_as az2 ovn-nbctl lrp-add lr12 lrp-lr12 aa:aa:aa:aa:bb:01 \"\n>>>> 192.168.0.1/24\"\n>>>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep\n>>>> 192.168 |\n>>>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>>>> +192.168.0.0/24 169.254.101.2\n>>>> +])\n>>>> +\n>>>> +ovn_as az2\n>>>> +check ovn-nbctl --wait=sb set Logical_Router lr12\n>>>> option:dynamic-routing=true \\\n>>>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>>>> +check ovn_as az2 ovn-nbctl --wait=sb lrp-add lr12 lr12-dr1\n>>>> 00:00:00:00:ff:01 10.0.0.1/24\n>>>> +dr1=$(fetch_column port_binding _uuid logical_port=lr12-dr1)\n>>>> +datapath=$(fetch_column datapath_binding _uuid external_ids:name=lr12)\n>>>> +\n>>>> +check_uuid ovn-sbctl create Learned_Route \\\n>>>> +    datapath=$datapath                    \\\n>>>> +    logical_port=$dr1                     \\\n>>>> +    ip_prefix=192.168.1.0/24              \\\n>>>> +    nexthop=10.0.0.20\n>>>> +\n>>>> +# Check Learned_Route adv in ovn-ic\n>>>> +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 |\n>>>> +             grep learned | awk '{print $1, $2}' | sort ], [0], [dnl\n>>>> +10.0.0.0/24 169.254.101.2\n>>>> +192.168.0.0/24 169.254.101.2\n>>>> +192.168.1.0/24 169.254.101.2\n>>>> +])\n>>>> +\n>>>> +ovn_as az1\n>>>> +check ovn-nbctl --wait=sb set Logical_Router lr11\n>>>> option:dynamic-routing=true \\\n>>>> +    option:dynamic-routing-redistribute=\"connected,static\"\n>>>> +# Advertise just 10.0.0.0/24 and 192.168.0.0/24 routes\n>>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>>>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>>>> +check_row_count Advertised_Route 0 ip_prefix=192.168.1.0/24\n>>>> +\n>>>> +\n>>>> +ovn_as az1\n>>>> +check ovn-nbctl --wait=sb set Logical_Router lr11 \\\n>>>> +    option:dynamic-routing-redistribute=\"connected,static,hub-spoke\"\n>>>> +# Advertise just 10.0.0.0/24, 192.168.0.0/24 and 192.168.1.0/24 routes\n>>>> +# Route 192.168.1.0/24 is learned by DR from other logical routes\n>>>> (lr12)\n>>>> +# And lr12 Advertised it in ovn-ic. Hub-spoke option enable re-routing\n>>>> in lr11\n>>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.0.0/24\n>>>> +check_row_count Advertised_Route 1 ip_prefix=10.0.0.0/24\n>>>> +check_row_count Advertised_Route 1 ip_prefix=192.168.1.0/24\n>>>> +\n>>>>\n>>>\n>>> I would add an extra check that removed the hub-spoke again just to be\n>>> sure.\n>>>\n>>\n>> I agree\n>>\n>>\n>>>\n>>>\n>>>> +OVN_CLEANUP_IC([az1], [az2])\n>>>> +\n>>>> +AT_CLEANUP\n>>>> +])\n>>>> --\n>>>> 2.43.0\n>>>>\n>>>>\n>>>> --\n>>>>\n>>>>\n>>>>\n>>>>\n>>>> _'Esta mensagem é direcionada apenas para os endereços constantes no\n>>>> cabeçalho inicial. Se você não está listado nos endereços constantes no\n>>>> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa\n>>>> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas\n>>>> estão\n>>>> imediatamente anuladas e proibidas'._\n>>>>\n>>>>\n>>>> * **'Apesar do Magazine Luiza tomar\n>>>> todas as precauções razoáveis para assegurar que nenhum vírus esteja\n>>>> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade\n>>>> por\n>>>> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*\n>>>>\n>>>>\n>>>>\n>>>> _______________________________________________\n>>>> dev mailing list\n>>>> dev@openvswitch.org\n>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev\n>>>>\n>>>>\n>>> Regards,\n>>> Ales\n>>>\n>>\n>\n> *‘Esta mensagem é direcionada apenas para os endereços constantes no\n> cabeçalho inicial. Se você não está listado nos endereços constantes no\n> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa\n> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão\n> imediatamente anuladas e proibidas’.*\n>\n>  *‘Apesar do Magazine Luiza tomar todas as precauções razoáveis para\n> assegurar que nenhum vírus esteja presente nesse e-mail, a empresa não\n> poderá aceitar a responsabilidade por quaisquer perdas ou danos causados\n> por esse e-mail ou por seus anexos’.*\n>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=dQza27+r;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp3.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=dQza27+r","smtp3.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com"],"Received":["from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fsbYd3vX3z20HV\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 10 Apr 2026 22:23:17 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby smtp3.osuosl.org (Postfix) with ESMTP id 071D060ED5;\n\tFri, 10 Apr 2026 12:23:15 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id iMzQcEP7g-Tq; Fri, 10 Apr 2026 12:23:13 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp3.osuosl.org (Postfix) with ESMTPS id 735D6607DC;\n\tFri, 10 Apr 2026 12:23:13 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 3BAB3C054A;\n\tFri, 10 Apr 2026 12:23:13 +0000 (UTC)","from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n by lists.linuxfoundation.org (Postfix) with ESMTP id E9793C0549\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 12:23:11 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp3.osuosl.org (Postfix) with ESMTP id D560660B70\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 12:23:11 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id UxnhrRBz5MDj for <dev@openvswitch.org>;\n Fri, 10 Apr 2026 12:23:10 +0000 (UTC)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by smtp3.osuosl.org (Postfix) with ESMTPS id 9332E607DC\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 12:23:08 +0000 (UTC)","from mail-yw1-f198.google.com (mail-yw1-f198.google.com\n [209.85.128.198]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-642-Xjc4eqAlObSO_-lUBLud3w-1; Fri, 10 Apr 2026 08:23:06 -0400","by mail-yw1-f198.google.com with SMTP id\n 00721157ae682-794d80fea59so35504467b3.1\n for <dev@openvswitch.org>; Fri, 10 Apr 2026 05:23:06 -0700 (PDT)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp3.osuosl.org 735D6607DC","OpenDKIM Filter v2.11.0 smtp3.osuosl.org 9332E607DC"],"Received-SPF":"Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com;\n receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp3.osuosl.org 9332E607DC","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1775823788;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=KspMbE/a4DKz/UbpUNzl1VSWGFjt+402hE2bg8gHX+s=;\n b=dQza27+rSaJ364Nhp0H6FoVFoqcYoie3zaxPQB1hghvYapHrzZZM4PdtTk0WGMfK9FeG3a\n qcdGoxvOTMVg7RsF63RhM0rpXcP8UayHC4NaiTgqc2qdfDG1pHNnmb4H1AcPP5C29SnA1M\n Gtg2vmPqMKRutejAKN/tCTkCMhMr1Bk=","X-MC-Unique":"Xjc4eqAlObSO_-lUBLud3w-1","X-Mimecast-MFC-AGG-ID":"Xjc4eqAlObSO_-lUBLud3w_1775823786","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775823785; x=1776428585;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=KspMbE/a4DKz/UbpUNzl1VSWGFjt+402hE2bg8gHX+s=;\n b=X0n8/VkITe5xypdfBTpsehJSESjKeWGRN1Ht/GI7aNf3k/5PwtvJRSAOr/HxvLRhIs\n JFE1n8+0Dv8QTN65ACY0U4KA+Z1y2YXAn6uwHwt0/ySO2ijG6QyyvjTuZOaYQM31VbX+\n /EPjTshRDPxBcce98ogWv6gwcKZlX3D6roHH8jrjqCh4qi/Fm6cdoAl9pTkPRQ9SmiVW\n 7AaOtphAL0dcgFcG8kf5ZFyV1dwkSJXfSI9UpnkmS7iBmWmadxsyJ/9x7w9CpG+DsnQD\n Pk+ZulSPJ2IWWhOtilrOgZv4XOC0bntG8ZzS8i0cKje68LIHxK3cQ6W8fOKlWKP0dG5R\n g8HQ==","X-Gm-Message-State":"AOJu0Yx2dATrgzL4ptzYymM4E4CRGFoZe1IQmGuB0qHVSWsicvginh21\n 1W5H8BUHcrc7nrXhVGNHm98c9z2hd23IHUJB4hIlXqyZ0gxTL8gXe8zONVJcEbNL0vlA2YOqDDW\n f185yrcyfa4V/cy7IWOAP9n4e3VRB42IotmDLvwZkF9st9JHsu/5CSm7ysSyOw0zhw+tE8Gp5IX\n Acrw4ujDxl+/BtDy/4ZVuG+QixTQ53498moRxj","X-Gm-Gg":"AeBDieuN5sTQmyyIX7+KWLuF8JJv+hDjrSBbSkZmVBtvogkZfPSLcJTkYS5aSiA1GKO\n 9iUeW60KxN9eMYwFQ8objIIcxjqPoeXxDLnMOdzJFTzp2IfjydhbOnuGAL1hdYovKXMh0TcAnAV\n q4GvPWHIn1LdpLNHkxrdwLodwh/S61GnTEakzrVPby6yL3kx3ody2Z3JTmtbtEndLWVmRaD1qtn\n TDg7h1BUvPLXrP24LXEXLtKvoR8j+GuUVS3PjfSwudZjgelZTLgBJJr62+oPubFgFyi4i3+bssX\n 1bURDTZjMCxK76WHGQF4VceHH5oEU/Plci26eMeZUT6MYBzfcaHempx61qccfEPmT6KPNH/Rftj\n 9PA15ByIbivxf7674qSfXAbg0qUYF/161gKdvaUbtFOt+vAs=","X-Received":["by 2002:a05:690c:c50f:b0:79a:cdf0:e285 with SMTP id\n 00721157ae682-7af6f907270mr27761687b3.13.1775823785238;\n Fri, 10 Apr 2026 05:23:05 -0700 (PDT)","by 2002:a05:690c:c50f:b0:79a:cdf0:e285 with SMTP id\n 00721157ae682-7af6f907270mr27761227b3.13.1775823784393; Fri, 10 Apr 2026\n 05:23:04 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260203202354.228161-1-lucas.vdias@luizalabs.com>\n <CALVEqe6bA6O6mUEzcC6pMtG1d4FeX-XftcJv9jZhSXDbfqhpBw@mail.gmail.com>\n <CACAUutPSeTajT9SZO_6o0zn+J4eeN9-oztNtb=1Bzy=PTTE1KQ@mail.gmail.com>\n <CACAUutMYqnbFhRZ_1Pc-2-hfRRrcBY_HVd9ExryAkF8fityOfQ@mail.gmail.com>","In-Reply-To":"\n <CACAUutMYqnbFhRZ_1Pc-2-hfRRrcBY_HVd9ExryAkF8fityOfQ@mail.gmail.com>","Date":"Fri, 10 Apr 2026 14:22:52 +0200","X-Gm-Features":"AQROBzBXgO9CmoZM1dy5VHAhNUDduOa1SIpRyQWTDT_QHAJrMUPWI_Jrde6S3d0","Message-ID":"\n <CALVEqe7H6QZRpTDp7omdWQiuyW0=-8wsTppyA=AgfiywC=FhTQ@mail.gmail.com>","To":"Lucas Vargas Dias <lucas.vdias@luizalabs.com>","Cc":"dev@openvswitch.org","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"7PIddwikODnu7mfylK-VeXIsRASAD4OSH1ejKFKodDI_1775823786","X-Mimecast-Originator":"redhat.com","X-Content-Filtered-By":"Mailman/MimeDel 2.1.30","Subject":"Re: [ovs-dev] [PATCH ovn v2] northd,\n ic: Add hub-spoke options to adv DR routes learned in ovn-ic.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","From":"Ales Musil via dev <ovs-dev@openvswitch.org>","Reply-To":"Ales Musil <amusil@redhat.com>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"}}]