On Thu, Jul 31, 2025 at 04:08:58PM +0200, Ales Musil wrote:
> When "connected-as-host" was configured for option
> "dynamic-routing-redistribute" OVN would attempt to advertise also
> NATs and LBs connected to that LRP. Prevent that by advertising only
> the LRP networks. This also prevents commit fail loop when
> "connected-as-host" and "nat" are used at the same time. Also fix
> the case when there is "conflict" between LRP IP and SNAT. In
> that case honor the LRP IP advertised route.
> 
> Fixes: 93f541f342f9 ("northd: Allow announcing individual host routes.")
> Reported-at: https://issues.redhat.com/browse/FDP-1564
> Signed-off-by: Ales Musil <amu...@redhat.com>
> ---

Acked-By: Felix Huettner <felix.huettner@stackit.cloud>

> v2: Rebase on top of latest main.
>     Make sure the tracked_port is properly set back if needed.
> ---
>  northd/en-advertised-route-sync.c | 87 ++++++++++++-------------------
>  tests/ovn-northd.at               | 16 +++---
>  tests/system-ovn.at               |  4 +-
>  3 files changed, 42 insertions(+), 65 deletions(-)
> 
> diff --git a/northd/en-advertised-route-sync.c 
> b/northd/en-advertised-route-sync.c
> index 6c653529b..e75ab15c5 100644
> --- a/northd/en-advertised-route-sync.c
> +++ b/northd/en-advertised-route-sync.c
> @@ -127,7 +127,6 @@ static void
>  advertised_route_table_sync(
>      struct ovsdb_idl_txn *ovnsb_txn,
>      const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
> -    const struct lr_stateful_table *lr_stateful_table,
>      const struct hmap *routes,
>      const struct hmap *dynamic_routes,
>      struct advertised_route_sync_data *data);
> @@ -245,14 +244,11 @@ en_advertised_route_sync_run(struct engine_node *node, 
> void *data OVS_UNUSED)
>      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,
> -                                &lr_stateful_data->table,
>                                  &routes_data->parsed_routes,
>                                  &dynamic_routes_data->routes,
>                                  routes_sync_data);
> @@ -564,40 +560,10 @@ publish_lport_addresses(struct hmap *sync_routes,
>      }
>  }
>  
> -/* Collect all IP addresses connected via this LRP. */
> -static void
> -publish_host_routes_lrp(struct hmap *sync_routes,
> -                        const struct lr_stateful_table *lr_stateful_table,
> -                        const struct ovn_datapath *advertising_od,
> -                        const struct ovn_port *advertising_op,
> -                        struct advertised_route_sync_data *data,
> -                        const struct ovn_port *lrp)
> -{
> -    /* This is a LSP connected to an LRP */
> -    const struct lport_addresses *addresses = &lrp->lrp_networks;
> -    publish_lport_addresses(sync_routes, advertising_od,
> -                            advertising_op, addresses, lrp);
> -
> -    const struct lr_stateful_record *lr_stateful_rec;
> -    lr_stateful_rec =
> -        lr_stateful_table_find_by_index(lr_stateful_table, lrp->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(lrp, lr_stateful_rec, false);
> -    for (size_t i = 0; i < addrs.n_addrs; i++) {
> -        publish_lport_addresses(sync_routes, advertising_od,
> -                                advertising_op, &addrs.laddrs[i], lrp);
> -    }
> -    destroy_routable_addresses(&addrs);
> -}
> -
>  /* 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 ovn_datapath *advertising_od,
>                      const struct ovn_port *advertising_op,
>                      struct advertised_route_sync_data *data)
> @@ -613,8 +579,9 @@ publish_host_routes(struct hmap *sync_routes,
>  
>      if (peer_od->nbr) {
>          /* This is a LRP directly connected to another LRP. */
> -        publish_host_routes_lrp(sync_routes, lr_stateful_table, 
> advertising_od,
> -                                advertising_op, data, advertising_op->peer);
> +        const struct ovn_port *lrp = advertising_op->peer;
> +        publish_lport_addresses(sync_routes, advertising_od,
> +                                advertising_op, &lrp->lrp_networks, lrp);
>          return;
>      }
>  
> @@ -626,9 +593,9 @@ publish_host_routes(struct hmap *sync_routes,
>      HMAP_FOR_EACH (port, dp_node, &peer_od->ports) {
>          if (port->peer && port->peer->nbrp) {
>              /* This is a LSP connected to an LRP */
> -            publish_host_routes_lrp(sync_routes, lr_stateful_table,
> -                                    advertising_od, advertising_op,
> -                                    data, port->peer);
> +            const struct ovn_port *lrp = port->peer;
> +            publish_lport_addresses(sync_routes, advertising_od,
> +                                    advertising_op, &lrp->lrp_networks, lrp);
>          } else {
>              /* This is just a plain LSP */
>              for (size_t i = 0; i < port->n_lsp_addrs; i++) {
> @@ -688,7 +655,6 @@ should_advertise_route(const struct uuidset 
> *host_route_lrps,
>   */
>  static bool
>  process_prereqs_advertise_route(
> -    const struct lr_stateful_table *lr_stateful_table,
>      struct advertised_route_sync_data *data,
>      struct uuidset *host_route_lrps,
>      struct hmap *sync_routes,
> @@ -705,8 +671,7 @@ process_prereqs_advertise_route(
>          if (drr_mode_CONNECTED_AS_HOST_is_set(drr)) {
>              const struct uuid *lrp_uuid = 
> &advertising_op->nbrp->header_.uuid;
>              uuidset_insert(host_route_lrps, lrp_uuid);
> -            publish_host_routes(sync_routes, lr_stateful_table,
> -                                advertising_od, advertising_op,
> +            publish_host_routes(sync_routes, advertising_od, advertising_op,
>                                  data);
>              return true;
>          }
> @@ -748,7 +713,6 @@ static void
>  advertised_route_table_sync(
>      struct ovsdb_idl_txn *ovnsb_txn,
>      const struct sbrec_advertised_route_table *sbrec_advertised_route_table,
> -    const struct lr_stateful_table *lr_stateful_table,
>      const struct hmap *routes,
>      const struct hmap *dynamic_routes,
>      struct advertised_route_sync_data *data)
> @@ -772,9 +736,9 @@ advertised_route_table_sync(
>              continue;
>          }
>  
> -        if (process_prereqs_advertise_route(lr_stateful_table, data,
> -                                            &host_route_lrps, &sync_routes,
> -                                            route->od, route->out_port,
> +        if (process_prereqs_advertise_route(data, &host_route_lrps,
> +                                            &sync_routes, route->od,
> +                                            route->out_port,
>                                              route->tracked_port,
>                                              route->source)) {
>              continue;
> @@ -794,14 +758,22 @@ advertised_route_table_sync(
>              continue;
>          }
>  
> -        if (process_prereqs_advertise_route(lr_stateful_table, data,
> -                                            &host_route_lrps, &sync_routes,
> -                                            route_e->od, route_e->op,
> -                                            route_e->tracked_port,
> +        if (process_prereqs_advertise_route(data, &host_route_lrps,
> +                                            &sync_routes, route_e->od,
> +                                            route_e->op, 
> route_e->tracked_port,
>                                              route_e->source)) {
>              continue;
>          }
>  
> +        const struct sbrec_port_binding *tracked_pb =
> +            route_e->tracked_port ? route_e->tracked_port->sb : NULL;
> +        if (ar_entry_find(&sync_routes, route_e->od->sb, route_e->op->sb,
> +                          route_e->ip_prefix, tracked_pb)) {
> +            /* We could already have advertised route entry for LRP IP that
> +             * corresponds to "snat" when "connected-as-host" is combined
> +             * with "nat". Skip it. */
> +            continue;
> +        }
>          ar_entry_add(&sync_routes, route_e->od, route_e->op,
>                       route_e->ip_prefix, route_e->tracked_port,
>                       route_e->source);
> @@ -814,12 +786,17 @@ advertised_route_table_sync(
>          route_e = ar_entry_find(&sync_routes, sb_route->datapath,
>                                  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);
> -        } else {
> -          sbrec_advertised_route_delete(sb_route);
> +        if (!route_e) {
> +            sbrec_advertised_route_delete(sb_route);
> +            continue;
>          }
> +
> +        if (route_e->tracked_port && !sb_route->tracked_port) {
> +            sbrec_advertised_route_set_tracked_port(
> +                sb_route, route_e->tracked_port->sb);
> +        }
> +        hmap_remove(&sync_routes, &route_e->hmap_node);
> +        ar_entry_free(route_e);
>      }
>  
>      HMAP_FOR_EACH_POP (route_e, hmap_node, &sync_routes) {
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 5ddb15587..ec7009b28 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -15545,7 +15545,7 @@ 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-redistribute="connected-as-host,static"
> +    options:dynamic-routing-redistribute="connected-as-host,static,nat"
>  check_row_count Advertised_Route 2
>  check_column 10.0.0.1 Advertised_Route ip_prefix \
>      datapath=$datapath logical_port=$sw0
> @@ -15577,14 +15577,14 @@ check_column $lr1 Advertised_Route tracked_port \
>  # 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 \
> +check_row_count Advertised_Route 3 tracked_port!='[[]]'
> +check_column '' Advertised_Route tracked_port \
>      datapath=$datapath logical_port=$sw0 ip_prefix=10.0.0.100
>  
>  # 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 3 tracked_port!='[[]]'
>  check_row_count Advertised_Route 1 datapath=$datapath logical_port=$sw0 \
>      ip_prefix=172.16.0.0/24
>  
> @@ -15593,16 +15593,16 @@ check_row_count Advertised_Route 1 
> datapath=$datapath logical_port=$sw0 \
>  check ovn-nbctl lr-add lr2
>  check ovn-nbctl lrp-add lr0 lr0-lr2 00:00:00:02:ff:01 10.10.0.1/24 
> peer=lr2-lr0
>  check ovn-nbctl set Logical_Router_Port lr0-lr2 \
> -    options:dynamic-routing-redistribute="connected-as-host,static"
> +    options:dynamic-routing-redistribute="connected-as-host,static,nat"
>  lr0lr2=$(fetch_column port_binding _uuid logical_port=lr0-lr2)
>  check ovn-nbctl lrp-add lr2 lr2-lr0 00:00:00:02:ff:02 10.10.0.2/24 
> peer=lr0-lr2
>  lr2lr0=$(fetch_column port_binding _uuid logical_port=lr2-lr0)
>  check ovn-nbctl lrp-add lr2 lr2-sw1 00:00:00:02:ff:03 10.11.0.1/24
>  check ovn-nbctl --wait=sb lr-nat-add lr2 dnat_and_snat 10.10.0.20 10.20.0.123
>  check_row_count Advertised_Route 8
> -check_row_count Advertised_Route 6 tracked_port!='[[]]'
> +check_row_count Advertised_Route 4 tracked_port!='[[]]'
>  check_row_count Advertised_Route 1 datapath=$datapath logical_port=$lr0lr2 \
> -    ip_prefix=10.10.0.20 tracked_port=$lr2lr0
> +    ip_prefix=10.10.0.20 tracked_port='[[]]'
>  
>  # Add a directly connected switch and make sure that northd is not confused.
>  # The IP on a switch-switch port should be advertised.
> @@ -15615,7 +15615,7 @@ check ovn-nbctl --wait=sb lsp-set-addresses sw0-sw1 \
>      "11:aa:bb:cc:dd:ee 10.0.0.42"
>  sw0sw1=$(fetch_column port_binding _uuid logical_port=sw0-sw1)
>  check_row_count Advertised_Route 9
> -check_row_count Advertised_Route 7 tracked_port!='[[]]'
> +check_row_count Advertised_Route 5 tracked_port!='[[]]'
>  check_column $sw0sw1 Advertised_Route tracked_port \
>      datapath=$datapath logical_port=$sw0 ip_prefix=10.0.0.42
>  
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index e0407383a..e99cf6f3d 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -16125,7 +16125,7 @@ blackhole 198.51.100.0/24 proto ovn metric 1000])
>  # The last 3 of them are local to the current chassis so we expect a better
>  # prio.
>  check ovn-nbctl --wait=hv set Logical_Router_Port internet-public \
> -    options:dynamic-routing-redistribute="connected-as-host,static"
> +    options:dynamic-routing-redistribute="connected-as-host,static,nat"
>  
>  OVN_ROUTE_EQUAL([ovnvrf1337], [dnl
>  blackhole 192.0.2.1 proto ovn metric 1000
> @@ -16485,7 +16485,7 @@ blackhole 198.51.100.0/24 proto ovn metric 1000])
>  # The last 3 of them are local to the current chassis so we expect a better
>  # prio.
>  check ovn-nbctl --wait=hv set Logical_Router_Port internet-public \
> -    options:dynamic-routing-redistribute="connected-as-host,static"
> +    options:dynamic-routing-redistribute="connected-as-host,static,nat"
>  
>  OVN_ROUTE_EQUAL([ovnvrf1337], [dnl
>  blackhole 192.0.2.1 proto ovn metric 100
> -- 
> 2.50.0
> 
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to