On 2/25/25 3:28 PM, martin.kal...@canonical.com wrote:
> On Tue, 2025-02-25 at 00:01 +0100, Dumitru Ceara wrote:
>> Change the en_dynamic_routes I-P node to compute a map of 'advertised
>> routes' (struct ar_entry) instead of parsed routes.  Like that we can
>> avoid having to re-parse NAT/LB IPs when advertising them.
>>
>> Fixes: cd4ad2f56179 ("northd: Redistribution of NAT/LB routes.")
>> Signed-off-by: Dumitru Ceara <dce...@redhat.com>
> 
> Hi Dumitru,

Hi Martin,

> Overall, this looks good to me. I have some nits/suggestions that I'll
> leave up to you to consider. Otherwise consider this acked by me.
> 

Thanks for the review!

> Now that the dynamic routes don't use "struct parsed_route", we can
> probably remove the TODO item that calls for splitting parsed_routes
> [0].
> 

Ah, I forgot about that, thanks for pointing it out!  I'll remove it in v2.

>> ---
>>  northd/en-advertised-route-sync.c | 376 +++++++++++++++++-----------
>> --
>>  northd/northd.h                   |   3 +-
>>  2 files changed, 210 insertions(+), 169 deletions(-)
>>
>> diff --git a/northd/en-advertised-route-sync.c b/northd/en-
>> advertised-route-sync.c
>> index 486bcc2fd2..ebaed08b69 100644
>> --- a/northd/en-advertised-route-sync.c
>> +++ b/northd/en-advertised-route-sync.c
>> @@ -27,6 +27,102 @@
>>  #include "openvswitch/hmap.h"
>>  #include "ovn-util.h"
>>  
>> +struct ar_entry {
>> +    struct hmap_node hmap_node;
>> +
>> +    const struct ovn_datapath *od;       /* Datapath the route is
>> +                                          * advertised on. */
>> +    const struct ovn_port *op;           /* Port the route is
>> advertised
>> +                                          * on. */
>> +    char *ip_prefix;
>> +    const struct ovn_port *tracked_port; /* If set, the port whose
>> chassis
>> +                                          * advertises this route
>> with a
>> +                                          * higher priority. */
>> +    enum route_source source;
>> +};
>> +
>> +/* Add a new entries to the to-be-advertised routes.
>> + * Takes ownership of ip_prefix. */
>> +static struct ar_entry *
>> +ar_entry_add_nocopy(struct hmap *routes, const struct ovn_datapath
>> *od,
>> +                    const struct ovn_port *op, char *ip_prefix,
>> +                    const struct ovn_port *tracked_port,
>> +                    enum route_source source)
>> +{
> 
> With the "copy version" of this function being more popular, and the
> "no_copy" used only once. Would it make sense to keep only the
> "ar_entry_add" function that always copies the ip_prefix, and in the
> one case where we want "no_copy" just freeing the ip_prefix after
> calling regular "ar_entry_add"?
> 

We could but it seems straight forward enough to avoid that copy.  I'll
keep it as is if you don't mind.

> 
>> +    struct ar_entry *route_e = xzalloc(sizeof *route_e);
>> +
>> +    route_e->od = od;
>> +    route_e->op = op;
>> +    route_e->ip_prefix = ip_prefix;
>> +    route_e->tracked_port = tracked_port;
>> +    route_e->source = source;
>> +    uint32_t hash = uuid_hash(&od->sb->header_.uuid);
>> +    hash = hash_string(op->sb->logical_port, hash);
>> +    hash = hash_string(ip_prefix, hash);
>> +    hmap_insert(routes, &route_e->hmap_node, hash);
>> +
>> +    return route_e;
>> +}
>> +
>> +/* Add a new entries to the to-be-advertised routes.
>> + * Makes a copy of ip_prefix. */
>> +static struct ar_entry *
>> +ar_entry_add(struct hmap *routes, const struct ovn_datapath *od,
>> +             const struct ovn_port *op, const char *ip_prefix,
>> +             const struct ovn_port *tracked_port,
>> +             enum route_source source)
>> +{
>> +    return ar_entry_add_nocopy(routes, od, op, xstrdup(ip_prefix),
>> +                               tracked_port, source);
>> +}
>> +
>> +static struct ar_entry *
>> +ar_entry_find(struct hmap *route_map,
>> +              const struct sbrec_datapath_binding *sb_db,
>> +              const struct sbrec_port_binding *logical_port,
>> +              const char *ip_prefix,
>> +              const struct sbrec_port_binding *tracked_port)
>> +{
>> +    struct ar_entry *route_e;
>> +    uint32_t hash;
>> +
>> +    hash = uuid_hash(&sb_db->header_.uuid);
>> +    hash = hash_string(logical_port->logical_port, hash);
>> +    hash = hash_string(ip_prefix, hash);
>> +
>> +    HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
>> +        if (!uuid_equals(&sb_db->header_.uuid,
>> +                         &route_e->od->sb->header_.uuid)) {
>> +            continue;
>> +        }
>> +        if (!uuid_equals(&logical_port->header_.uuid,
>> +                         &route_e->op->sb->header_.uuid)) {
>> +            continue;
>> +        }
>> +        if (strcmp(ip_prefix, route_e->ip_prefix)) {
>> +            continue;
>> +        }
>> +
>> +        if (tracked_port) {
>> +            if (!route_e->tracked_port ||
>> +                    tracked_port != route_e->tracked_port->sb) {
>> +                continue;
>> +            }
>> +        }
>> +
>> +        return route_e;
>> +    }
>> +
>> +    return NULL;
>> +}
>> +
>> +static void
>> +ar_entry_free(struct ar_entry *route_e)
>> +{
>> +    free(route_e->ip_prefix);
>> +    free(route_e);
>> +}
>> +
>>  static void
>>  advertised_route_table_sync(
>>      struct ovsdb_idl_txn *ovnsb_txn,
>> @@ -158,7 +254,7 @@ en_advertised_route_sync_run(struct engine_node
>> *node, void *data OVS_UNUSED)
>>                                  sbrec_advertised_route_table,
>>                                  &lr_stateful_data->table,
>>                                  &routes_data->parsed_routes,
>> -                                &dynamic_routes_data->parsed_routes,
>> +                                &dynamic_routes_data->routes,
>>                                  routes_sync_data);
>>  
>>      stopwatch_stop(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME,
>> time_msec());
>> @@ -184,18 +280,18 @@ build_nat_parsed_route_for_port(const struct
>> ovn_port *advertising_op,
>>              continue;
>>          }
>>  
>> -        int plen = nat_entry_is_v6(nat) ? 128 : 32;
>> -        struct in6_addr prefix;
>> -        ip46_parse(nat->nb->external_ip, &prefix);
>> -
>>          const struct ovn_port *tracked_port =
>>              nat->is_distributed
>>              ? ovn_port_find(ls_ports, nat->nb->logical_port)
>>              : nat->l3dgw_port;
>> -        parsed_route_add(advertising_od, NULL, &prefix, plen, false,
>> -                         nat->nb->external_ip, advertising_op, 0,
>> false,
>> -                         false, NULL, ROUTE_SOURCE_NAT, &nat->nb-
>>> header_,
>> -                         tracked_port, routes);
>> +
>> +        if (!ar_entry_find(routes, advertising_od->sb,
>> advertising_op->sb,
>> +                           nat->nb->external_ip,
>> +                           tracked_port ? tracked_port->sb : NULL))
>> {
> 
> Is the if clause necessary here? With "routes" being hashmap of
> ar_routes that uses "advertising_od", "advertising_op" and
> "external_ip" as a key, isn't that enough to prevent duplicates?
> 

But ar_entry_add() doesn't check if the entry already exists, it will
insert a duplicate if we have multiple NAT entries with the same
external_ip.  And AFAICT external_ip is not a index column in the NB.NAT
schema so duplicates can happen.

So I think we need to keep the lookup.

Also, I just realized all these functions are still called
build_nat/lb_parsed_route_for_port().  I'll change that in v2 too.

>> +            ar_entry_add(routes, advertising_od, advertising_op,
>> +                         nat->nb->external_ip, tracked_port,
>> +                         ROUTE_SOURCE_NAT);
>> +        }
>>      }
>>  }
>>  
>> @@ -294,20 +390,12 @@ build_lb_parsed_route_for_port(const struct
>> ovn_port *advertising_op,
>>  
>>      const char *ip_address;
>>      SSET_FOR_EACH (ip_address, &lb_ips->ips_v4) {
>> -        struct in6_addr prefix;
>> -        ip46_parse(ip_address, &prefix);
>> -        parsed_route_add(advertising_od, NULL, &prefix, 32, false,
>> -                         ip_address, advertising_op, 0, false,
>> false,
>> -                         NULL, ROUTE_SOURCE_LB, &advertising_op-
>>> nbrp->header_,
>> -                         tracked_port, routes);
>> +        ar_entry_add(routes, advertising_od, advertising_op,
>> +                     ip_address, tracked_port, ROUTE_SOURCE_LB);
>>      }
>>      SSET_FOR_EACH (ip_address, &lb_ips->ips_v6) {
>> -        struct in6_addr prefix;
>> -        ip46_parse(ip_address, &prefix);
>> -        parsed_route_add(advertising_od, NULL, &prefix, 128, false,
>> -                         ip_address, advertising_op, 0, false,
>> false,
>> -                         NULL, ROUTE_SOURCE_LB, &advertising_op-
>>> nbrp->header_,
>> -                         tracked_port, routes);
>> +        ar_entry_add(routes, advertising_od, advertising_op,
>> +                     ip_address, tracked_port, ROUTE_SOURCE_LB);
>>      }
>>  }
>>  
>> @@ -402,7 +490,7 @@ en_dynamic_routes_init(struct engine_node *node
>> OVS_UNUSED,
>>  {
>>      struct dynamic_routes_data *data = xmalloc(sizeof *data);
>>      *data = (struct dynamic_routes_data) {
>> -        .parsed_routes = HMAP_INITIALIZER(&data->parsed_routes),
>> +        .routes = HMAP_INITIALIZER(&data->routes),
>>      };
>>  
>>      return data;
>> @@ -411,9 +499,9 @@ en_dynamic_routes_init(struct engine_node *node
>> OVS_UNUSED,
>>  static void
>>  en_dynamic_routes_clear(struct dynamic_routes_data *data)
>>  {
>> -    struct parsed_route *r;
>> -    HMAP_FOR_EACH_POP (r, key_node, &data->parsed_routes) {
>> -        parsed_route_free(r);
>> +    struct ar_entry *ar;
>> +    HMAP_FOR_EACH_POP (ar, hmap_node, &data->routes) {
>> +        ar_entry_free(ar);
>>      }
>>  }
>>  void
>> @@ -422,7 +510,7 @@ en_dynamic_routes_cleanup(void *data_)
>>      struct dynamic_routes_data *data = data_;
>>  
>>      en_dynamic_routes_clear(data);
>> -    hmap_destroy(&data->parsed_routes);
>> +    hmap_destroy(&data->routes);
>>  }
>>  
>>  void
>> @@ -447,100 +535,20 @@ en_dynamic_routes_run(struct engine_node
>> *node, void *data)
>>          }
>>          build_nat_parsed_routes(od, lr_stateful_rec->lrnat_rec,
>>                                  &northd_data->ls_ports,
>> -                                &dynamic_routes_data-
>>> parsed_routes);
>> +                                &dynamic_routes_data->routes);
>>          build_nat_connected_parsed_routes(od, &lr_stateful_data-
>>> table,
>>                                            &northd_data->ls_ports,
>> -                                          &dynamic_routes_data-
>>> parsed_routes);
>> +                                          &dynamic_routes_data-
>>> routes);
>>  
>>          build_lb_parsed_routes(od, lr_stateful_rec->lb_ips,
>> -                               &dynamic_routes_data->parsed_routes);
>> +                               &dynamic_routes_data->routes);
>>          build_lb_connected_parsed_routes(od, &lr_stateful_data-
>>> table,
>> -                                         &dynamic_routes_data-
>>> parsed_routes);
>> +                                         &dynamic_routes_data-
>>> routes);
>>      }
>>      stopwatch_stop(DYNAMIC_ROUTES_RUN_STOPWATCH_NAME, time_msec());
>>      engine_set_node_state(node, EN_UPDATED);
>>  }
>>  
>> -struct ar_entry {
>> -    struct hmap_node hmap_node;
>> -
>> -    const struct ovn_datapath *od;       /* Datapath the route is
>> -                                          * advertised on. */
>> -    const struct ovn_port *op;           /* Port the route is
>> advertised
>> -                                          * on. */
>> -    char *ip_prefix;
>> -    const struct ovn_port *tracked_port; /* If set, the port whose
>> chassis
>> -                                          * advertises this route
>> with a
>> -                                          * higher priority. */
>> -};
>> -
>> -/* Add a new entries to the to-be-advertised routes.
>> - * Takes ownership of ip_prefix. */
>> -static struct ar_entry *
>> -ar_entry_add(struct hmap *routes, const struct ovn_datapath *od,
>> -             const struct ovn_port *op, char *ip_prefix,
>> -             const struct ovn_port *tracked_port)
>> -{
>> -    struct ar_entry *route_e = xzalloc(sizeof *route_e);
>> -
>> -    route_e->od = od;
>> -    route_e->op = op;
>> -    route_e->ip_prefix = ip_prefix;
>> -    route_e->tracked_port = tracked_port;
>> -    uint32_t hash = uuid_hash(&od->sb->header_.uuid);
>> -    hash = hash_string(op->sb->logical_port, hash);
>> -    hash = hash_string(ip_prefix, hash);
>> -    hmap_insert(routes, &route_e->hmap_node, hash);
>> -
>> -    return route_e;
>> -}
>> -
>> -static struct ar_entry *
>> -ar_entry_find(struct hmap *route_map,
>> -              const struct sbrec_datapath_binding *sb_db,
>> -              const struct sbrec_port_binding *logical_port,
>> -              const char *ip_prefix,
>> -              const struct sbrec_port_binding *tracked_port)
>> -{
>> -    struct ar_entry *route_e;
>> -    uint32_t hash;
>> -
>> -    hash = uuid_hash(&sb_db->header_.uuid);
>> -    hash = hash_string(logical_port->logical_port, hash);
>> -    hash = hash_string(ip_prefix, hash);
>> -
>> -    HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
>> -        if (!uuid_equals(&sb_db->header_.uuid,
>> -                         &route_e->od->sb->header_.uuid)) {
>> -            continue;
>> -        }
>> -        if (!uuid_equals(&logical_port->header_.uuid,
>> -                         &route_e->op->sb->header_.uuid)) {
>> -            continue;
>> -        }
>> -        if (strcmp(ip_prefix, route_e->ip_prefix)) {
>> -            continue;
>> -        }
>> -
>> -        if (tracked_port) {
>> -            if (!route_e->tracked_port ||
>> -                    tracked_port != route_e->tracked_port->sb) {
>> -                continue;
>> -            }
>> -        }
>> -        return route_e;
>> -    }
>> -
>> -    return NULL;
>> -}
>> -
>> -static void
>> -ar_entry_free(struct ar_entry *route_e)
>> -{
>> -    free(route_e->ip_prefix);
>> -    free(route_e);
>> -}
>> -
>>  static void
>>  publish_lport_addresses(struct hmap *sync_routes,
>>                          const struct ovn_datapath *od,
>> @@ -550,16 +558,16 @@ publish_lport_addresses(struct hmap
>> *sync_routes,
>>  {
>>      for (size_t i = 0; i < addresses->n_ipv4_addrs; i++) {
>>          const struct ipv4_netaddr *addr = &addresses->ipv4_addrs[i];
>> -        ar_entry_add(sync_routes, od, logical_port, xstrdup(addr-
>>> addr_s),
>> -                     tracking_port);
>> +        ar_entry_add(sync_routes, od, logical_port, addr->addr_s,
>> +                     tracking_port, ROUTE_SOURCE_CONNECTED);
>>      }
>>      for (size_t i = 0; i < addresses->n_ipv6_addrs; i++) {
>>          if (in6_is_lla(&addresses->ipv6_addrs[i].network)) {
>>              continue;
>>          }
>>          const struct ipv6_netaddr *addr = &addresses->ipv6_addrs[i];
>> -        ar_entry_add(sync_routes, od, logical_port, xstrdup(addr-
>>> addr_s),
>> -                      tracking_port);
>> +        ar_entry_add(sync_routes, od, logical_port, addr->addr_s,
>> +                     tracking_port, ROUTE_SOURCE_CONNECTED);
>>      }
>>  }
>>  
>> @@ -640,78 +648,85 @@ publish_host_routes(struct hmap *sync_routes,
>>      }
>>  }
>>  
>> -static void
>> -advertised_route_table_sync_route_add(
>> -    const struct lr_stateful_table *lr_stateful_table,
>> -    struct advertised_route_sync_data *data,
>> -    struct uuidset *host_route_lrps,
>> -    struct hmap *sync_routes,
>> -    const struct parsed_route *route)
>> +static bool
>> +should_advertise_route(const struct lr_stateful_table
>> *lr_stateful_table,
>> +                       struct advertised_route_sync_data *data,
>> +                       struct uuidset *host_route_lrps,
>> +                       struct hmap *sync_routes,
>> +                       const struct ovn_datapath *advertising_od,
>> +                       const struct ovn_port *advertising_op,
>> +                       const struct ovn_port *tracked_op,
>> +                       enum route_source source)
>>  {
>> -    if (route->is_discard_route) {
>> -        return;
>> -    }
>> -    if (prefix_is_link_local(&route->prefix, route->plen)) {
>> -        return;
>> -    }
>> -    if (!route->od->dynamic_routing) {
>> -        return;
>> +    if (!advertising_od->dynamic_routing) {
>> +        return false;
>>      }
>>  
>>      enum dynamic_routing_redistribute_mode drr =
>> -        route->out_port->dynamic_routing_redistribute;
>> -    if (route->source == ROUTE_SOURCE_CONNECTED) {
>> +        advertising_op->dynamic_routing_redistribute;
>> +
>> +    switch (source) {
>> +    case ROUTE_SOURCE_CONNECTED:
>>          if (!drr_mode_CONNECTED_is_set(drr)) {
>> -            return;
>> +            return false;
>>          }
>> +
>>          /* If we advertise host routes, we only need to do so once
>> per
>>           * LRP. */
>> -        const struct uuid *lrp_uuid = &route->out_port->nbrp-
>>> header_.uuid;
>> -        if (drr_mode_CONNECTED_AS_HOST_is_set(drr) &&
>> -            !uuidset_contains(host_route_lrps, lrp_uuid)) {
>> +        const struct uuid *lrp_uuid = &advertising_op->nbrp-
>>> header_.uuid;
>> +        if (drr_mode_CONNECTED_AS_HOST_is_set(drr)) {
>> +            if (uuidset_contains(host_route_lrps, lrp_uuid)) {
>> +                return false;
>> +            }
>>              uuidset_insert(host_route_lrps, lrp_uuid);
>>              publish_host_routes(sync_routes, lr_stateful_table,
>> -                                route->od, route->out_port,
>> +                                advertising_od, advertising_op,
>>                                  data);
>> -            return;
>> +            return false;
>>          }
>> -    }
>> -    if (route->source == ROUTE_SOURCE_STATIC &&
>> !drr_mode_STATIC_is_set(drr)) {
>> -        return;
>> -    }
>> -    if (route->source == ROUTE_SOURCE_NAT) {
>> +        return true;
>> +
>> +    case ROUTE_SOURCE_STATIC:
>> +        return drr_mode_STATIC_is_set(drr);
>> +
>> +    case ROUTE_SOURCE_NAT:
>>          if (!drr_mode_NAT_is_set(drr)) {
>> -            return;
>> +            return false;
>>          }
>> +
>>          /* If NAT route tracks port on a different DP than the one
>> that
>>           * advertises the route, we need to watch for changes on
>> that DP as
>>           * well. */
>> -        if (route->tracked_port && route->tracked_port->od != route-
>>> od) {
>> -            if (route->tracked_port->od->nbr) {
>> +        if (tracked_op && tracked_op->od != advertising_od) {
>> +            if (tracked_op->od->nbr) {
>>                  uuidset_insert(&data->nb_lr,
>> -                               &route->tracked_port->od->nbr-
>>> header_.uuid);
>> -            } else if (route->tracked_port->od->nbs) {
>> +                               &tracked_op->od->nbr->header_.uuid);
>> +            } else if (tracked_op->od->nbs) {
>>                  uuidset_insert(&data->nb_ls,
>> -                               &route->tracked_port->od->nbs-
>>> header_.uuid);
>> +                               &tracked_op->od->nbs->header_.uuid);
>>              }
>>          }
>> -    }
>> -    if (route->source == ROUTE_SOURCE_LB) {
>> +        return true;
>> +
>> +    case ROUTE_SOURCE_LB:
>>          if (!drr_mode_LB_is_set(drr)) {
>> -            return;
>> +            return false;
>>          }
>> +
>>          /* If LB route tracks port on a different DP than the one
>> that
>>           * advertises the route, we need to watch for changes on
>> that DP as
>>           * well. */
>> -        if (route->tracked_port && route->tracked_port->od != route-
>>> od) {
>> +        if (tracked_op && tracked_op->od != advertising_od) {
>>              uuidset_insert(&data->nb_lr,
>> -                           &route->tracked_port->od->nbr-
>>> header_.uuid);
>> +                           &tracked_op->od->nbr->header_.uuid);
>>          }
>> +        return true;
>> +
>> +    case ROUTE_SOURCE_LEARNED:
>> +        return true;
>>      }
>>  
>> -    char *ip_prefix = normalize_v46_prefix(&route->prefix, route-
>>> plen);
>> -    ar_entry_add(sync_routes, route->od, route->out_port, ip_prefix,
>> -                 route->tracked_port);
>> +    OVS_NOT_REACHED();
>>  }
>>  
>>  static void
>> @@ -725,23 +740,48 @@ advertised_route_table_sync(
>>  {
>>      struct hmap sync_routes = HMAP_INITIALIZER(&sync_routes);
>>      struct uuidset host_route_lrps =
>> UUIDSET_INITIALIZER(&host_route_lrps);
>> -    const struct parsed_route *route;
>> -
>> -    struct ar_entry *route_e;
>>  
>>      /* First build the set of non-dynamic routes that need sync-ing.
>> */
>> +    const struct parsed_route *route;
>>      HMAP_FOR_EACH (route, key_node, routes) {
>> -        advertised_route_table_sync_route_add(lr_stateful_table,
>> -                                              data,
>> &host_route_lrps,
>> -                                              &sync_routes,
>> -                                              route);
>> +        if (route->is_discard_route) {
>> +            continue;
>> +        }
>> +
>> +        if (prefix_is_link_local(&route->prefix, route->plen)) {
>> +            continue;
>> +        }
>> +
>> +        if (!should_advertise_route(lr_stateful_table,
>> +                                    data, &host_route_lrps,
>> +                                    &sync_routes,
>> +                                    route->od, route->out_port,
>> +                                    route->tracked_port,
>> +                                    route->source)) {
>> +            continue;
>> +        }
>> +
>> +        ar_entry_add_nocopy(&sync_routes, route->od, route-
>>> out_port,
>> +                            normalize_v46_prefix(&route->prefix,
>> route->plen),
>> +                            route->tracked_port,
>> +                            route->source);
>>      }
>> +
>>      /* Then add the set of dynamic routes that need sync-ing. */
>> -    HMAP_FOR_EACH (route, key_node, dynamic_routes) {
>> -        advertised_route_table_sync_route_add(lr_stateful_table,
>> -                                              data,
>> &host_route_lrps,
>> -                                              &sync_routes,
>> -                                              route);
>> +    struct ar_entry *route_e;
>> +    HMAP_FOR_EACH (route_e, hmap_node, dynamic_routes) {
>> +        if (!should_advertise_route(lr_stateful_table,
>> +                                    data, &host_route_lrps,
>> +                                    &sync_routes,
>> +                                    route_e->od, route_e->op,
>> +                                    route_e->tracked_port,
>> +                                    route_e->source)) {
>> +            continue;
>> +        }
>> +
>> +        ar_entry_add(&sync_routes, route_e->od, route_e->op,
>> +                     route_e->ip_prefix, route_e->tracked_port,
>> +                     route_e->source);
> 
> With "dynamic_routes" and "sync_routes" both being hmaps of ar_entry
> structs, would it make sense to pop the "ar_entry" item from
> dynamic_routes and directly insert it into the "sync_routes"? Instead
> of sending individual route_e values through the ar_entry_add, to
> basically create a copy of "route_e".
> 

Unfortunately that would break the constraints the I-P engine enforces
on us.  A node should not change any data of other nodes that are its
inputs.  In this case, imagine we ever need to add another I-P engine
node that depends on "en_dynamic_routes".  If "en_advertise_routes"
changes the dynamic_routes map then the behavior of the incremental
processing graph is undefined, because the input data for the
"en_advertise_routes" and the new node looks different while it's
actually coming from the same input node.

> Thanks a lot,
> Martin.

Regards,
Dumitru

> 
> [0]https://github.com/ovn-org/ovn/blob/fe26d5b53f5c1f939c8e03e0677e5268a1f7432d/TODO.rst?plain=1#L163-L168
> 

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to