On Tue, Nov 26, 2024 at 04:28:53PM -0300, Tiago Pires wrote:
> Hi Felix,
> 
> Thanks for the patch.
> I would ask if it makes sense to have logical flows for NAT addresses
> that are in different subnets of the network of the LR IP. In this
> case, when using the active-active feature, the tear one LR would have
> those logical flows to know how to route the traffic back to the tear
> two LR (project routers).
> This use case happens when the user separates NAT IPs in a subnet and
> LRPs addresses in another one.
> Nowadays this scenario works when the external network (LS) has the
> localnet port and can rely in the ARP as the ovn-controller sends the
> GARP or using NDR(Neutron dynamic routing) to advertise the /32 or /64
> having the next-hop as the LRP uplink address.

Hi Tiago,

i think in this case the tier one LR (so the one connected to the
fabric) would need to have static /32 routes pointing to the tier two LRs
(the project routers) for each of the NAT IPs.

This series would then announce these /32 routes to the fabric.
However this patch would not play part in this and we would not actually
populate "tracked_port", thereby potentially causing the fabric to send
traffic to a non-optimal chassis.

I guess this could be quite easily added afterwards that we also
populate tracked_port for static routes with the nexthop LSP/LRP.

Thanks a lot
Felix

> 
> Regards,
> 
> Tiago Pires
> 
> On Tue, Nov 26, 2024 at 11:40 AM Felix Huettner via dev
> <[email protected]> wrote:
> >
> > sometimes we want to use individual host routes instead of the connected
> > routes of LRPs.
> > This allows the network fabric to know which adresses are actually in
> > use and e.g. drop traffic to adresses that are not used anyway.
> >
> > Signed-off-by: Felix Huettner <[email protected]>
> > ---
> >  NEWS                     |   2 +
> >  northd/en-lflow.c        |   1 +
> >  northd/en-routes-sync.c  | 270 ++++++++++++++++++++++++++++++++++-----
> >  northd/en-routes-sync.h  |  22 +++-
> >  northd/inc-proc-northd.c |   2 +
> >  northd/northd.c          |  32 ++---
> >  northd/northd.h          |  25 +++-
> >  ovn-nb.xml               |  27 ++++
> >  ovn-sb.ovsschema         |   3 +-
> >  ovn-sb.xml               |  13 ++
> >  tests/ovn-northd.at      |  67 ++++++++++
> >  11 files changed, 406 insertions(+), 58 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index efb42b32b..a780940fc 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -14,6 +14,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.
> >
> >  OVN v24.09.0 - 13 Sep 2024
> >  --------------------------
> > diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> > index 8995f0300..aabba943e 100644
> > --- a/northd/en-lflow.c
> > +++ b/northd/en-lflow.c
> > @@ -26,6 +26,7 @@
> >  #include "en-northd.h"
> >  #include "en-meters.h"
> >  #include "en-sampling-app.h"
> > +#include "en-routes-sync.h"
> >  #include "lflow-mgr.h"
> >
> >  #include "lib/inc-proc-eng.h"
> > diff --git a/northd/en-routes-sync.c b/northd/en-routes-sync.c
> > index 7ca87c76a..d5a534f86 100644
> > --- a/northd/en-routes-sync.c
> > +++ b/northd/en-routes-sync.c
> > @@ -13,6 +13,7 @@
> >   */
> >
> >  #include <config.h>
> > +#include <stdbool.h>
> >
> >  #include "openvswitch/vlog.h"
> >  #include "smap.h"
> > @@ -20,6 +21,7 @@
> >  #include "northd.h"
> >
> >  #include "en-routes-sync.h"
> > +#include "en-lr-stateful.h"
> >  #include "lib/stopwatch-names.h"
> >  #include "openvswitch/hmap.h"
> >  #include "ovn-util.h"
> > @@ -29,15 +31,19 @@ VLOG_DEFINE_THIS_MODULE(en_routes_sync);
> >  static void
> >  routes_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
> >                    const struct sbrec_route_table *sbrec_route_table,
> > +                  const struct lr_stateful_table *lr_stateful_table,
> >                    const struct hmap *parsed_routes,
> >                    const struct hmap *lr_ports,
> >                    const struct ovn_datapaths *lr_datapaths,
> > -                  struct hmap *parsed_routes_out);
> > +                  struct hmap *parsed_routes_out,
> > +                  struct routes_sync_tracked_data *trk_data);
> >
> >  static void
> >  routes_sync_init(struct routes_sync_data *data)
> >  {
> >      hmap_init(&data->parsed_routes);
> > +    uuidset_init(&data->trk_data.nb_lr_stateful);
> > +    uuidset_init(&data->trk_data.nb_ls);
> >  }
> >
> >  static void
> > @@ -48,12 +54,15 @@ routes_sync_destroy(struct routes_sync_data *data)
> >          parsed_route_free(r);
> >      }
> >      hmap_destroy(&data->parsed_routes);
> > +    uuidset_destroy(&data->trk_data.nb_lr_stateful);
> > +    uuidset_destroy(&data->trk_data.nb_ls);
> >  }
> >
> >  bool
> >  routes_sync_northd_change_handler(struct engine_node *node,
> > -                                  void *data OVS_UNUSED)
> > +                                  void *data_)
> >  {
> > +    struct routes_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;
> > @@ -69,7 +78,58 @@ routes_sync_northd_change_handler(struct engine_node 
> > *node,
> >       *      this happens and so does this node.
> >       *      Note: When we add I-P to the created/deleted logical routers or
> >       *      logical router ports, we need to revisit this handler.
> > +     *   3. Indirectly  northd_data->ls_ports if we announce host routes
> > +     *      This is what we check below
> >       */
> > +
> > +    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;
> > +}
> > +
> > +bool
> > +routes_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 routes_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;
> >  }
> >
> > @@ -101,14 +161,18 @@ en_routes_sync_run(struct engine_node *node, void 
> > *data)
> >      const struct sbrec_route_table *sbrec_route_table =
> >          EN_OVSDB_GET(engine_get_input("SB_route", node));
> >      struct northd_data *northd_data = engine_get_input_data("northd", 
> > node);
> > +    struct ed_type_lr_stateful *lr_stateful_data =
> > +        engine_get_input_data("lr_stateful", node);
> >
> >      stopwatch_start(ROUTES_SYNC_RUN_STOPWATCH_NAME, time_msec());
> >
> >      routes_table_sync(eng_ctx->ovnsb_idl_txn, sbrec_route_table,
> > +                      &lr_stateful_data->table,
> >                        &routes_data->parsed_routes,
> >                        &northd_data->lr_ports,
> >                        &northd_data->lr_datapaths,
> > -                      &routes_sync_data->parsed_routes);
> > +                      &routes_sync_data->parsed_routes,
> > +                      &routes_sync_data->trk_data);
> >
> >      stopwatch_stop(ROUTES_SYNC_RUN_STOPWATCH_NAME, time_msec());
> >      engine_set_node_state(node, EN_UPDATED);
> > @@ -122,6 +186,7 @@ struct route_entry {
> >
> >      char *logical_port;
> >      char *ip_prefix;
> > +    char *tracked_port;
> >      char *type;
> >      bool stale;
> >  };
> > @@ -129,7 +194,10 @@ struct route_entry {
> >  static struct route_entry *
> >  route_alloc_entry(struct hmap *routes,
> >                    const struct sbrec_datapath_binding *sb_db,
> > -                  char *logical_port, char *ip_prefix, char *route_type)
> > +                  const char *logical_port,
> > +                  const char *ip_prefix,
> > +                  const char *route_type,
> > +                  const char *tracked_port)
> >  {
> >      struct route_entry *route_e = xzalloc(sizeof *route_e);
> >
> > @@ -137,6 +205,9 @@ route_alloc_entry(struct hmap *routes,
> >      route_e->logical_port = xstrdup(logical_port);
> >      route_e->ip_prefix = xstrdup(ip_prefix);
> >      route_e->type = xstrdup(route_type);
> > +    if (tracked_port) {
> > +        route_e->tracked_port = xstrdup(tracked_port);
> > +    }
> >      route_e->stale = false;
> >      uint32_t hash = uuid_hash(&sb_db->header_.uuid);
> >      hash = hash_string(logical_port, hash);
> > @@ -149,27 +220,72 @@ route_alloc_entry(struct hmap *routes,
> >  static struct route_entry *
> >  route_lookup_or_add(struct hmap *route_map,
> >                      const struct sbrec_datapath_binding *sb_db,
> > -                    char *logical_port, const struct in6_addr *prefix,
> > -                    unsigned int plen, char *route_type)
> > +                    const char *logical_port, const char *ip_prefix,
> > +                    const char *route_type, const char *tracked_port)
> >  {
> >      struct route_entry *route_e;
> >      uint32_t hash;
> >
> > -    char *ip_prefix = normalize_v46_prefix(prefix, plen);
> > -
> >      hash = uuid_hash(&sb_db->header_.uuid);
> >      hash = hash_string(logical_port, hash);
> >      hash = hash_string(ip_prefix, hash);
> >      HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) {
> > -        if (!strcmp(route_e->type, route_type)) {
> > -            free(ip_prefix);
> > -            return route_e;
> > +        if (!uuid_equals(&sb_db->header_.uuid,
> > +                         &route_e->sb_db->header_.uuid)) {
> > +            continue;
> >          }
> > +
> > +        if (strcmp(logical_port, route_e->logical_port)) {
> > +            continue;
> > +        }
> > +
> > +        if (strcmp(ip_prefix, route_e->ip_prefix)) {
> > +            continue;
> > +        }
> > +
> > +        if (strcmp(route_type, route_e->type)) {
> > +            continue;
> > +        }
> > +
> > +        if (!streq(tracked_port, route_e->tracked_port)) {
> > +            continue;
> > +        }
> > +
> > +        return route_e;
> > +    }
> > +
> > +    route_e = route_alloc_entry(route_map, sb_db,
> > +                                 logical_port, ip_prefix, route_type,
> > +                                 tracked_port);
> > +    return route_e;
> > +}
> > +
> > +static struct route_entry *
> > +route_sync_to_sb(struct ovsdb_idl_txn *ovnsb_txn, struct hmap *route_map,
> > +                 const struct sbrec_datapath_binding *sb_db,
> > +                 const char *logical_port, const char *ip_prefix,
> > +                 const char *route_type, const char *tracked_port)
> > +{
> > +    struct route_entry *route_e = route_lookup_or_add(route_map,
> > +                                                      sb_db,
> > +                                                      logical_port,
> > +                                                      ip_prefix,
> > +                                                      route_type,
> > +                                                      tracked_port);
> > +    route_e->stale = false;
> > +
> > +    if (!route_e->sb_route) {
> > +        const struct sbrec_route *sr = sbrec_route_insert(ovnsb_txn);
> > +        sbrec_route_set_datapath(sr, route_e->sb_db);
> > +        sbrec_route_set_logical_port(sr, route_e->logical_port);
> > +        sbrec_route_set_ip_prefix(sr, route_e->ip_prefix);
> > +        sbrec_route_set_type(sr, route_e->type);
> > +        if (route_e->tracked_port) {
> > +            sbrec_route_set_tracked_port(sr, route_e->tracked_port);
> > +        }
> > +        route_e->sb_route = sr;
> >      }
> >
> > -    route_e =  route_alloc_entry(route_map, sb_db,
> > -                                 logical_port, ip_prefix, route_type);
> > -    free(ip_prefix);
> >      return route_e;
> >  }
> >
> > @@ -179,6 +295,7 @@ route_erase_entry(struct route_entry *route_e)
> >      free(route_e->logical_port);
> >      free(route_e->ip_prefix);
> >      free(route_e->type);
> > +    free(route_e->tracked_port);
> >      free(route_e);
> >  }
> >
> > @@ -270,13 +387,95 @@ parse_route_from_sbrec_route(struct hmap 
> > *parsed_routes_out,
> >          );
> >  }
> >
> > +static void
> > +publish_lport_addresses(struct ovsdb_idl_txn *ovnsb_txn,
> > +                        struct hmap *route_map,
> > +                        const struct sbrec_datapath_binding *sb_db,
> > +                        char *logical_port,
> > +                        struct lport_addresses *addresses,
> > +                        struct ovn_port *tracking_port)
> > +{
> > +    for (int i = 0; i < addresses->n_ipv4_addrs; i++) {
> > +        const struct ipv4_netaddr *addr = &addresses->ipv4_addrs[i];
> > +        char *addr_s = xasprintf("%s/32", addr->addr_s);
> > +        route_sync_to_sb(ovnsb_txn, route_map,
> > +                         sb_db,
> > +                         logical_port,
> > +                         addr_s,
> > +                         "advertise",
> > +                         tracking_port->sb->logical_port);
> > +        free(addr_s);
> > +    }
> > +    for (int 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];
> > +        char *addr_s = xasprintf("%s/128", addr->addr_s);
> > +        route_sync_to_sb(ovnsb_txn, route_map,
> > +                         sb_db,
> > +                         logical_port,
> > +                         addr_s,
> > +                         "advertise",
> > +                         tracking_port->sb->logical_port);
> > +        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 routes_sync_tracked_data *trk_data)
> > +{
> > +    struct ovn_port *port;
> > +    struct ovn_datapath *lsp_od = route->out_port->peer->od;
> > +    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->key,
> > +                                    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);
> > +            for (int i = 0; i < addrs.n_addrs; i++) {
> > +                publish_lport_addresses(ovnsb_txn, route_map, 
> > route->od->sb,
> > +                                        route->out_port->key,
> > +                                        &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++) {
> > +                publish_lport_addresses(ovnsb_txn, route_map, 
> > route->od->sb,
> > +                                        route->out_port->key,
> > +                                        &port->lsp_addrs[i],
> > +                                        port);
> > +            }
> > +        }
> > +    }
> > +}
> > +
> >  static void
> >  routes_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
> >                    const struct sbrec_route_table *sbrec_route_table,
> > +                  const struct lr_stateful_table *lr_stateful_table,
> >                    const struct hmap *parsed_routes,
> >                    const struct hmap *lr_ports,
> >                    const struct ovn_datapaths *lr_datapaths,
> > -                  struct hmap *parsed_routes_out)
> > +                  struct hmap *parsed_routes_out,
> > +                  struct routes_sync_tracked_data *trk_data)
> >  {
> >      if (!ovnsb_txn) {
> >          return;
> > @@ -303,7 +502,8 @@ routes_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
> >                                      sb_route->datapath,
> >                                      sb_route->logical_port,
> >                                      sb_route->ip_prefix,
> > -                                    sb_route->type);
> > +                                    sb_route->type,
> > +                                    sb_route->tracked_port);
> >          route_e->stale = true;
> >          route_e->sb_route = sb_route;
> >      }
> > @@ -321,32 +521,34 @@ routes_table_sync(struct ovsdb_idl_txn *ovnsb_txn,
> >                             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,
> >                                          "dynamic-routing-static")) {
> >              continue;
> >          }
> > -        route_e = route_lookup_or_add(&sync_routes,
> > -                                      route->od->sb,
> > -                                      route->out_port->key,
> > -                                      &route->prefix,
> > -                                      route->plen,
> > -                                      "advertise");
> > -        route_e->stale = false;
> >
> > -        if (!route_e->sb_route) {
> > -            const struct sbrec_route *sr = sbrec_route_insert(ovnsb_txn);
> > -            sbrec_route_set_datapath(sr, route_e->sb_db);
> > -            sbrec_route_set_logical_port(sr, route_e->logical_port);
> > -            sbrec_route_set_ip_prefix(sr, route_e->ip_prefix);
> > -            sbrec_route_set_type(sr, route_e->type);
> > -            route_e->sb_route = sr;
> > -        }
> > +        char *ip_prefix = normalize_v46_prefix(&route->prefix,
> > +                                               route->plen);
> > +        route_sync_to_sb(ovnsb_txn, &sync_routes,
> > +                         route->od->sb,
> > +                         route->out_port->key,
> > +                         ip_prefix,
> > +                         "advertise",
> > +                         NULL);
> > +        free(ip_prefix);
> >      }
> >
> >      HMAP_FOR_EACH_POP (route_e, hmap_node, &sync_routes) {
> > diff --git a/northd/en-routes-sync.h b/northd/en-routes-sync.h
> > index 391f17452..10f33ce91 100644
> > --- a/northd/en-routes-sync.h
> > +++ b/northd/en-routes-sync.h
> > @@ -15,9 +15,29 @@
> >  #define EN_ROUTES_SYNC_H 1
> >
> >  #include "lib/inc-proc-eng.h"
> > +#include "lib/uuidset.h"
> > +#include "openvswitch/hmap.h"
> > +
> > +struct routes_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. */
> > +  struct uuidset nb_ls;
> > +};
> > +
> > +struct routes_sync_data {
> > +    struct hmap parsed_routes;
> > +
> > +    /* Node's tracked data. */
> > +    struct routes_sync_tracked_data trk_data;
> > +};
> >
> >  bool routes_sync_northd_change_handler(struct engine_node *node,
> > -                                       void *data OVS_UNUSED);
> > +                                       void *data);
> > +bool routes_sync_lr_stateful_change_handler(struct engine_node *node,
> > +                                            void *data);
> >  void *en_routes_sync_init(struct engine_node *, struct engine_arg *);
> >  void en_routes_sync_cleanup(void *data);
> >  void en_routes_sync_run(struct engine_node *, void *data);
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index 741295709..84072d6ce 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -271,6 +271,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >      engine_add_input(&en_routes_sync, &en_sb_route, NULL);
> >      engine_add_input(&en_routes_sync, &en_northd,
> >                       routes_sync_northd_change_handler);
> > +    engine_add_input(&en_routes_sync, &en_lr_stateful,
> > +                     routes_sync_lr_stateful_change_handler);
> >
> >      engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
> >      engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 4439a74da..a2e59dcfc 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -1094,19 +1094,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.
> > @@ -1141,7 +1128,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++) {
> > @@ -1154,12 +1141,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) {
> > @@ -1192,6 +1181,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 991ba5f9f..dc51630ed 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 */
> > @@ -186,10 +187,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;
> > @@ -936,4 +933,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.
> > + */
> > +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 75fe40c01..d67a3d07a 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -3705,6 +3705,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
> > +        whole. Rather each individual IP address that is actually in use 
> > inside
> > +        this prefix is announced as a host route.
> > +
> > +        This can be used to:
> > +        <ul>
> > +          <li>
> > +            allow the fabric outside of OVN to drop traffic towards IP
> > +            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/ovn-sb.ovsschema b/ovn-sb.ovsschema
> > index 74540782e..01df9cc6b 100644
> > --- a/ovn-sb.ovsschema
> > +++ b/ovn-sb.ovsschema
> > @@ -1,7 +1,7 @@
> >  {
> >      "name": "OVN_Southbound",
> >      "version": "20.38.0",
> > -    "cksum": "1944407838 32212",
> > +    "cksum": "1452226583 32264",
> >      "tables": {
> >          "SB_Global": {
> >              "columns": {
> > @@ -626,6 +626,7 @@
> >                  "logical_port": {"type": "string"},
> >                  "ip_prefix": {"type": "string"},
> >                  "nexthop": {"type": "string"},
> > +                "tracked_port": {"type": "string"},
> >                  "type": {"type": {"key": {"type": "string",
> >                                            "enum": ["set", ["advertise",
> >                                                             "receive"]]},
> > diff --git a/ovn-sb.xml b/ovn-sb.xml
> > index 493b7e839..bf587153a 100644
> > --- a/ovn-sb.xml
> > +++ b/ovn-sb.xml
> > @@ -5224,6 +5224,19 @@ tcp.flags = RST;
> >        </p>
> >      </column>
> >
> > +    <column name="tracked_port">
> > +      <p>
> > +        Only relevant for type <code>advertise</code> and if
> > +        <code>options:dynamic-routing-connected-as-host-routes</code> is
> > +        set on the <code>OVN_Northbound.Logical_Router_Port</code>.
> > +
> > +        In this case this lists the name of the <code>Port_Binding</code>
> > +        that is holding this ip address. ovn-controller can use this
> > +        information to determine the distance and therefor the route 
> > priority
> > +        of a published route
> > +      </p>
> > +    </column>
> > +
> >      <column name="type">
> >        <p>
> >          If the route is to be exported from OVN to the outside network or 
> > if
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 213536707..b40eb24e6 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -14042,5 +14042,72 @@ 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
> > +check ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 10.0.1.1/24
> > +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 Route 2 type=advertise tracked_port='""'
> > +datapath=$(ovn-sbctl --bare --columns _uuid list datapath_binding lr0)
> > +
> > +# 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 Route 2 type=advertise
> > +AT_CHECK([ovn-sbctl --columns ip_prefix,tracked_port --bare find Route 
> > datapath=$datapath logical_port=lr0-sw0], [0], [dnl
> > +10.0.0.1/32
> > +lr0-sw0
> > +])
> > +
> > +# 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"
> > +check_row_count Route 3 type=advertise
> > +check_row_count Route 2 type=advertise tracked_port!='""'
> > +AT_CHECK([ovn-sbctl --columns tracked_port --bare find Route 
> > datapath=$datapath logical_port=lr0-sw0 ip_prefix=10.0.0.2/32], [0], [dnl
> > +sw0-vif0
> > +])
> > +
> > +# 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
> > +check ovn-nbctl --wait=sb set Logical_Switch_Port sw0-lr1 type=router 
> > options:router-port=lr1-sw0
> > +check_row_count Route 4 type=advertise
> > +check_row_count Route 3 type=advertise tracked_port!='""'
> > +AT_CHECK([ovn-sbctl --columns tracked_port --bare find Route 
> > datapath=$datapath logical_port=lr0-sw0 ip_prefix=10.0.0.10/32], [0], [dnl
> > +lr1-sw0
> > +])
> > +
> > +# 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 Route 5 type=advertise
> > +check_row_count Route 4 type=advertise tracked_port!='""'
> > +AT_CHECK([ovn-sbctl --columns tracked_port --bare find Route 
> > datapath=$datapath logical_port=lr0-sw0 ip_prefix=10.0.0.100/32], [0], [dnl
> > +lr1-sw0
> > +])
> > +
> > +# 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 Route 6 type=advertise
> > +check_row_count Route 4 type=advertise tracked_port!='""'
> > +AT_CHECK([ovn-sbctl --columns ip_prefix --bare find Route 
> > datapath=$datapath logical_port=lr0-sw0 ip_prefix=172.16.0.0/24], [0], [dnl
> > +172.16.0.0/24
> > +])
> > +
> >  AT_CLEANUP
> >  ])
> > --
> > 2.47.0
> >
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> 
> -- 
> 
> 
> 
> 
> _‘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

Reply via email to