On Wed, Jan 21, 2026 at 3:12 PM Lucas Vargas Dias via dev <
[email protected]> wrote:

> If the LRPs are scheduled in the same chassis for some reason,
> ovn controller will try to advertise many times the same prefix with the
> same priority.
> This generates a high CPU load in ovn-controller and generate a lot of
> messages
> like the following:
> "Add route table_id=1337 dst=42.10.10.14 plen=32 nexthop=(blackhole)
> failed: File exists"
> To fix it, just check if prefix was already advertised with the same
> priority.
>
> Fixes: ccb0b6b9109c ("controller: Introduce route node.")
> Signed-off-by: Lucas Vargas Dias <[email protected]>
> ---
>  controller/route-exchange-netlink.c | 14 ++---
>  controller/route.c                  | 27 ++++++++-
>  controller/route.h                  |  4 ++
>  tests/system-ovn.at                 | 87 +++++++++++++++++++++++++++++
>  4 files changed, 121 insertions(+), 11 deletions(-)
>
> diff --git a/controller/route-exchange-netlink.c
> b/controller/route-exchange-netlink.c
> index 4e51bf69c..7ab0690f2 100644
> --- a/controller/route-exchange-netlink.c
> +++ b/controller/route-exchange-netlink.c
> @@ -261,15 +261,11 @@ handle_route_msg(const struct route_table_msg *msg,
> void *data)
>      const struct advertise_route_entry re =
>              advertise_route_from_route_data(rd);
>      if (handle_data->routes_to_advertise) {
> -        uint32_t hash = advertise_route_hash(&re.addr, &re.nexthop,
> re.plen);
> -        HMAP_FOR_EACH_WITH_HASH (ar, node, hash, handle_data->routes) {
> -            if (ipv6_addr_equals(&ar->addr, &re.addr)
> -                    && ar->plen == re.plen
> -                    && ipv6_addr_equals(&ar->nexthop, &re.nexthop)
> -                    && ar->priority == re.priority) {
> -                hmapx_find_and_delete(handle_data->routes_to_advertise,
> ar);
> -                return;
> -            }
> +        ar = advertise_route_find(re.priority, &re.addr, re.plen,
> +                                  &re.nexthop, handle_data->routes);
> +        if (ar) {
> +            hmapx_find_and_delete(handle_data->routes_to_advertise, ar);
> +            return;
>          }
>      }
>
> diff --git a/controller/route.c b/controller/route.c
> index ecddd0497..1b9c9915a 100644
> --- a/controller/route.c
> +++ b/controller/route.c
> @@ -368,13 +368,19 @@ route_run(struct route_ctx_in *r_ctx_in,
>              }
>          }
>
> +        struct in6_addr nexthop = IN6_IS_ADDR_V4MAPPED(&prefix)
> +                ? ad->ipv4_nexthop : ad->ipv6_nexthop;
> +        if (advertise_route_find(priority, &prefix, plen, &nexthop,
> +                                 &ad->routes)) {
> +            continue;
> +        }
> +
>          struct advertise_route_entry *ar = xmalloc(sizeof(*ar));
>          *ar = (struct advertise_route_entry) {
>              .addr = prefix,
>              .plen = plen,
>              .priority = priority,
> -            .nexthop = IN6_IS_ADDR_V4MAPPED(&prefix)
> -                       ? ad->ipv4_nexthop : ad->ipv6_nexthop,
> +            .nexthop = nexthop,
>          };
>          hmap_insert(&ad->routes, &ar->node,
>                      advertise_route_hash(&ar->addr, &ar->nexthop, plen));
> @@ -399,3 +405,20 @@ route_get_table_id(const struct
> sbrec_datapath_binding *dp)
>                                          "dynamic-routing-vrf-id", -1);
>      return (vrf_id >= 1 && vrf_id <= UINT32_MAX) ? vrf_id :
> dp->tunnel_key;
>  }
> +
> +struct advertise_route_entry *
> +advertise_route_find(unsigned int priority, const struct in6_addr *prefix,
> +                     unsigned int plen, const struct in6_addr *nexthop,
> +                     const struct hmap *advertised_routes)
> +{
> +    uint32_t hash = advertise_route_hash(prefix, nexthop, plen);
> +    struct advertise_route_entry *ar;
> +    HMAP_FOR_EACH_WITH_HASH (ar, node, hash, advertised_routes) {
> +        if (ar->priority == priority &&
> +            ipv6_addr_equals(&ar->addr, prefix) && ar->plen == plen &&
>

nit: It's better to order it by the order in the struct.


> +            ipv6_addr_equals(&ar->nexthop, nexthop)) {
> +            return ar;
> +        }
> +    }
> +    return NULL;
> +}
> diff --git a/controller/route.h b/controller/route.h
> index de77f64fc..108e34200 100644
> --- a/controller/route.h
> +++ b/controller/route.h
> @@ -101,5 +101,9 @@ advertise_route_from_route_data(const struct
> route_data *);
>  void route_run(struct route_ctx_in *, struct route_ctx_out *);
>  void route_cleanup(struct hmap *announce_routes);
>  uint32_t route_get_table_id(const struct sbrec_datapath_binding *);
> +struct advertise_route_entry *
> +advertise_route_find(unsigned int priority, const struct in6_addr *prefix,
> +                     unsigned int plen, const struct in6_addr *nexthop,
> +                     const struct hmap *advertised_routes);
>
>  #endif /* ROUTE_H */
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 636b1e4d9..59701d41b 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -17061,6 +17061,93 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port
> patch-.*/d
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([dynamic-routing - multiple DGP with same priority])
> +
> +VRF_RESERVE([1337])
> +
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +
> +ADD_BR([br-int])
> +check ovs-vsctl
>            \
> +    -- set Open_vSwitch . external-ids:system-id=hv1
>           \
> +    -- set Open_vSwitch .
> external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +    -- set Open_vSwitch . external-ids:ovn-encap-type=geneve
>           \
> +    -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1
>            \
> +    -- set bridge br-int fail-mode=secure
> other-config:disable-in-band=true
> +
> +start_daemon ovn-controller
> +check ovn-nbctl
>      \
> +    -- lr-add lr
>     \
> +      -- set logical_router lr options:dynamic-routing=true
>      \
> +                               options:dynamic-routing-vrf-id=1337
>     \
> +      -- lrp-add lr lr-gw1 00:00:00:01:00:10 42.10.10.12/24
>      \
> +        -- lrp-set-gateway-chassis lr-gw1 hv1 10
>     \
> +        -- lrp-set-options lr-gw1 dynamic-routing-redistribute=nat,lb
>      \
> +                                  dynamic-routing-maintain-vrf=true
>      \
> +      -- lrp-add lr lr-gw2 00:00:00:02:00:10 42.20.10.22/24
>      \
> +        -- lrp-set-gateway-chassis lr-gw2 hv1 10
>     \
> +        -- lrp-set-options lr-gw2 dynamic-routing-redistribute=nat,lb
>      \
> +                                  dynamic-routing-maintain-vrf=true
>      \
> +      -- lrp-add lr lr-int1 00:00:00:00:01:02 30.0.1.1/24
>      \
> +        -- lrp-set-options lr-int1
> dynamic-routing-redistribute=connected     \
> +      -- lrp-add lr lr-int2 00:00:00:00:01:02 30.0.2.1/24
>      \
> +        -- lrp-set-options lr-int2
> dynamic-routing-redistribute=connected     \
> +    -- ls-add ls
>     \
> +      -- lsp-add-router-port ls ls-lr-gw1 lr-gw1
>     \
> +      -- lsp-add-router-port ls ls-lr-gw2 lr-gw2
>     \
> +    -- ls-add ls-int1
>      \
> +      -- lsp-add-router-port ls-int1 ls-int1-lr lr-int1
>      \
> +      -- lsp-add ls-int1 w1
>      \
> +        -- lsp-set-addresses w1 "00:00:00:00:00:01 30.0.1.11"
>      \
> +    -- ls-add ls-int2
>      \
> +      -- lsp-add-router-port ls-int2 ls-int2-lr lr-int2
>      \
> +      -- lsp-add ls-int2 w2
>      \
> +        -- lsp-set-addresses w2 "00:00:00:00:00:02 30.0.2.11"
>      \
> +    -- lr-nat-add lr dnat_and_snat 42.10.10.23 30.0.1.11 w1
> 00:00:00:00:01:11 \
> +    -- lb-add lb1 42.10.10.14 30.0.1.11
>      \
> +    -- lr-lb-add lr lb1
>      \
> +    -- lr-nat-add lr dnat_and_snat 42.20.10.23 30.0.2.11 w2
> 00:00:00:00:02:11 \
> +    -- lb-add lb2 42.20.10.24 30.0.2.11
>      \
> +    -- lr-lb-add lr lb2
> +
> +check ovs-vsctl add-port br-int w1 \
> +    -- set interface w1 type=internal external_ids:iface-id=w1
> +check ovs-vsctl add-port br-int w2 \
> +    -- set interface w2 type=internal external_ids:iface-id=w2
> +check ovn-nbctl --wait=hv sync
> +wait_for_ports_up w1 w2
> +
> +
> +AT_CHECK([ip vrf show ovnvrf1337], [0], [dnl
> +ovnvrf1337 1337
> +])
> +
> +OVN_ROUTE_EQUAL([ovnvrf1337], [dnl
> +blackhole 30.0.1.0/24 proto ovn metric 1000
> +blackhole 30.0.2.0/24 proto ovn metric 1000
> +blackhole 42.10.10.14 proto ovn metric 100
> +blackhole 42.10.10.23 proto ovn metric 100
> +blackhole 42.20.10.23 proto ovn metric 100
> +blackhole 42.20.10.24 proto ovn metric 100])
> +
> +check ovn-nbctl --wait=hv ls-del ls-int1
> +check ovn-nbctl --wait=hv ls-del ls-int2
> +check ovn-nbctl --wait=hv ls-del ls
> +check ovn-nbctl --wait=hv lr-del lr
> +
> +OVN_CLEANUP_CONTROLLER([hv1])
> +
> +OVN_CLEANUP_NORTHD
> +
> +as
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +
> +AT_CLEANUP
> +])
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([Mac binding aging - Probing])
>  AT_KEYWORDS([mac_binding_probing])
> --
> 2.43.0
>
>
> --
>
>
>
>
> _'Esta mensagem é direcionada apenas para os endereços constantes no
> cabeçalho inicial. Se você não está listado nos endereços constantes no
> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa
> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas
> estão
> imediatamente anuladas e proibidas'._
>
>
> * **'Apesar do Magazine Luiza tomar
> todas as precauções razoáveis para assegurar que nenhum vírus esteja
> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por
> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*
>
>
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Thank you Lucas,

I took care of the nit, went ahead, merged it into main and backported down
to 25.03.

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

Reply via email to