On Thu, Dec 11, 2025 at 8:21 PM Dumitru Ceara <[email protected]> wrote:

> On 12/11/25 4:24 PM, Ales Musil wrote:
> > The struct route_data includes an ovs_list, by copying it into vector
> > we might be copying soon to be invalid pointers, in other words
> > pointers to stack variables. This wasn't an issue until now because
> > we didn't reference anything within the list, however it has become
> > an issue with the nexthop reference added later on.
> >
> > Fixes: 13d1a5cbae68 ("controller: Postpone the route deletion after the
> dump is done.")
> > Signed-off-by: Ales Musil <[email protected]>
> > ---
> > v3: New patch in the series.
> > ---
>
> Hi Ales,
>
> Thanks for the patch!
>
> >  controller/route-exchange-netlink.c | 72 ++++++++++++++---------------
> >  controller/route-exchange-netlink.h |  7 ++-
> >  controller/route.c                  | 12 +++++
> >  controller/route.h                  |  3 ++
> >  4 files changed, 54 insertions(+), 40 deletions(-)
> >
> > diff --git a/controller/route-exchange-netlink.c
> b/controller/route-exchange-netlink.c
> > index 60bae4781..d6358343d 100644
> > --- a/controller/route-exchange-netlink.c
> > +++ b/controller/route-exchange-netlink.c
> > @@ -97,11 +97,10 @@ re_nl_delete_vrf(const char *ifname)
> >
> >  static int
> >  modify_route(uint32_t type, uint32_t flags_arg, uint32_t table_id,
> > -             const struct in6_addr *dst, unsigned int plen,
> > -             unsigned int priority)
> > +             const struct advertise_route_entry *re)
> >  {
> >      uint32_t flags = NLM_F_REQUEST | NLM_F_ACK;
> > -    bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(dst);
> > +    bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&re->addr);
> >      struct rtmsg *rt;
> >      int err;
> >
> > @@ -119,15 +118,16 @@ modify_route(uint32_t type, uint32_t flags_arg,
> uint32_t table_id,
> >      rt->rtm_protocol = RTPROT_OVN;
> >      rt->rtm_type = RTN_BLACKHOLE;
> >      rt->rtm_scope = RT_SCOPE_UNIVERSE;
> > -    rt->rtm_dst_len = plen;
> > +    rt->rtm_dst_len = re->plen;
> >
> >      nl_msg_put_u32(&request, RTA_TABLE, table_id);
> > -    nl_msg_put_u32(&request, RTA_PRIORITY, priority);
> > +    nl_msg_put_u32(&request, RTA_PRIORITY, re->priority);
> >
> >      if (is_ipv4) {
> > -        nl_msg_put_be32(&request, RTA_DST,
> in6_addr_get_mapped_ipv4(dst));
> > +        nl_msg_put_be32(&request, RTA_DST,
> > +                        in6_addr_get_mapped_ipv4(&re->addr));
> >      } else {
> > -        nl_msg_put_in6_addr(&request, RTA_DST, dst);
> > +        nl_msg_put_in6_addr(&request, RTA_DST, &re->addr);
> >      }
> >
> >      if (VLOG_IS_DBG_ENABLED()) {
> > @@ -140,13 +140,13 @@ modify_route(uint32_t type, uint32_t flags_arg,
> uint32_t table_id,
> >          }
> >
> >          ds_put_format(&msg, "table %"PRIu32 " for prefix ", table_id);
> > -        if (IN6_IS_ADDR_V4MAPPED(dst)) {
> > +        if (IN6_IS_ADDR_V4MAPPED(&re->addr)) {
>
> We're changing this line anyway, I guess we could also just do:
>
> if (is_ipv4) {
>
> >              ds_put_format(&msg, IP_FMT,
> > -                          IP_ARGS(in6_addr_get_mapped_ipv4(dst)));
> > +                          IP_ARGS(in6_addr_get_mapped_ipv4(&re->addr)));
> >          } else {
> > -            ipv6_format_addr(dst, &msg);
> > +            ipv6_format_addr(&re->addr, &msg);
> >          }
> > -        ds_put_format(&msg, "/%u", plen);
> > +        ds_put_format(&msg, "/%u", re->plen);
> >
> >          VLOG_DBG("%s", ds_cstr(&msg));
> >          ds_destroy(&msg);
> > @@ -159,8 +159,7 @@ modify_route(uint32_t type, uint32_t flags_arg,
> uint32_t table_id,
> >  }
> >
> >  int
> > -re_nl_add_route(uint32_t table_id, const struct in6_addr *dst,
> > -                unsigned int plen, unsigned int priority)
> > +re_nl_add_route(uint32_t table_id, const struct advertise_route_entry
> *re)
> >  {
> >      if (!TABLE_ID_VALID(table_id)) {
> >          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
> > @@ -170,13 +169,11 @@ re_nl_add_route(uint32_t table_id, const struct
> in6_addr *dst,
> >          return EINVAL;
> >      }
> >
> > -    return modify_route(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
> table_id,
> > -                        dst, plen, priority);
> > +    return modify_route(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
> table_id, re);
> >  }
> >
> >  int
> > -re_nl_delete_route(uint32_t table_id, const struct in6_addr *dst,
> > -                   unsigned int plen, unsigned int priority)
> > +re_nl_delete_route(uint32_t table_id, const struct
> advertise_route_entry *re)
> >  {
> >      if (!TABLE_ID_VALID(table_id)) {
> >          static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
> > @@ -186,7 +183,7 @@ re_nl_delete_route(uint32_t table_id, const struct
> in6_addr *dst,
> >          return EINVAL;
> >      }
> >
> > -    return modify_route(RTM_DELROUTE, 0, table_id, dst, plen, priority);
> > +    return modify_route(RTM_DELROUTE, 0, table_id, re);
> >  }
> >
> >  struct route_msg_handle_data {
> > @@ -248,12 +245,14 @@ handle_route_msg(const struct route_table_msg
> *msg, void *data)
> >          return;
> >      }
> >
> > +    const struct advertise_route_entry re =
> > +            advertise_route_from_route_data(rd);
> >      if (handle_data->routes_to_advertise) {
> > -        uint32_t hash = advertise_route_hash(&rd->rta_dst,
> rd->rtm_dst_len);
> > +        uint32_t hash = advertise_route_hash(&re.addr, re.plen);
> >          HMAP_FOR_EACH_WITH_HASH (ar, node, hash, handle_data->routes) {
> > -            if (ipv6_addr_equals(&ar->addr, &rd->rta_dst)
> > -                    && ar->plen == rd->rtm_dst_len
> > -                    && ar->priority == rd->rta_priority) {
> > +            if (ipv6_addr_equals(&ar->addr, &re.addr)
> > +                    && ar->plen == re.plen
> > +                    && ar->priority == re.priority) {
> >                  hmapx_find_and_delete(handle_data->routes_to_advertise,
> ar);
> >                  return;
> >              }
> > @@ -261,27 +260,26 @@ handle_route_msg(const struct route_table_msg
> *msg, void *data)
> >      }
> >
> >      if (handle_data->stale_routes) {
> > -        vector_push(handle_data->stale_routes, rd);
> > +        vector_push(handle_data->stale_routes, &re);
> >      }
> >  }
> >
> >  static int
> > -re_nl_delete_stale_routes(const struct vector *stale_routes)
> > +re_nl_delete_stale_routes(uint32_t table_id, const struct vector
> *stale_routes)
> >  {
> >      int ret = 0;
> >
> > -    const struct route_data *rd;
> > -    VECTOR_FOR_EACH_PTR (stale_routes, rd) {
> > -        int err = re_nl_delete_route(rd->rta_table_id, &rd->rta_dst,
> > -                                     rd->rtm_dst_len, rd->rta_priority);
> > +    const struct advertise_route_entry *re;
> > +    VECTOR_FOR_EACH_PTR (stale_routes, re) {
> > +        int err = re_nl_delete_route(table_id, re);
> >          if (err) {
> >              char addr_s[INET6_ADDRSTRLEN + 1];
> >              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,
> 20);
> >              VLOG_WARN_RL(&rl, "Delete route table_id=%"PRIu32" dst=%s
> plen=%d "
> > -                         "failed: %s", rd->rta_table_id,
> > +                         "failed: %s", table_id,
> >                           ipv6_string_mapped(
> > -                             addr_s, &rd->rta_dst) ? addr_s :
> "(invalid)",
> > -                         rd->rtm_dst_len,
> > +                             addr_s, &re->addr) ? addr_s : "(invalid)",
> > +                         re->plen,
> >                           ovs_strerror(err));
> >              if (!ret) {
> >                  ret = err;
> > @@ -298,7 +296,8 @@ re_nl_sync_routes(uint32_t table_id, const struct
> hmap *routes,
> >                    const struct sbrec_datapath_binding *db)
> >  {
> >      struct hmapx routes_to_advertise =
> HMAPX_INITIALIZER(&routes_to_advertise);
> > -    struct vector stale_routes = VECTOR_EMPTY_INITIALIZER(struct
> route_data);
> > +    struct vector stale_routes =
> > +        VECTOR_EMPTY_INITIALIZER(struct advertise_route_entry);
> >      struct advertise_route_entry *ar;
> >
> >      HMAP_FOR_EACH (ar, node, routes) {
> > @@ -318,14 +317,14 @@ re_nl_sync_routes(uint32_t table_id, const struct
> hmap *routes,
> >      };
> >      route_table_dump_one_table(table_id, handle_route_msg, &data);
> >
> > -    int ret = re_nl_delete_stale_routes(&stale_routes);
> > +    int ret = re_nl_delete_stale_routes(table_id, &stale_routes);
> >
> >      /* Add any remaining routes in the routes_to_advertise hmapx to the
> >       * system routing table. */
> >      struct hmapx_node *hn;
> >      HMAPX_FOR_EACH (hn, &routes_to_advertise) {
> >          ar = hn->data;
> > -        int err = re_nl_add_route(table_id, &ar->addr, ar->plen,
> ar->priority);
> > +        int err = re_nl_add_route(table_id, ar);
> >          if (err) {
> >              char addr_s[INET6_ADDRSTRLEN + 1];
> >              static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5,
> 20);
> > @@ -352,7 +351,8 @@ re_nl_sync_routes(uint32_t table_id, const struct
> hmap *routes,
> >  int
> >  re_nl_cleanup_routes(uint32_t table_id)
> >  {
> > -    struct vector stale_routes = VECTOR_EMPTY_INITIALIZER(struct
> route_data);
> > +    struct vector stale_routes =
> > +        VECTOR_EMPTY_INITIALIZER(struct advertise_route_entry);
> >      /* Remove routes from the system that are not in the host_routes
> hmap and
> >       * remove entries from host_routes hmap that match routes already
> installed
> >       * in the system. */
> > @@ -364,7 +364,7 @@ re_nl_cleanup_routes(uint32_t table_id)
> >      };
> >      route_table_dump_one_table(table_id, handle_route_msg, &data);
> >
> > -    int ret = re_nl_delete_stale_routes(&stale_routes);
> > +    int ret = re_nl_delete_stale_routes(table_id, &stale_routes);
> >      vector_destroy(&stale_routes);
> >
> >      return ret;
> > diff --git a/controller/route-exchange-netlink.h
> b/controller/route-exchange-netlink.h
> > index 1741f761d..ad1f0783b 100644
> > --- a/controller/route-exchange-netlink.h
> > +++ b/controller/route-exchange-netlink.h
> > @@ -52,10 +52,9 @@ struct re_nl_received_route_node {
> >  int re_nl_create_vrf(const char *ifname, uint32_t table_id);
> >  int re_nl_delete_vrf(const char *ifname);
> >
> > -int re_nl_add_route(uint32_t table_id, const struct in6_addr *dst,
> > -                    unsigned int plen, unsigned int priority);
> > -int re_nl_delete_route(uint32_t table_id, const struct in6_addr *dst,
> > -                       unsigned int plen, unsigned int priority);
> > +int re_nl_add_route(uint32_t table_id, const struct
> advertise_route_entry *);
> > +int re_nl_delete_route(uint32_t table_id,
> > +                       const struct advertise_route_entry *);
> >
> >  int re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
> >                        struct vector *learned_routes,
> > diff --git a/controller/route.c b/controller/route.c
> > index 093306c5b..dcf1984ab 100644
> > --- a/controller/route.c
> > +++ b/controller/route.c
> > @@ -31,6 +31,8 @@
> >  #include "local_data.h"
> >  #include "route.h"
> >
> > +#include "route-table.h"
> > +
> >  VLOG_DEFINE_THIS_MODULE(exchange);
> >
> >  #define PRIORITY_DEFAULT 1000
> > @@ -49,6 +51,16 @@ advertise_route_hash(const struct in6_addr *dst,
> unsigned int plen)
> >      return hash_int(plen, hash);
> >  }
> >
> > +struct advertise_route_entry
> > +advertise_route_from_route_data(const struct route_data *rd)
> > +{
> > +    return (struct advertise_route_entry) {
> > +        .addr = rd->rta_dst,
> > +        .plen = rd->rtm_dst_len,
> > +        .priority = rd->rta_priority,
> > +    };
> > +}
> > +
> >  const struct sbrec_port_binding*
> >  route_exchange_find_port(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> >                           const struct sbrec_chassis *chassis,
> > diff --git a/controller/route.h b/controller/route.h
> > index 5c800f4ab..a1dd61d53 100644
> > --- a/controller/route.h
> > +++ b/controller/route.h
> > @@ -27,6 +27,7 @@
> >
> >  struct hmap;
> >  struct ovsdb_idl_index;
> > +struct route_data;
> >  struct sbrec_chassis;
> >  struct sbrec_port_binding;
> >  struct sbrec_datapath_binding;
> > @@ -89,6 +90,8 @@ const struct sbrec_port_binding
> *route_exchange_find_port(
> >      const struct sbrec_port_binding *pb,
> >      const char **dynamic_routing_port_name);
> >  uint32_t advertise_route_hash(const struct in6_addr *dst, unsigned int
> plen);
> > +struct advertise_route_entry
> > +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 *);
>
> Looks good to me, thanks!
>
> Acked-by: Dumitru Ceara <[email protected]>
>
> Regards,
> Dumitru
>
>
>
Thank you Dumitru,

I went ahead, addressed the comment, merged this into main and backported
down to 25.09.

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

Reply via email to