> On 6 Feb 2025, at 16:29, Dumitru Ceara <[email protected]> wrote:
> 
> On 2/6/25 4:10 PM, [email protected] wrote:
>> On Thu, 2025-02-06 at 15:08 +0100, Felix Huettner wrote:
>>> On Thu, Feb 06, 2025 at 02:59:21PM +0100,
>>> [email protected] wrote:
>>>> On Thu, 2025-02-06 at 11:52 +0100, Dumitru Ceara wrote:
>>>>> On 2/6/25 11:46 AM, Felix Huettner via dev wrote:
>>>>>> On Thu, Feb 06, 2025 at 10:45:15AM +0100,
>>>>>> [email protected] wrote:
>>>>>>> He Felix, I have one comment regarding the publishing of
>>>>>>> SNATs
>>>>>>> that was
>>>>>>> discussed in my patch series as well.
>>>>>>> 
>>>>>>> On Tue, 2025-02-04 at 14:59 +0100, Felix Huettner via dev
>>>>>>> wrote:
>>>>>>>> Sometimes we want to use individual host routes instead of
>>>>>>>> the
>>>>>>>> connected
>>>>>>>> routes of LRPs.
>>>>>>>> This allows the network fabric to know which addresses are
>>>>>>>> actually
>>>>>>>> in
>>>>>>>> use and e.g. drop traffic to addresses that are not used
>>>>>>>> anyway.
>>>>>>>> 
>>>>>>>> Signed-off-by: Felix Huettner
>>>>>>>> <[email protected]>
>>>>>>>> ---
>>>>>>>> v5->v6:
>>>>>>>>   * addressed review comments
>>>>>>>> v4->v5: skipped
>>>>>>>> v3->v4:
>>>>>>>>   * fix a memory leak
>>>>>>>> v2->v3:
>>>>>>>>   * A lot of minor review comments.
>>>>>>>> 
>>>>>>>>  NEWS                              |   3 +
>>>>>>>>  northd/en-advertised-route-sync.c | 227
>>>>>>>> ++++++++++++++++++++++++++++--
>>>>>>>>  northd/en-advertised-route-sync.h |  11 ++
>>>>>>>>  northd/inc-proc-northd.c          |   4 +
>>>>>>>>  northd/northd.c                   |  35 +++--
>>>>>>>>  northd/northd.h                   |  22 +++
>>>>>>>>  ovn-nb.xml                        |  27 ++++
>>>>>>>>  tests/ovn-northd.at               | 113 ++++++++++++++-
>>>>>>>>  8 files changed, 407 insertions(+), 35 deletions(-)
>>>>>>>> 
>>>>>>>> diff --git a/NEWS b/NEWS
>>>>>>>> index b0ca1992e..3547f659f 100644
>>>>>>>> --- a/NEWS
>>>>>>>> +++ b/NEWS
>>>>>>>> @@ -50,6 +50,9 @@ Post v24.09.0
>>>>>>>>         fabric. Routes entered into the "Learned_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-advertised-route-sync.c b/northd/en-
>>>>>>>> advertised-route-sync.c
>>>>>>>> index d4360763f..a0087c71a 100644
>>>>>>>> --- a/northd/en-advertised-route-sync.c
>>>>>>>> +++ b/northd/en-advertised-route-sync.c
>>>>>>>> @@ -20,6 +20,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"
>>>>>>>> @@ -28,34 +29,131 @@ 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_data *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->nb_lr,
>>>>>>>> +                             &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;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    /* We indirectly use northd_data->ls_ports if we
>>>>>>>> announce
>>>>>>>> host
>>>>>>>> routes.
>>>>>>>> +     * For now we just recompute on any change to lsps
>>>>>>>> that
>>>>>>>> are
>>>>>>>> relevant to us.
>>>>>>>> +     */
>>>>>>>> +    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->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->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->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->nb_lr);
>>>>>>>> +    uuidset_init(&data->nb_ls);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void
>>>>>>>> +routes_sync_clear(struct advertised_route_sync_data *data)
>>>>>>>> +{
>>>>>>>> +    uuidset_clear(&data->nb_lr);
>>>>>>>> +    uuidset_clear(&data->nb_ls);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +static void
>>>>>>>> +routes_sync_destroy(struct advertised_route_sync_data
>>>>>>>> *data)
>>>>>>>> +{
>>>>>>>> +    uuidset_destroy(&data->nb_lr);
>>>>>>>> +    uuidset_destroy(&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_clear(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);
>>>>>>>>  
>>>>>>>>     
>>>>>>>> stopwatch_stop(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME,
>>>>>>>> time_msec());
>>>>>>>>      engine_set_node_state(node, EN_UPDATED);
>>>>>>>> @@ -68,19 +166,24 @@ struct ar_entry {
>>>>>>>>  
>>>>>>>>      const struct sbrec_port_binding *logical_port;
>>>>>>>>      char *ip_prefix;
>>>>>>>> +    const struct sbrec_port_binding *tracked_port;
>>>>>>>>  };
>>>>>>>>  
>>>>>>>>  /* Add a new entries to the to-be-advertised routes.
>>>>>>>>   * Takes ownership of ip_prefix. */
>>>>>>>>  static struct ar_entry *
>>>>>>>>  ar_add_entry(struct hmap *routes, const struct
>>>>>>>> sbrec_datapath_binding *sb_db,
>>>>>>>> -             const struct sbrec_port_binding
>>>>>>>> *logical_port,
>>>>>>>> char
>>>>>>>> *ip_prefix)
>>>>>>>> +               const struct sbrec_port_binding
>>>>>>>> *logical_port,
>>>>>>>> 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 = ip_prefix;
>>>>>>>> +    if (tracked_port) {
>>>>>>>> +        route_e->tracked_port = tracked_port;
>>>>>>>> +    }
>>>>>>>>      uint32_t hash = uuid_hash(&sb_db->header_.uuid);
>>>>>>>>      hash = hash_string(logical_port->logical_port, hash);
>>>>>>>>      hash = hash_string(ip_prefix, hash);
>>>>>>>> @@ -91,7 +194,8 @@ ar_add_entry(struct hmap *routes, const
>>>>>>>> struct
>>>>>>>> sbrec_datapath_binding *sb_db,
>>>>>>>>  
>>>>>>>>  static struct ar_entry *
>>>>>>>>  ar_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 *logical_port,
>>>>>>>> const
>>>>>>>> char
>>>>>>>> *ip_prefix,
>>>>>>>> +        const struct sbrec_port_binding *tracked_port)
>>>>>>>>  {
>>>>>>>>      struct ar_entry *route_e;
>>>>>>>>      uint32_t hash;
>>>>>>>> @@ -114,6 +218,10 @@ ar_find(struct hmap *route_map, const
>>>>>>>> struct
>>>>>>>> sbrec_datapath_binding *sb_db,
>>>>>>>>              continue;
>>>>>>>>          }
>>>>>>>>  
>>>>>>>> +        if (tracked_port != route_e->tracked_port) {
>>>>>>>> +            continue;
>>>>>>>> +        }
>>>>>>>> +
>>>>>>>>          return route_e;
>>>>>>>>      }
>>>>>>>>  
>>>>>>>> @@ -127,13 +235,94 @@ ar_entry_free(struct ar_entry
>>>>>>>> *route_e)
>>>>>>>>      free(route_e);
>>>>>>>>  }
>>>>>>>>  
>>>>>>>> +static void
>>>>>>>> +publish_lport_addresses(struct hmap *sync_routes,
>>>>>>>> +                        const struct
>>>>>>>> sbrec_datapath_binding
>>>>>>>> *sb_db,
>>>>>>>> +                        const struct ovn_port
>>>>>>>> *logical_port,
>>>>>>>> +                        struct lport_addresses *addresses,
>>>>>>>> +                        const struct ovn_port
>>>>>>>> *tracking_port)
>>>>>>>> +{
>>>>>>>> +    for (size_t 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);
>>>>>>>> +        ar_add_entry(sync_routes, sb_db, logical_port->sb,
>>>>>>>> +                       addr_s, tracking_port->sb);
>>>>>>>> +    }
>>>>>>>> +    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];
>>>>>>>> +        char *addr_s = xasprintf("%s/128", addr->addr_s);
>>>>>>>> +        ar_add_entry(sync_routes, sb_db, logical_port->sb,
>>>>>>>> +                       addr_s, tracking_port->sb);
>>>>>>>> +    }
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/* Collect all IP addresses connected to the out_port of a
>>>>>>>> route.
>>>>>>>> + * This traverses all LSPs on the LS connected to the
>>>>>>>> out_port. */
>>>>>>>> +static void
>>>>>>>> +publish_host_routes(struct hmap *sync_routes,
>>>>>>>> +                    const struct lr_stateful_table
>>>>>>>> *lr_stateful_table,
>>>>>>>> +                    const struct parsed_route *route,
>>>>>>>> +                    struct advertised_route_sync_data
>>>>>>>> *data)
>>>>>>>> +{
>>>>>>>> +    struct ovn_port *port;
>>>>>>>> +    struct ovn_datapath *lsp_od = route->out_port->peer-
>>>>>>>>> od;
>>>>>>>> +
>>>>>>>> +    if (!lsp_od->nbs) {
>>>>>>>> +        return;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    /* We need to track the LS we are publishing routes
>>>>>>>> from,
>>>>>>>> so
>>>>>>>> that we can
>>>>>>>> +     * recompute when any port on there changes. */
>>>>>>>> +    uuidset_insert(&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(sync_routes, 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);
>>>>>>>> +            /* We also need to track this LR as we need to
>>>>>>>> recompute
>>>>>>>> when
>>>>>>>> +             * any of its IPs change. */
>>>>>>>> +            uuidset_insert(&data->nb_lr,
>>>>>>>> +                           &lr_stateful_rec->nbr_uuid);
>>>>>>>> +            struct ovn_port_routable_addresses addrs =
>>>>>>>> get_op_addresses(
>>>>>>>> +                port->peer, lr_stateful_rec, false);
>>>>>>> 
>>>>>>> If I understand correctly, the only purpose of the call to
>>>>>>> get_op_addresses is to get NAT addresses with
>>>>>>> "add_route=true"
>>>>>>> option.
>>>>>>> I'm still unsure whether this fits here. With the follow-up
>>>>>>> series
>>>>>>> dedicated to advertising NAT/LB addresses, wouldn't it be
>>>>>>> better
>>>>>>> if NAT
>>>>>>> addresses were exclusively handled in there? i.e. only when a
>>>>>>> dynamic-
>>>>>>> routing-redistribute=nat option is set?
>>>>>> 
>>>>>> Hi Martin,
>>>>>> 
>>>>>> i still see it in the same way as commented on the other patch.
>>>>>> 
>>>>>> Lets assume we have LR1 with LRP1. LRP1 has 192.168.0.1/24
>>>>>> configured.
>>>>>> Also we have LR2 with LRP2. LRP1 and LRP2 are connected
>>>>>> (directly
>>>>>> or via LS)
>>>>>> LRP2 has 192.168.0.10/24 configured. Also LR2 has a nat rule
>>>>>> with
>>>>>> an external
>>>>>> IP of 192.168.0.20 configured.
>>>>>> 
>>>>>> If we enable dynamic-routing on LR1 and redistribute connected
>>>>>> routes we
>>>>>> would get an advertisement of 192.168.0.0/24. This means both
>>>>>> the
>>>>>> LRP
>>>>>> addresses and the NAT addresses are in the scope of the
>>>>>> advertised
>>>>>> route. Traffic to other IPs of that subnet would just be
>>>>>> dropped by
>>>>>> LR1
>>>>>> if it would receive it (as there is no destination).
>>>>>> 
>>>>>> The idea is that the "connected-as-host" setting does not
>>>>>> change
>>>>>> the
>>>>>> reachable addresses in any way. So we still should be able to
>>>>>> reach
>>>>>> both
>>>>>> LRPs and the NAT addresses.
>>>>>> The only change this setting does is how the routes are
>>>>>> advertised.
>>>>>> But
>>>>>> it should not change the behaviour for any routeable address.
>>>>>> 
>>>>> 
>>>>> I tend to agree with Felix on this one.  I think it makes sense
>>>>> that
>>>>> if
>>>>> a NAT/LB IP is part of the router port subnet then redistributing
>>>>> "connected" (either aggregated or as host routes) should include
>>>>> that
>>>>> IP
>>>>> too.
>>> 
>>> Hi Martin,
>>> 
>>>> 
>>>> I see your point and it does make sense. So you propose that
>>>> "connected-as-host" would be the only option that also considers
>>>> NAT/LB/LRP IPs of neighboring routers and "nat"/"lb-vip" options
>>>> would
>>>> control only advertising of NAT/LB addresses configured on the
>>>> "local"
>>>> LR?
>>> 
>>> Yes, that would be my feeling.
>>> 
>>> However that is only based on my assumption that the neighboring
>>> "nat"
>>> and "lb-vip" IPs are actually in the same subnet as the "local" LRP.
>>> I
>> 
>> Would it not? Your implementation seems to go only over neighboring
>> NATs/LBs with "add_route=true", so they should be reachable from the
>> router that advertises them.
>> 
>>> am not sure if we have any reason to announce such IPs if they are in
>>> different subnets.
>>> I guess that would not even work, but i am not sure about that.
>>> 
>> 
>> Yeah, this is a good point, and actually a part about which I'm not
>> sure about either. On one hand, it doesn't sound right to have external
>> NAT IP on a LRP that doesn't belong to any of the LRP subnets. However,
>> that's exactly the test scenario that Frode proposed at the bottom of
>> his email[0]. Maybe he can chime in with more details. It also feels
>> like that the "option:add_route"[1] was created just for this scenario.
>> Otherwise why would neighboring routers need explicit flows for the NAT
>> IP, if it was part of the subnet.
>> 
> 
> Yes, this is also very similar to the case when you have a load balancer
> VIP configured on a router with the VIP value not being part of any of
> the router networks:
> 
> https://mail.openvswitch.org/pipermail/ovs-dev/2025-February/420729.html
> 
> So what if we add a test case in the "Advertise Routes for LB and NAT
> VIPs." series for the LB scenario too?

Yes, the v3 added tests for LBs as well (“route-exchange for LB VIPs”)[0], 
those will have to get adjusted, but I keep them in mind.

Martin.

[0] https://mail.openvswitch.org/pipermail/ovs-dev/2025-February/420556.html

> 
>>>> 
>>>> In my mind I was thinking about these "as equal" in a sense that
>>>> "connected-as-host" would concern only neighboring LRP addresses,
>>>> "nat"
>>>> would deal with NAT external IPs (both local and neighboring) and
>>>> same
>>>> for the "lb-vips". This would give more granular control over which
>>>> addresses are advertised. Though admittedly I'm not sure if there's
>>>> a
>>>> real use-case for this granular control.
>>>> 
>>>> With this implementation (and the above scenario described by
>>>> Felix),
>>>> to achieve that both LR1 and LR2 advertise NAT addresses of LR2,
>>>> they
>>>> would have to have following configuration
>>>>   * LR1: dynamic-routing-redistribute="connected-as-host"
>>>>   * LR2: dynamic-routing-redistribute="nat"
>>>> 
>>>> This kind of "asymmetric" configuration may be bit unexpected, but
>>>> it's
>>>> nothing that couldn't be explained in the documentation.
>>> 
>>> I would find that problematic. Once you assume that both LR1 and LR2
>>> are
>>> actually doing dynamic-routing with different peers outside of OVN
>>> this
>>> gets really confusing.
>> 
>> Ok, it seems we have an agreement then. I'll update my patch series
>> asap.
>> 
>> (Just one note, not sure if you noticed, but I left a small comment
>> regarding the docs in my previous email).
>> 
>> Thanks,
>> Martin.
>> 
>> [0]
>> https://mail.openvswitch.org/pipermail/ovs-dev/2025-January/420169.html
>> [1] https://man7.org/linux/man-pages/man5/ovn-nb.5.html#NAT_TABLE
>> 
>>> 
>>> But that is just my feeling on this one.
>>> 
>>> Thanks a lot,
>>> Felix
>>> 
>>>>  
>>>>> 
>>>>>> 
>>>>>> In contrast to that i would understand the
>>>>>> dynamic-routing-redistribute=nat setting to advertise NAT rules
>>>>>> that are
>>>>>> configured on LR1. Because these would currently not be
>>>>>> announced
>>>>>> in any
>>>>>> way.
>>>>>> 
>>>>>> I hope that clarifies my perspective.
>>>>>> 
>>>>>> Thanks a lot,
>>>>>> Felix
>>>>>> 
>>>>>>> 
>>>>>>> Thanks,
>>>>>>> Martin.
>>>>>>> 
>>>>>>>> +            for (size_t i = 0; i < addrs.n_addrs; i++) {
>>>>>>>> +                publish_lport_addresses(sync_routes,
>>>>>>>> route-
>>>>>>>>> od->sb,
>>>>>>>> +                                        route->out_port,
>>>>>>>> +                                        &addrs.laddrs[i],
>>>>>>>> +                                        port->peer);
>>>>>>>> +            }
>>>>>>>> +            destroy_routable_addresses(&addrs);
>>>>>>>> +        } else {
>>>>>>>> +            /* This is just a plain LSP */
>>>>>>>> +            for (size_t i = 0; i < port->n_lsp_addrs; i++)
>>>>>>>> {
>>>>>>>> +                publish_lport_addresses(sync_routes,
>>>>>>>> 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_data *data)
>>>>>>>>  {
>>>>>>>>      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;
>>>>>>>> @@ -148,9 +337,21 @@ advertised_route_table_sync(
>>>>>>>>          if (!route->od->dynamic_routing) {
>>>>>>>>              continue;
>>>>>>>>          }
>>>>>>>> -        if (route->source == ROUTE_SOURCE_CONNECTED &&
>>>>>>>> -                !route->out_port-
>>>>>>>>> dynamic_routing_connected) {
>>>>>>>> -            continue;
>>>>>>>> +        if (route->source == ROUTE_SOURCE_CONNECTED) {
>>>>>>>> +            if (!route->out_port-
>>>>>>>>> dynamic_routing_connected) {
>>>>>>>> +                continue;
>>>>>>>> +            }
>>>>>>>> +            /* 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 (route->out_port-
>>>>>>>>> dynamic_routing_connected_as_host_routes &&
>>>>>>>> +                !uuidset_contains(&host_route_lrps,
>>>>>>>> lrp_uuid))
>>>>>>>> {
>>>>>>>> +                uuidset_insert(&host_route_lrps,
>>>>>>>> lrp_uuid);
>>>>>>>> +                publish_host_routes(&sync_routes,
>>>>>>>> lr_stateful_table,
>>>>>>>> +                                    route, data);
>>>>>>>> +                continue;
>>>>>>>> +            }
>>>>>>>>          }
>>>>>>>>          if (route->source == ROUTE_SOURCE_STATIC &&
>>>>>>>>                  !route->out_port->dynamic_routing_static)
>>>>>>>> {
>>>>>>>> @@ -160,14 +361,15 @@ advertised_route_table_sync(
>>>>>>>>          char *ip_prefix = normalize_v46_prefix(&route-
>>>>>>>>> prefix,
>>>>>>>>                                                 route-
>>>>>>>>> plen);
>>>>>>>>          route_e = ar_add_entry(&sync_routes, route->od-
>>>>>>>>> sb,
>>>>>>>> -                               route->out_port->sb,
>>>>>>>> ip_prefix);
>>>>>>>> +                               route->out_port->sb,
>>>>>>>> ip_prefix,
>>>>>>>> NULL);
>>>>>>>>      }
>>>>>>>> +    uuidset_destroy(&host_route_lrps);
>>>>>>>>  
>>>>>>>>      SBREC_ADVERTISED_ROUTE_TABLE_FOR_EACH_SAFE (sb_route,
>>>>>>>>                                                 
>>>>>>>> sbrec_advertised_route_table) {
>>>>>>>>          route_e = ar_find(&sync_routes, sb_route-
>>>>>>>>> datapath,
>>>>>>>> -                          sb_route->logical_port,
>>>>>>>> -                          sb_route->ip_prefix);
>>>>>>>> +                          sb_route->logical_port,
>>>>>>>> sb_route-
>>>>>>>>> ip_prefix,
>>>>>>>> +                          sb_route->tracked_port);
>>>>>>>>          if (route_e) {
>>>>>>>>            hmap_remove(&sync_routes, &route_e->hmap_node);
>>>>>>>>            ar_entry_free(route_e);
>>>>>>>> @@ -182,6 +384,7 @@ advertised_route_table_sync(
>>>>>>>>          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);
>>>>>>>> +        sbrec_advertised_route_set_tracked_port(sr,
>>>>>>>> route_e-
>>>>>>>>> tracked_port);
>>>>>>>>          ar_entry_free(route_e);
>>>>>>>>      }
>>>>>>>>  
>>>>>>>> diff --git a/northd/en-advertised-route-sync.h b/northd/en-
>>>>>>>> advertised-route-sync.h
>>>>>>>> index 30e7cae1f..1f24fd329 100644
>>>>>>>> --- a/northd/en-advertised-route-sync.h
>>>>>>>> +++ b/northd/en-advertised-route-sync.h
>>>>>>>> @@ -17,10 +17,21 @@
>>>>>>>>  #define EN_ADVERTISED_ROUTE_SYNC_H 1
>>>>>>>>  
>>>>>>>>  #include "lib/inc-proc-eng.h"
>>>>>>>> +#include "lib/uuidset.h"
>>>>>>>>  
>>>>>>>>  struct advertised_route_sync_data {
>>>>>>>> +  /* Contains the uuids of all NB Logical Routers where we
>>>>>>>> used a
>>>>>>>> +   * lr_stateful_record during computation. */
>>>>>>>> +  struct uuidset nb_lr;
>>>>>>>> +  /* Contains the uuids of all NB Logical Switches where
>>>>>>>> we
>>>>>>>> rely on
>>>>>>>> port
>>>>>>>> +   * changes for host routes. */
>>>>>>>> +  struct uuidset nb_ls;
>>>>>>>>  };
>>>>>>>>  
>>>>>>>> +bool
>>>>>>>> advertised_route_sync_lr_stateful_change_handler(struct
>>>>>>>> engine_node *,
>>>>>>>> +                                                      void
>>>>>>>> *data);
>>>>>>>> +bool advertised_route_sync_northd_change_handler(struct
>>>>>>>> engine_node
>>>>>>>> *,
>>>>>>>> +                                                 void
>>>>>>>> *data);
>>>>>>>>  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 fa7ca6f2d..86b7b999e 100644
>>>>>>>> --- a/northd/inc-proc-northd.c
>>>>>>>> +++ b/northd/inc-proc-northd.c
>>>>>>>> @@ -284,6 +284,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,
>>>>>>>>                       NULL);
>>>>>>>> +    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);
>>>>>>>>  
>>>>>>>>      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 5cbf6c800..3f14cc75c 100644
>>>>>>>> --- a/northd/northd.c
>>>>>>>> +++ b/northd/northd.c
>>>>>>>> @@ -1122,19 +1122,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.
>>>>>>>> @@ -1169,7 +1156,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++) {
>>>>>>>> @@ -1182,12 +1169,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) {
>>>>>>>> @@ -1220,6 +1209,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,
>>>>>>>> @@ -2267,6 +2263,9 @@ join_logical_ports_lrp(struct hmap
>>>>>>>> *ports,
>>>>>>>>  
>>>>>>>>      op->prefix_delegation = smap_get_bool(&op->nbrp-
>>>>>>>>> options,
>>>>>>>>                                           
>>>>>>>> "prefix_delegation",
>>>>>>>> false);
>>>>>>>> +    op->dynamic_routing_connected_as_host_routes =
>>>>>>>> smap_get_bool(
>>>>>>>> +        &op->nbrp->options,
>>>>>>>> +        "dynamic-routing-connected-as-host-routes",
>>>>>>>> false);
>>>>>>>>      parse_dynamic_routing_redistribute(&op->nbrp->options,
>>>>>>>>                                         &op-
>>>>>>>>> dynamic_routing_connected,
>>>>>>>>                                         od-
>>>>>>>>> dynamic_routing_connected,
>>>>>>>> diff --git a/northd/northd.h b/northd/northd.h
>>>>>>>> index 75a3df617..15bd01c05 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 */
>>>>>>>> @@ -625,6 +626,8 @@ struct ovn_port {
>>>>>>>>       * If the option is unset it will be initialized based
>>>>>>>> on
>>>>>>>> the
>>>>>>>> nbr
>>>>>>>>       * option. */
>>>>>>>>      bool dynamic_routing_connected;
>>>>>>>> +    /* nbrp option "dynamic-routing-connected-as-host-
>>>>>>>> routes"
>>>>>>>> is
>>>>>>>> "true". */
>>>>>>>> +    bool dynamic_routing_connected_as_host_routes;
>>>>>>>>      /* nbrp option "dynamic-routing-redistribute" contains
>>>>>>>> "static".
>>>>>>>>       * If the option is unset it will be initialized based
>>>>>>>> on
>>>>>>>> the
>>>>>>>> nbr
>>>>>>>>       * option. */
>>>>>>>> @@ -935,4 +938,23 @@ void build_igmp_lflows(struct hmap
>>>>>>>> *igmp_groups,
>>>>>>>>                         const struct hmap *ls_datapaths,
>>>>>>>>                         struct lflow_table *lflows,
>>>>>>>>                         struct lflow_ref *lflow_ref);
>>>>>>>> +/* 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 bf785e4d3..d0bdb5058 100644
>>>>>>>> --- a/ovn-nb.xml
>>>>>>>> +++ b/ovn-nb.xml
>>>>>>>> @@ -3752,6 +3752,33 @@ or
>>>>>>>>          key="dynamic-routing-redistribute"
>>>>>>>> table="Logical_Router"/>
>>>>>>>> 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.
>>>>>>>> +
>>>>>>>> +        If set to true 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. Default
>>>>>>>> is
>>>>>>>> false.
>>>> 
>>>> With the discussion above in mind, I think this documentation could
>>>> add
>>>> a note that it includes NAT/LB VIPs as well.
>>>> 
>>>> Thanks,
>>>> Martin. 
>>>> 
>>>>>>>> +
>>>>>>>> +        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/tests/ovn-northd.at b/tests/ovn-northd.at
>>>>>>>> index 52a458e35..18d367fa5 100644
>>>>>>>> --- a/tests/ovn-northd.at
>>>>>>>> +++ b/tests/ovn-northd.at
>>>>>>>> @@ -14845,6 +14845,66 @@ 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.
>>>>>>>> +# LRP 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-
>>>>>>>> redistribute="connected;static"
>>>>>>>> +check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01
>>>>>>>> 10.0.0.1/24
>>>>>>>> +sw0=$(fetch_column port_binding _uuid logical_port=lr0-
>>>>>>>> sw0)
>>>>>>>> +check ovn-nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02
>>>>>>>> 10.0.1.1/24
>>>>>>>> +sw1=$(fetch_column port_binding _uuid logical_port=lr0-
>>>>>>>> sw1)
>>>>>>>> +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=$(fetch_column datapath_binding _uuid
>>>>>>>> external_ids:name=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 Advertised_Route 2
>>>>>>>> +check_column 10.0.0.1/32 Advertised_Route ip_prefix
>>>>>>>> datapath=$datapath logical_port=$sw0
>>>>>>>> +check_column $sw0 Advertised_Route tracked_port
>>>>>>>> datapath=$datapath
>>>>>>>> logical_port=$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"
>>>>>>>> +vif0=$(fetch_column port_binding _uuid logical_port=sw0-
>>>>>>>> vif0)
>>>>>>>> +check_row_count Advertised_Route 3
>>>>>>>> +check_row_count Advertised_Route 2 tracked_port!='[[]]'
>>>>>>>> +check_column $vif0 Advertised_Route tracked_port
>>>>>>>> datapath=$datapath
>>>>>>>> logical_port=$sw0 ip_prefix=10.0.0.2/32
>>>>>>>> +
>>>>>>>> +# 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=$(fetch_column port_binding _uuid logical_port=lr1-
>>>>>>>> sw0)
>>>>>>>> +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!='[[]]'
>>>>>>>> +check_column $lr1 Advertised_Route tracked_port
>>>>>>>> datapath=$datapath
>>>>>>>> logical_port=$sw0 ip_prefix=10.0.0.10/32
>>>>>>>> +
>>>>>>>> +# 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!='[[]]'
>>>>>>>> +check_column $lr1 Advertised_Route tracked_port
>>>>>>>> datapath=$datapath
>>>>>>>> logical_port=$sw0 ip_prefix=10.0.0.100/32
>>>>>>>> +
>>>>>>>> +# 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!='[[]]'
>>>>>>>> +check_row_count Advertised_Route 1 datapath=$datapath
>>>>>>>> logical_port=$sw0 ip_prefix=172.16.0.0/24
>>>>>>>> +
>>>>>>>> +AT_CLEANUP
>>>>>>>> +])
>>>>>>>> +
>>>>>>>>  OVN_FOR_EACH_NORTHD_NO_HV([
>>>>>>>>  AT_SETUP([dynamic-routing incremental processing])
>>>>>>>>  AT_KEYWORDS([dynamic-routing])
>>>>>>>> @@ -14868,13 +14928,16 @@ check_engine_stats lflow
>>>>>>>> recompute
>>>>>>>> nocompute
>>>>>>>>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>>  
>>>>>>>>  check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> -check ovn-nbctl --wait=sb lrp-add lr0 lr0-sw0
>>>>>>>> 00:00:00:00:ff:01
>>>>>>>> 10.0.0.1/24
>>>>>>>> +check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01
>>>>>>>> 10.0.0.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
>>>>>>>>  sw0=$(fetch_column port_binding _uuid logical_port=lr0-
>>>>>>>> sw0)
>>>>>>>>  check_engine_stats northd recompute compute
>>>>>>>> -check_engine_stats routes recompute nocompute
>>>>>>>> -check_engine_stats advertised_route_sync recompute
>>>>>>>> nocompute
>>>>>>>> -check_engine_stats learned_route_sync recompute nocompute
>>>>>>>> -check_engine_stats lflow recompute nocompute
>>>>>>>> +check_engine_stats routes recompute compute
>>>>>>>> +check_engine_stats advertised_route_sync recompute compute
>>>>>>>> +check_engine_stats learned_route_sync recompute compute
>>>>>>>> +check_engine_stats lflow recompute compute
>>>>>>>>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>>  
>>>>>>>>  check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> @@ -14980,6 +15043,46 @@ check_engine_stats
>>>>>>>> learned_route_sync
>>>>>>>> recompute nocompute
>>>>>>>>  check_engine_stats lflow recompute nocompute
>>>>>>>>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>>  
>>>>>>>> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> +check ovn-nbctl --wait=sb set Logical_Router_Port lr0-sw0
>>>>>>>> options:dynamic-routing-connected-as-host-routes=true
>>>>>>>> +check_engine_stats northd recompute nocompute
>>>>>>>> +check_engine_stats routes recompute nocompute
>>>>>>>> +check_engine_stats advertised_route_sync recompute
>>>>>>>> nocompute
>>>>>>>> +check_engine_stats learned_route_sync recompute nocompute
>>>>>>>> +check_engine_stats lflow recompute nocompute
>>>>>>>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>> +
>>>>>>>> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> +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_engine_stats northd norecompute compute
>>>>>>>> +check_engine_stats routes norecompute compute
>>>>>>>> +check_engine_stats advertised_route_sync recompute
>>>>>>>> nocompute
>>>>>>>> +check_engine_stats learned_route_sync norecompute compute
>>>>>>>> +check_engine_stats lflow norecompute compute
>>>>>>>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>> +
>>>>>>>> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> +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_engine_stats northd recompute compute
>>>>>>>> +check_engine_stats routes recompute compute
>>>>>>>> +check_engine_stats advertised_route_sync recompute
>>>>>>>> nocompute
>>>>>>>> +check_engine_stats learned_route_sync recompute compute
>>>>>>>> +check_engine_stats lflow recompute compute
>>>>>>>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>> +
>>>>>>>> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>> +check ovn-nbctl --wait=sb lr-nat-add lr1 dnat_and_snat
>>>>>>>> 10.0.0.100
>>>>>>>> 192.168.0.1
>>>>>>>> +check_engine_stats northd norecompute compute
>>>>>>>> +check_engine_stats routes norecompute compute
>>>>>>>> +check_engine_stats advertised_route_sync recompute
>>>>>>>> nocompute
>>>>>>>> +check_engine_stats learned_route_sync norecompute compute
>>>>>>>> +check_engine_stats lflow norecompute compute
>>>>>>>> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
>>>>>>>> +
>>>>>>>>  check as northd ovn-appctl -t ovn-northd inc-engine/clear-
>>>>>>>> stats
>>>>>>>>  check ovn-nbctl --wait=sb lrp-del lr0-sw0
>>>>>>>>  check_engine_stats northd recompute compute
>>>>>>> 
>>>>>>> _______________________________________________
>>>>>>> dev mailing list
>>>>>>> [email protected]
>>>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>>>> _______________________________________________
>>>>>> dev mailing list
>>>>>> [email protected]
>>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>>> 
>>>> 
>> 
> 

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

Reply via email to