On Tue, Jan 14, 2025 at 01:37:08PM +0100, Dumitru Ceara wrote:
> Hi Felix,
> 
> Thanks for the patch!

Hi Dumitru,

thanks for the review.
All smaller stuff will be part of v3, for the rest, see below.

I will not finish reworking this patchset today, but i plan to send out
v3 sometime tomorrow.

> 
> On 12/18/24 11:25 AM, Felix Huettner via dev wrote:
> > sometimes we want to use individual host routes instead of the connected
> 
> Nit: Sometimes
> 
> > routes of LRPs.
> > This allows the network fabric to know which adresses are actually in
> 
> Typo: adresses
> 
> > use and e.g. drop traffic to adresses that are not used anyway.
> 
> Here too.
> 
> > 
> > Signed-off-by: Felix Huettner <[email protected]>
> > ---
> >  NEWS                              |   2 +
> >  northd/en-advertised-route-sync.c | 270 +++++++++++++++++++++++++++---
> >  northd/en-advertised-route-sync.h |  16 ++
> >  northd/inc-proc-northd.c          |   4 +
> >  northd/northd.c                   |  32 ++--
> >  northd/northd.h                   |  25 ++-
> >  ovn-nb.xml                        |  27 +++
> >  tests/ovn-northd.at               |  71 ++++++++
> >  8 files changed, 402 insertions(+), 45 deletions(-)
> > 
> > diff --git a/NEWS b/NEWS
> > index c64453007..f526013f1 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -22,6 +22,8 @@ Post v24.09.0
> >       Routes entered into the "Route" table in the southbound database will 
> > be
> >       learned by the respective LR. They are included in the route table 
> > with
> >       a lower priority than static routes.
> > +   - Add the option "dynamic-routing-connected-as-host-routes" to LRPs. If 
> > set
> > +     to true then connected routes are announced as individual host routes.
> 
> This is becoming a big list with dynamic routing related options.
> Should we add a dedicated "dynamic routing" section (see SSL/TLS above)
> in the first patch and expand it in each subsequent patch of the series?

Yep, sounds good.

> 
> >  
> >  OVN v24.09.0 - 13 Sep 2024
> >  --------------------------
> > diff --git a/northd/en-advertised-route-sync.c 
> > b/northd/en-advertised-route-sync.c
> > index 33097ed72..065c73861 100644
> > --- a/northd/en-advertised-route-sync.c
> > +++ b/northd/en-advertised-route-sync.c
> > @@ -13,6 +13,7 @@
> >   */
> >  
> >  #include <config.h>
> > +#include <stdbool.h>
> 
> Is this really needed?

No, seems like a leftover.

> 
> >  
> >  #include "openvswitch/vlog.h"
> >  #include "smap.h"
> > @@ -20,6 +21,7 @@
> >  #include "northd.h"
> >  
> >  #include "en-advertised-route-sync.h"
> > +#include "en-lr-stateful.h"
> >  #include "lib/stopwatch-names.h"
> >  #include "openvswitch/hmap.h"
> >  #include "ovn-util.h"
> > @@ -30,34 +32,129 @@ static void
> >  advertised_route_table_sync(
> >      struct ovsdb_idl_txn *ovnsb_txn,
> >      const struct sbrec_advertised_route_table 
> > *sbrec_advertised_route_table,
> > -    const struct hmap *parsed_routes);
> > +    const struct lr_stateful_table *lr_stateful_table,
> > +    const struct hmap *parsed_routes,
> > +    struct advertised_route_sync_tracked_data *trk_data);
> > +
> > +bool
> > +advertised_route_sync_lr_stateful_change_handler(struct engine_node *node,
> > +                                                 void *data_)
> > +{
> > +    /* We only actually use lr_stateful data if we expose individual host
> > +     * routes. In this case we for now just recompute.
> > +     * */
> > +    struct ed_type_lr_stateful *lr_stateful_data =
> > +        engine_get_input_data("lr_stateful", node);
> > +    struct advertised_route_sync_data *data = data_;
> > +
> > +    struct hmapx_node *hmapx_node;
> > +    const struct lr_stateful_record *lr_stateful_rec;
> > +    HMAPX_FOR_EACH (hmapx_node, &lr_stateful_data->trk_data.crupdated) {
> > +        lr_stateful_rec = hmapx_node->data;
> > +        if (uuidset_contains(&data->trk_data.nb_lr_stateful,
> > +                             &lr_stateful_rec->nbr_uuid)) {
> > +            return false;
> > +        }
> > +    }
> > +
> > +    return true;
> > +}
> > +
> > +bool
> > +advertised_route_sync_northd_change_handler(struct engine_node *node,
> > +                                            void *data_)
> > +{
> > +    struct advertised_route_sync_data *data = data_;
> > +    struct northd_data *northd_data = engine_get_input_data("northd", 
> > node);
> > +    if (!northd_has_tracked_data(&northd_data->trk_data)) {
> > +        return false;
> > +    }
> > +
> > +    /* This node uses the below data from the en_northd engine node.
> > +     * See (lr_stateful_get_input_data())
> > +     *   1. Indirectly  northd_data->ls_ports if we announce host routes
> > +     *      This is what we check below
> 
> This comment doesn't seem complete.
> 
> > +     */
> > +
> > +    struct hmapx_node *hmapx_node;
> > +    const struct ovn_port *op;
> > +    HMAPX_FOR_EACH (hmapx_node, &northd_data->trk_data.trk_lsps.created) {
> > +        op = hmapx_node->data;
> > +        if (uuidset_contains(&data->trk_data.nb_ls,
> > +                             &op->od->nbs->header_.uuid)) {
> > +            return false;
> > +        }
> > +    }
> > +    HMAPX_FOR_EACH (hmapx_node, &northd_data->trk_data.trk_lsps.updated) {
> > +        op = hmapx_node->data;
> > +        if (uuidset_contains(&data->trk_data.nb_ls,
> > +                             &op->od->nbs->header_.uuid)) {
> > +            return false;
> > +        }
> > +    }
> > +    HMAPX_FOR_EACH (hmapx_node, &northd_data->trk_data.trk_lsps.deleted) {
> > +        op = hmapx_node->data;
> > +        if (uuidset_contains(&data->trk_data.nb_ls,
> > +                             &op->od->nbs->header_.uuid)) {
> > +            return false;
> > +        }
> > +    }
> > +
> > +    return true;
> > +}
> > +
> > +static void
> > +routes_sync_init(struct advertised_route_sync_data *data)
> > +{
> > +    uuidset_init(&data->trk_data.nb_lr_stateful);
> > +    uuidset_init(&data->trk_data.nb_ls);
> > +}
> > +
> > +static void
> > +routes_sync_destroy(struct advertised_route_sync_data *data)
> > +{
> > +    uuidset_destroy(&data->trk_data.nb_lr_stateful);
> > +    uuidset_destroy(&data->trk_data.nb_ls);
> > +}
> > +
> >  
> >  void
> >  *en_advertised_route_sync_init(struct engine_node *node OVS_UNUSED,
> >                       struct engine_arg *arg OVS_UNUSED)
> >  {
> > -    return NULL;
> > +    struct advertised_route_sync_data *data = xzalloc(sizeof *data);
> > +    routes_sync_init(data);
> > +    return data;
> >  }
> >  
> >  void
> >  en_advertised_route_sync_cleanup(void *data OVS_UNUSED)
> >  {
> > +    routes_sync_destroy(data);
> >  }
> >  
> >  void
> >  en_advertised_route_sync_run(struct engine_node *node, void *data 
> > OVS_UNUSED)
> >  {
> > +    routes_sync_destroy(data);
> > +    routes_sync_init(data);
> > +
> > +    struct advertised_route_sync_data *routes_sync_data = data;
> >      struct routes_data *routes_data
> >          = engine_get_input_data("routes", node);
> >      const struct engine_context *eng_ctx = engine_get_context();
> >      const struct sbrec_advertised_route_table 
> > *sbrec_advertised_route_table =
> >          EN_OVSDB_GET(engine_get_input("SB_advertised_route", node));
> > +    struct ed_type_lr_stateful *lr_stateful_data =
> > +        engine_get_input_data("lr_stateful", node);
> >  
> >      stopwatch_start(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec());
> >  
> >      advertised_route_table_sync(eng_ctx->ovnsb_idl_txn,
> >                        sbrec_advertised_route_table,
> > -                      &routes_data->parsed_routes);
> > +                      &lr_stateful_data->table,
> > +                      &routes_data->parsed_routes,
> > +                      &routes_sync_data->trk_data);
> >  
> >      stopwatch_stop(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec());
> >      engine_set_node_state(node, EN_UPDATED);
> > @@ -71,6 +168,7 @@ struct ar_entry {
> >  
> >      const struct sbrec_port_binding *logical_port;
> >      char *ip_prefix;
> > +    const struct sbrec_port_binding *tracked_port;
> >      bool stale;
> >  };
> >  
> > @@ -78,13 +176,17 @@ static struct ar_entry *
> >  ar_alloc_entry(struct hmap *routes,
> >                    const struct sbrec_datapath_binding *sb_db,
> >                    const struct sbrec_port_binding *logical_port,
> > -                  const char *ip_prefix)
> > +                  const char *ip_prefix,
> > +                  const struct sbrec_port_binding *tracked_port)
> >  {
> >      struct ar_entry *route_e = xzalloc(sizeof *route_e);
> >  
> >      route_e->sb_db = sb_db;
> >      route_e->logical_port = logical_port;
> >      route_e->ip_prefix = xstrdup(ip_prefix);
> > +    if (tracked_port) {
> > +        route_e->tracked_port = tracked_port;
> > +    }
> >      route_e->stale = false;
> >      uint32_t hash = uuid_hash(&sb_db->header_.uuid);
> >      hash = hash_string(logical_port->logical_port, hash);
> > @@ -98,7 +200,8 @@ static struct ar_entry *
> >  ar_lookup_or_add(struct hmap *route_map,
> >                      const struct sbrec_datapath_binding *sb_db,
> >                      const struct sbrec_port_binding *logical_port,
> > -                    const char *ip_prefix)
> > +                    const char *ip_prefix,
> > +                    const struct sbrec_port_binding *tracked_port)
> >  {
> >      struct ar_entry *route_e;
> >      uint32_t hash;
> > @@ -121,11 +224,50 @@ ar_lookup_or_add(struct hmap *route_map,
> >              continue;
> >          }
> >  
> > +        if (!tracked_port != !route_e->tracked_port) {
> > +            continue;
> > +        }
> > +
> > +        if (tracked_port && !uuid_equals(
> > +                &tracked_port->header_.uuid,
> > +                &route_e->tracked_port->header_.uuid)) {
> 
> We don't need to compare UUIDs, do we?  We can just compare pointers.
> We can't have 2 IDL records with different pointers for the same UUID in
> a given table.
> 
> > +            continue;
> > +        }
> > +
> >          return route_e;
> >      }
> >  
> >      route_e = ar_alloc_entry(route_map, sb_db,
> > -                             logical_port, ip_prefix);
> > +                             logical_port, ip_prefix, tracked_port);
> 
> Nit, I'd probably indent this as:
> 
>     route_e = ar_alloc_entry(route_map, sb_db, logical_port, ip_prefix,
>                              tracked_port);
> 
> > +    return route_e;
> > +}
> > +
> > +static struct ar_entry *
> > +ar_sync_to_sb(struct ovsdb_idl_txn *ovnsb_txn, 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 = ar_lookup_or_add(route_map,
> > +                                                sb_db,
> > +                                                logical_port,
> > +                                                ip_prefix,
> > +                                                tracked_port);
> > +    route_e->stale = false;
> > +
> > +    if (!route_e->sb_route) {
> > +        const struct sbrec_advertised_route *sr =
> > +            sbrec_advertised_route_insert(ovnsb_txn);
> > +        sbrec_advertised_route_set_datapath(sr, route_e->sb_db);
> > +        sbrec_advertised_route_set_logical_port(sr, route_e->logical_port);
> > +        sbrec_advertised_route_set_ip_prefix(sr, route_e->ip_prefix);
> > +        if (route_e->tracked_port) {
> > +            sbrec_advertised_route_set_tracked_port(sr, 
> > route_e->tracked_port);
> 
> sbrec_advertised_route_set_tracked_port() works just fine with NULL as
> argument.
> 
> > +        }
> > +        route_e->sb_route = sr;
> > +    }
> > +
> >      return route_e;
> >  }
> >  
> > @@ -143,11 +285,91 @@ get_nbrp_or_nbr_option(const struct ovn_port *op, 
> > const char *key)
> >          smap_get_bool(&op->od->nbr->options, key, false));
> >  }
> >  
> > +static void
> > +publish_lport_addresses(struct ovsdb_idl_txn *ovnsb_txn,
> > +                        struct hmap *route_map,
> > +                        const struct sbrec_datapath_binding *sb_db,
> > +                        const struct ovn_port *logical_port,
> > +                        struct lport_addresses *addresses,
> > +                        const struct ovn_port *tracking_port)
> > +{
> > +    for (int i = 0; i < addresses->n_ipv4_addrs; i++) {
> 
> s/int/size_t
> 
> > +        const struct ipv4_netaddr *addr = &addresses->ipv4_addrs[i];
> > +        char *addr_s = xasprintf("%s/32", addr->addr_s);
> > +        ar_sync_to_sb(ovnsb_txn, route_map,
> > +                         sb_db,
> > +                         logical_port->sb,
> > +                         addr_s,
> > +                         tracking_port->sb);
> 
> Indentation is a bit off here.  Also, this easily fits on 2 lines.
> 
> > +        free(addr_s);
> > +    }
> > +    for (int i = 0; i < addresses->n_ipv6_addrs; i++) {
> 
> s/int/size_t
> 
> > +        if (in6_is_lla(&addresses->ipv6_addrs[i].network)) {
> > +            continue;
> > +        }
> > +        const struct ipv6_netaddr *addr = &addresses->ipv6_addrs[i];
> > +        char *addr_s = xasprintf("%s/128", addr->addr_s);
> > +        ar_sync_to_sb(ovnsb_txn, route_map,
> > +                         sb_db,
> > +                         logical_port->sb,
> > +                         addr_s,
> > +                         tracking_port->sb);
> 
> Indentation is a bit off here.  Also, this easily fits on 2 lines.
> 
> > +        free(addr_s);
> > +    }
> > +}
> > +
> > +
> > +static void
> > +publish_host_routes(struct ovsdb_idl_txn *ovnsb_txn,
> > +                    struct hmap *route_map,
> > +                    const struct lr_stateful_table *lr_stateful_table,
> > +                    const struct parsed_route *route,
> > +                    struct advertised_route_sync_tracked_data *trk_data)
> 
> This function is not that obvious on a first read.  A comment might be
> nice to have.

I hope the new comment helps on that.
> 
> > +{
> > +    struct ovn_port *port;
> > +    struct ovn_datapath *lsp_od = route->out_port->peer->od;
> 
> Newline for readability.
> 
> > +    uuidset_insert(&trk_data->nb_ls, &lsp_od->nbs->header_.uuid);
> > +    HMAP_FOR_EACH (port, dp_node, &lsp_od->ports) {
> > +        if (port->peer) {
> > +            /* This is a LSP connected to an LRP */
> > +            struct lport_addresses *addresses = &port->peer->lrp_networks;
> > +            publish_lport_addresses(ovnsb_txn, route_map, route->od->sb,
> > +                                    route->out_port,
> > +                                    addresses, port->peer);
> > +
> > +            const struct lr_stateful_record *lr_stateful_rec;
> > +            lr_stateful_rec = lr_stateful_table_find_by_index(
> > +                lr_stateful_table, port->peer->od->index);
> > +            uuidset_insert(&trk_data->nb_lr_stateful,
> > +                           &lr_stateful_rec->nbr_uuid);
> > +            struct ovn_port_routable_addresses addrs = get_op_addresses(
> > +                port->peer, lr_stateful_rec, false);
> 
> THis is quite heavy: we'll do it for each and every route, for each and
> every port on each switch connected to the route's output router port.
> Can we precompute "ovn_port_routable_addresses" for all router ports
> instead?

I think it looks worse than it is. This option needs to be set on
individual LRPs so we probably only have it enabled on a few selected
LRPs instead of a large portion of them.

This is also only called for connected routes. So if generally a given
LRP has just a single address assigned to it, we will traverse this only
once.

However since the result of this function just depends on the
route->out_port i have added a filter in advertised_route_table_sync to
only call it at most once per LRP. This should solve the concern.

> 
> > +            for (int i = 0; i < addrs.n_addrs; i++) {
> 
> s/int/size_t
> 
> > +                publish_lport_addresses(ovnsb_txn, route_map, 
> > route->od->sb,
> > +                                        route->out_port,
> > +                                        &addrs.laddrs[i],
> > +                                        port->peer);
> > +            }
> > +            destroy_routable_addresses(&addrs);
> > +        } else {
> > +            /* This is just a plain LSP */
> > +            for (int i = 0; i < port->n_lsp_addrs; i++) {
> 
> s/int/size_t
> 
> > +                publish_lport_addresses(ovnsb_txn, route_map, 
> > route->od->sb,
> > +                                        route->out_port,
> > +                                        &port->lsp_addrs[i],
> > +                                        port);
> > +            }
> > +        }
> > +    }
> > +}
> > +
> >  static void
> >  advertised_route_table_sync(
> >      struct ovsdb_idl_txn *ovnsb_txn,
> >      const struct sbrec_advertised_route_table 
> > *sbrec_advertised_route_table,
> > -    const struct hmap *parsed_routes)
> > +    const struct lr_stateful_table *lr_stateful_table,
> > +    const struct hmap *parsed_routes,
> > +    struct advertised_route_sync_tracked_data *trk_data)
> >  {
> >      if (!ovnsb_txn) {
> >          return;
> > @@ -164,7 +386,8 @@ advertised_route_table_sync(
> >          route_e = ar_alloc_entry(&sync_routes,
> >                                      sb_route->datapath,
> >                                      sb_route->logical_port,
> > -                                    sb_route->ip_prefix);
> > +                                    sb_route->ip_prefix,
> > +                                    sb_route->tracked_port);
> >          route_e->stale = true;
> >          route_e->sb_route = sb_route;
> >      }
> > @@ -180,10 +403,18 @@ advertised_route_table_sync(
> >                             false)) {
> >              continue;
> >          }
> > -        if (route->source == ROUTE_SOURCE_CONNECTED &&
> > -                !get_nbrp_or_nbr_option(route->out_port,
> > +        if (route->source == ROUTE_SOURCE_CONNECTED) {
> > +            if (!get_nbrp_or_nbr_option(route->out_port,
> >                                          "dynamic-routing-connected")) {
> > -            continue;
> > +                continue;
> > +            }
> > +            if (smap_get_bool(&route->out_port->nbrp->options,
> > +                              "dynamic-routing-connected-as-host-routes",
> > +                              false)) {
> > +                publish_host_routes(ovnsb_txn, &sync_routes,
> > +                                    lr_stateful_table, route, trk_data);
> > +                continue;
> > +            }
> >          }
> >          if (route->source == ROUTE_SOURCE_STATIC &&
> >                  !get_nbrp_or_nbr_option(route->out_port,
> > @@ -193,18 +424,11 @@ advertised_route_table_sync(
> >  
> >          char *ip_prefix = normalize_v46_prefix(&route->prefix,
> >                                                 route->plen);
> > -        route_e = ar_lookup_or_add(&sync_routes, route->od->sb,
> > -                                   route->out_port->sb, ip_prefix);
> > -        route_e->stale = false;
> > -
> > -        if (!route_e->sb_route) {
> > -            const struct sbrec_advertised_route *sr =
> > -                sbrec_advertised_route_insert(ovnsb_txn);
> > -            sbrec_advertised_route_set_datapath(sr, route_e->sb_db);
> > -            sbrec_advertised_route_set_logical_port(sr, 
> > route_e->logical_port);
> > -            sbrec_advertised_route_set_ip_prefix(sr, route_e->ip_prefix);
> > -            route_e->sb_route = sr;
> > -        }
> > +        ar_sync_to_sb(ovnsb_txn, &sync_routes,
> > +                         route->od->sb,
> > +                         route->out_port->sb,
> > +                         ip_prefix,
> > +                         NULL);
> >  
> >          free(ip_prefix);
> >      }
> > diff --git a/northd/en-advertised-route-sync.h 
> > b/northd/en-advertised-route-sync.h
> > index c6a41c713..8206d7e27 100644
> > --- a/northd/en-advertised-route-sync.h
> > +++ b/northd/en-advertised-route-sync.h
> > @@ -15,10 +15,26 @@
> >  #define EN_ADVERTISED_ROUTE_SYNC_H 1
> >  
> >  #include "lib/inc-proc-eng.h"
> > +#include "lib/uuidset.h"
> > +
> > +struct advertised_route_sync_tracked_data {
> > +  /* Contains the uuids of all NB Logical Routers where we used a
> > +   * lr_stateful_record during computation. */
> > +  struct uuidset nb_lr_stateful;
> > +  /* Contains the uuids of all NB Logical Switches where we rely on port
> > +   * port changes for host routes. */
> 
> "port port"?
> 
> > +  struct uuidset nb_ls;
> > +};
> >  
> >  struct advertised_route_sync_data {
> > +    /* Node's tracked data. */
> > +    struct advertised_route_sync_tracked_data trk_data;
> 
> It's not really "tracked" data in the same sense we call other I-P data
> as "tracked".  In the incremental processing "world" of OVN "tracked
> data" is normally data for which we track changes
> (addition/updates/deletions) to pass along to other I-P nodes that
> depend on the current node data.
> 
> In this case advertised_route_sync_tracked_data is only relevant to the
> advertised_route_sync I-P node.  I'd just embed the nb_lr_stateful and
> nb_ls uuidsets here, I think.

Will do that, thanks

> 
> >  };
> >  
> > +bool advertised_route_sync_lr_stateful_change_handler(struct engine_node 
> > *node,
> 
> The parameter name 'node' is a bit superfluous here.
> 
> > +                                                      void *data);
> > +bool advertised_route_sync_northd_change_handler(struct engine_node *node,
> 
> Here too.
> 
> > +                                       void *data);
> 
> Incorrect indentation, please align with the first parameter above.
> 
> >  void *en_advertised_route_sync_init(struct engine_node *, struct 
> > engine_arg *);
> >  void en_advertised_route_sync_cleanup(void *data);
> >  void en_advertised_route_sync_run(struct engine_node *, void *data);
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index ed9e27de9..ab500a86a 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -272,6 +272,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >      engine_add_input(&en_advertised_route_sync, &en_routes, NULL);
> >      engine_add_input(&en_advertised_route_sync, &en_sb_advertised_route,
> >                       engine_noop_handler);
> > +    engine_add_input(&en_advertised_route_sync, &en_lr_stateful,
> > +                     advertised_route_sync_lr_stateful_change_handler);
> > +    engine_add_input(&en_advertised_route_sync, &en_northd,
> > +                     advertised_route_sync_northd_change_handler);
> 
> Could you please add some incremental processing unit tests for these
> new dependencies?

Yep, will be part of v3

> 
> >  
> >      engine_add_input(&en_learned_route_sync, &en_routes, NULL);
> >      engine_add_input(&en_learned_route_sync, &en_sb_learned_route, NULL);
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 75519e734..c6344b48a 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -1096,19 +1096,6 @@ build_datapaths(struct ovsdb_idl_txn *ovnsb_txn,
> >      ods_build_array_index(lr_datapaths);
> >  }
> >  
> > -/* Structure representing logical router port
> > - * routable addresses. This includes DNAT and Load Balancer
> > - * addresses. This structure will only be filled in if the
> > - * router port is a gateway router port. Otherwise, all pointers
> > - * will be NULL and n_addrs will be 0.
> > - */
> > -struct ovn_port_routable_addresses {
> > -    /* The parsed routable addresses */
> > -    struct lport_addresses *laddrs;
> > -    /* Number of items in the laddrs array */
> > -    size_t n_addrs;
> > -};
> > -
> >  static bool lsp_can_be_inc_processed(const struct 
> > nbrec_logical_switch_port *);
> >  
> >  /* This function returns true if 'op' is a gateway router port.
> > @@ -1143,7 +1130,7 @@ is_cr_port(const struct ovn_port *op)
> >      return op->primary_port;
> >  }
> >  
> > -static void
> > +void
> >  destroy_routable_addresses(struct ovn_port_routable_addresses *ra)
> >  {
> >      for (size_t i = 0; i < ra->n_addrs; i++) {
> > @@ -1156,12 +1143,14 @@ static char **get_nat_addresses(const struct 
> > ovn_port *op, size_t *n,
> >                                  bool routable_only, bool include_lb_ips,
> >                                  const struct lr_stateful_record *);
> >  
> > -static struct ovn_port_routable_addresses
> > -get_op_routable_addresses(struct ovn_port *op,
> > -                          const struct lr_stateful_record *lr_stateful_rec)
> > +struct ovn_port_routable_addresses
> > +get_op_addresses(struct ovn_port *op,
> > +                 const struct lr_stateful_record *lr_stateful_rec,
> > +                 bool routable_only)
> >  {
> >      size_t n;
> > -    char **nats = get_nat_addresses(op, &n, true, true, lr_stateful_rec);
> > +    char **nats = get_nat_addresses(op, &n, routable_only, true,
> > +                                    lr_stateful_rec);
> >  
> >      if (!nats) {
> >          return (struct ovn_port_routable_addresses) {
> > @@ -1194,6 +1183,13 @@ get_op_routable_addresses(struct ovn_port *op,
> >      };
> >  }
> >  
> > +static struct ovn_port_routable_addresses
> > +get_op_routable_addresses(struct ovn_port *op,
> > +                          const struct lr_stateful_record *lr_stateful_rec)
> > +{
> > +    return get_op_addresses(op, lr_stateful_rec, true);
> > +}
> > +
> >  
> >  static void
> >  ovn_port_set_nb(struct ovn_port *op,
> > diff --git a/northd/northd.h b/northd/northd.h
> > index 9b80f422d..3bc6f6f04 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -25,6 +25,7 @@
> >  #include "openvswitch/hmap.h"
> >  #include "simap.h"
> >  #include "ovs-thread.h"
> > +#include "en-lr-stateful.h"
> >  
> >  struct northd_input {
> >      /* Northbound table references */
> > @@ -185,10 +186,6 @@ struct routes_data {
> >      struct hmap bfd_active_connections;
> >  };
> >  
> > -struct routes_sync_data {
> > -    struct hmap parsed_routes;
> > -};
> > -
> >  struct route_policies_data {
> >      struct hmap route_policies;
> >      struct hmap bfd_active_connections;
> > @@ -938,4 +935,24 @@ ovn_port_find_bound(const struct hmap *ports, const 
> > char *name)
> >      return ovn_port_find__(ports, name, true);
> >  }
> >  
> > +/* Structure representing logical router port
> > + * routable addresses. This includes DNAT and Load Balancer
> > + * addresses. This structure will only be filled in if the
> > + * router port is a gateway router port. Otherwise, all pointers
> > + * will be NULL and n_addrs will be 0.
> > + */
> 
> Nit: I know this is just code you had to move around but we could wrap
> that comment a bit better now that we're moving it.  E.g.:
> 
> /* Structure representing logical router port routable addresses. This
>  * includes DNAT and Load Balancer addresses. This structure will only
>  * be filled in if the router port is a gateway router port. Otherwise,
>  * all pointers will be NULL and n_addrs will be 0.
>  */
> 
> > +struct ovn_port_routable_addresses {
> > +    /* The parsed routable addresses */
> > +    struct lport_addresses *laddrs;
> > +    /* Number of items in the laddrs array */
> > +    size_t n_addrs;
> > +};
> > +
> > +struct ovn_port_routable_addresses get_op_addresses(
> > +    struct ovn_port *op,
> > +    const struct lr_stateful_record *lr_stateful_rec,
> > +    bool routable_only);
> > +
> > +void destroy_routable_addresses(struct ovn_port_routable_addresses *ra);
> > +
> >  #endif /* NORTHD_H */
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index fb178cbed..eb7ee72df 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -3749,6 +3749,33 @@ or
> >          key="dynamic-routing-static" table="Logical_Router_Port"/> will be
> >          used.
> >        </column>
> > +      <column name="options" key="dynamic-routing-connected-as-host-routes"
> > +              type='{"type": "boolean"}'>
> > +        Only relevant if <ref column="options" key="dynamic-routing"
> > +        table="Logical_Router"/> on the respective Logical_Router is set
> > +        to <code>true</code> and also
> > +        <ref column="options" key="dynamic-routing-connected"/> is enabled 
> > on
> > +        the LR or LRP.
> > +
> > +        In this case the prefix connected to the LRP is not advertised as a
> 
> You mean "If set to true.. " here, right?
> 
> > +        whole. Rather each individual IP address that is actually in use 
> > inside
> > +        this prefix is announced as a host route.
> 
> Let's mention the default value
> 
> > +
> > +        This can be used to:
> > +        <ul>
> > +          <li>
> > +            allow the fabric outside of OVN to drop traffic towards IP
> 
> To be consistent we should start this with a capital letter.
> 
> > +            addresses that are not actually used. This traffic would 
> > otherwise
> > +            hit this LR and then be dropped.
> > +          </li>
> > +
> > +          <li>
> > +            If this LR has multiple LRPs connected to the fabric on 
> > different
> > +            chassis: allows the fabric outside of OVN to steer packets to 
> > the
> > +            chassis which already hosts this backing ip address.
> > +          </li>
> > +        </ul>
> > +      </column>
> >      </group>
> >  
> >      <group title="Attachment">
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 1dd2613c3..b7a5acd72 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -14607,3 +14607,74 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | 
> > ovn_strip_lflows], [0], [dnl
> >  AT_CLEANUP
> >  ])
> >  
> > +OVN_FOR_EACH_NORTHD_NO_HV([
> > +AT_SETUP([dynamic-routing - host routes])
> > +AT_KEYWORDS([dynamic-routing])
> > +ovn_start
> > +
> > +# we start with announcing routes on a lr with 2 lrps
> > +# lr0-sw0 is connected to ls sw0
> > +check ovn-nbctl lr-add lr0
> > +check ovn-nbctl set Logical_Router lr0 option:dynamic-routing=true \
> > +                                 option:dynamic-routing-connected=true \
> > +                                 option:dynamic-routing-static=true
> > +check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
> > +sw0=$(ovn-sbctl --bare --columns _uuid list port_binding lr0-sw0)
> 
> fetch_column
> 
> > +check ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 10.0.1.1/24
> > +sw1=$(ovn-sbctl --bare --columns _uuid list port_binding lr0-sw1)
> 
> fetch_column
> 
> > +check ovn-nbctl ls-add sw0
> > +check ovn-nbctl lsp-add sw0 sw0-lr0
> > +check ovn-nbctl --wait=sb set Logical_Switch_Port sw0-lr0 type=router 
> > options:router-port=lr0-sw0
> > +check_row_count Advertised_Route 2 tracked_port='[[]]'
> > +datapath=$(ovn-sbctl --bare --columns _uuid list datapath_binding lr0)
> 
> fetch_column
> 
> > +
> > +# configuring the LRP lr0-sw0 to send host routes
> > +# as sw0 is quite empty we will only see the addresses of lr0-sw0
> > +check ovn-nbctl --wait=sb set Logical_Router_Port lr0-sw0 
> > options:dynamic-routing-connected-as-host-routes=true
> > +check_row_count Advertised_Route 2
> > +AT_CHECK_UNQUOTED([ovn-sbctl --columns ip_prefix,tracked_port --bare find 
> > Advertised_Route datapath=$datapath logical_port=$sw0], [0], [dnl
> > +10.0.0.1/32
> > +$sw0
> > +])
> 
> check_column?
> 
> > +
> > +# adding a VIF to the LS sw0 will advertise it as well
> > +check ovn-nbctl lsp-add sw0 sw0-vif0
> > +check ovn-nbctl --wait=sb lsp-set-addresses sw0-vif0 "00:aa:bb:cc:dd:ee 
> > 10.0.0.2"
> > +vif0=$(ovn-sbctl --bare --columns _uuid list port_binding sw0-vif0)
> > +check_row_count Advertised_Route 3
> > +check_row_count Advertised_Route 2 tracked_port!='[[]]'
> > +AT_CHECK_UNQUOTED([ovn-sbctl --columns tracked_port --bare find 
> > Advertised_Route datapath=$datapath logical_port=$sw0 
> > ip_prefix=10.0.0.2/32], [0], [dnl
> > +$vif0
> > +])
> 
> check_column?
> 
> > +
> > +# adding a LR lr1 to the LS sw0 will advertise the LRP of the new router
> > +check ovn-nbctl lr-add lr1
> > +check ovn-nbctl lrp-add lr1 lr1-sw0 00:00:00:01:ff:01 10.0.0.10/24
> > +check ovn-nbctl lsp-add sw0 sw0-lr1
> > +lr1=$(ovn-sbctl --bare --columns _uuid list port_binding lr1-sw0)
> 
> fetch_column
> 
> > +check ovn-nbctl --wait=sb set Logical_Switch_Port sw0-lr1 type=router 
> > options:router-port=lr1-sw0
> > +check_row_count Advertised_Route 4
> > +check_row_count Advertised_Route 3 tracked_port!='[[]]'
> > +AT_CHECK_UNQUOTED([ovn-sbctl --columns tracked_port --bare find 
> > Advertised_Route datapath=$datapath logical_port=$sw0 
> > ip_prefix=10.0.0.10/32], [0], [dnl
> > +$lr1
> > +])
> 
> check_column?
> 
> > +
> > +# adding a NAT rule to lr1 will advertise it as well
> > +check ovn-nbctl --wait=sb lr-nat-add lr1 dnat_and_snat 10.0.0.100 
> > 192.168.0.1
> > +check_row_count Advertised_Route 5
> > +check_row_count Advertised_Route 4 tracked_port!='[[]]'
> > +AT_CHECK_UNQUOTED([ovn-sbctl --columns tracked_port --bare find 
> > Advertised_Route datapath=$datapath logical_port=$sw0 
> > ip_prefix=10.0.0.100/32], [0], [dnl
> > +$lr1
> > +])
> 
> check_column?
> 
> > +
> > +# adding a static route to lr1 will be advertised just normally
> > +check ovn-nbctl --wait=sb lr-route-add lr0 172.16.0.0/24 10.0.0.200
> > +check_row_count Advertised_Route 6
> > +check_row_count Advertised_Route 4 tracked_port!='[[]]'
> > +AT_CHECK([ovn-sbctl --columns ip_prefix --bare find Advertised_Route 
> > datapath=$datapath logical_port=$sw0 ip_prefix=172.16.0.0/24], [0], [dnl
> > +172.16.0.0/24
> > +])
> 
> check_column?
> 
> > +
> > +AT_CLEANUP
> > +])
> > +

Thanks a lot.
Felix

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

Reply via email to