On Fri, Jul 18, 2025 at 6:15 PM Mark Michelson via dev <
ovs-dev@openvswitch.org> wrote:

> Reported-at: https://issues.redhat.com/browse/FDP-1522
> Reported-at: https://issues.redhat.com/browse/FDP-1523
>
> Signed-off-by: Mark Michelson <mmich...@redhat.com>
> ---
>  northd/en-datapath-logical-router.c | 131 ++++++++++++++++++++++++++--
>  northd/en-datapath-logical-router.h |  16 +++-
>  northd/en-datapath-logical-switch.c | 127 +++++++++++++++++++++++++--
>  northd/en-datapath-logical-switch.h |  14 +++
>  northd/inc-proc-northd.c            |   8 +-
>  tests/ovn-northd.at                 |  53 +++++++++++
>  6 files changed, 332 insertions(+), 17 deletions(-)
>
> diff --git a/northd/en-datapath-logical-router.c
> b/northd/en-datapath-logical-router.c
> index 8a9adbc4f..a174e8abe 100644
> --- a/northd/en-datapath-logical-router.c
> +++ b/northd/en-datapath-logical-router.c
> @@ -230,12 +230,30 @@ en_datapath_logical_router_cleanup(void *data)
>      ovn_unsynced_datapath_map_destroy(map);
>  }
>
> +struct ovn_synced_logical_router *
> +ovn_synced_logical_router_find(const struct ovn_synced_logical_router_map
> *map,
> +                               const struct uuid *nb_uuid)
> +{
> +    struct ovn_synced_logical_router *lr;
> +    HMAP_FOR_EACH_WITH_HASH (lr, hmap_node, uuid_hash(nb_uuid),
> +                             &map->synced_routers) {
> +        if (uuid_equals(&lr->nb->header_.uuid, nb_uuid)) {
> +            return lr;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
>  static void
>  synced_logical_router_map_init(
>      struct ovn_synced_logical_router_map *router_map)
>  {
>      *router_map = (struct ovn_synced_logical_router_map) {
>          .synced_routers = HMAP_INITIALIZER(&router_map->synced_routers),
> +        .new = HMAPX_INITIALIZER(&router_map->new),
> +        .updated = HMAPX_INITIALIZER(&router_map->updated),
> +        .deleted = HMAPX_INITIALIZER(&router_map->deleted),
>      };
>  }
>
> @@ -243,7 +261,17 @@ static void
>  synced_logical_router_map_destroy(
>      struct ovn_synced_logical_router_map *router_map)
>  {
> +    hmapx_destroy(&router_map->new);
> +    hmapx_destroy(&router_map->updated);
> +
> +    struct hmapx_node *node;
>      struct ovn_synced_logical_router *lr;
> +    HMAPX_FOR_EACH_SAFE (node, &router_map->deleted) {
> +        lr = node->data;
> +        free(lr);
> +        hmapx_delete(&router_map->deleted, node);
> +    }
> +    hmapx_destroy(&router_map->deleted);
>      HMAP_FOR_EACH_POP (lr, hmap_node, &router_map->synced_routers) {
>          free(lr);
>      }
> @@ -261,6 +289,18 @@ en_datapath_synced_logical_router_init(struct
> engine_node *node OVS_UNUSED,
>      return router_map;
>  }
>
> +static struct ovn_synced_logical_router *
> +synced_logical_router_alloc(const struct ovn_synced_datapath *sdp)
> +{
> +    struct ovn_synced_logical_router *lr = xmalloc(sizeof *lr);
> +    *lr = (struct ovn_synced_logical_router) {
> +        .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_router,
> +                           header_),
> +        .sb = sdp->sb_dp,
> +    };
> +    return lr;
> +}
> +
>  enum engine_node_state
>  en_datapath_synced_logical_router_run(struct engine_node *node , void
> *data)
>  {
> @@ -276,12 +316,8 @@ en_datapath_synced_logical_router_run(struct
> engine_node *node , void *data)
>          if (sdp->nb_row->table->class_ != &nbrec_table_logical_router) {
>              continue;
>          }
> -        struct ovn_synced_logical_router *lr = xmalloc(sizeof *lr);
> -        *lr = (struct ovn_synced_logical_router) {
> -            .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_router,
> -                               header_),
> -            .sb = sdp->sb_dp,
> -        };
> +        struct ovn_synced_logical_router *lr =
> +            synced_logical_router_alloc(sdp);
>          hmap_insert(&router_map->synced_routers, &lr->hmap_node,
>                      uuid_hash(&lr->nb->header_.uuid));
>      }
> @@ -289,6 +325,89 @@ en_datapath_synced_logical_router_run(struct
> engine_node *node , void *data)
>      return EN_UPDATED;
>  }
>
> +void
> +en_datapath_synced_logical_router_clear_tracked_data(void *data)
> +{
> +    struct ovn_synced_logical_router_map *router_map = data;
> +
> +    hmapx_clear(&router_map->new);
> +    hmapx_clear(&router_map->updated);
> +
> +    struct hmapx_node *node;
> +    HMAPX_FOR_EACH_SAFE (node, &router_map->deleted) {
> +        struct ovn_synced_logical_router *lr = node->data;
> +        free(lr);
> +        hmapx_delete(&router_map->deleted, node);
> +    }
> +}
> +
> +enum engine_input_handler_result
> +en_datapath_synced_logical_router_datapath_sync_handler(
> +        struct engine_node *node, void *data)
> +{
> +    const struct ovn_synced_datapaths *dps =
> +        engine_get_input_data("datapath_sync", node);
> +    struct ovn_synced_logical_router_map *router_map = data;
> +
> +    if (hmapx_is_empty(&dps->deleted) &&
> +        hmapx_is_empty(&dps->new) &&
> +        hmapx_is_empty(&dps->updated)) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    enum engine_input_handler_result result = EN_HANDLED_UNCHANGED;
> +
> +    struct hmapx_node *hmapx_node;
> +    struct ovn_synced_datapath *sdp;
> +    struct ovn_synced_logical_router *lr;
> +    HMAPX_FOR_EACH (hmapx_node, &dps->new) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_router) {
> +            continue;
> +        }
> +        lr = synced_logical_router_alloc(sdp);
> +        hmap_insert(&router_map->synced_routers, &lr->hmap_node,
> +                    uuid_hash(&lr->nb->header_.uuid));
> +        hmapx_add(&router_map->new, lr);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +    HMAPX_FOR_EACH (hmapx_node, &dps->deleted) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_router) {
> +            continue;
> +        }
> +        lr = ovn_synced_logical_router_find(router_map,
> &sdp->nb_row->uuid);
> +        if (!lr) {
> +            return EN_UNHANDLED;
> +        }
> +        hmap_remove(&router_map->synced_routers, &lr->hmap_node);
> +        hmapx_add(&router_map->deleted, lr);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +    HMAPX_FOR_EACH (hmapx_node, &dps->updated) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_router) {
> +            continue;
> +        }
> +        lr = ovn_synced_logical_router_find(router_map,
> &sdp->nb_row->uuid);
> +        if (!lr) {
> +            return EN_UNHANDLED;
> +        }
> +        lr->nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_router,
> +                              header_);
> +        lr->sb = sdp->sb_dp;
> +        hmap_remove(&router_map->synced_routers, &lr->hmap_node);
> +        free(lr);
> +        lr = synced_logical_router_alloc(sdp);
> +        hmap_insert(&router_map->synced_routers, &lr->hmap_node,
> +                    uuid_hash(&lr->nb->header_.uuid));
> +        hmapx_add(&router_map->updated, lr);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +
> +    return result;
> +}
> +
>  void en_datapath_synced_logical_router_cleanup(void *data)
>  {
>      struct ovn_synced_logical_router_map *router_map = data;
> diff --git a/northd/en-datapath-logical-router.h
> b/northd/en-datapath-logical-router.h
> index fa2bf798f..555dd41e8 100644
> --- a/northd/en-datapath-logical-router.h
> +++ b/northd/en-datapath-logical-router.h
> @@ -19,6 +19,7 @@
>
>  #include "lib/inc-proc-eng.h"
>  #include "openvswitch/hmap.h"
> +#include "lib/hmapx.h"
>
>  void *en_datapath_logical_router_init(struct engine_node *,
>                                        struct engine_arg *);
> @@ -36,14 +37,27 @@ struct ovn_synced_logical_router {
>
>  struct ovn_synced_logical_router_map {
>      struct hmap synced_routers;
> +
> +    bool has_tracked_data;
> +    struct hmapx new;
> +    struct hmapx updated;
> +    struct hmapx deleted;
>  };
>
> +struct uuid;
> +struct ovn_synced_logical_router *
> +ovn_synced_logical_router_find(const struct ovn_synced_logical_router_map
> *map,
> +                               const struct uuid *nb_uuid);
> +
>  void *en_datapath_synced_logical_router_init(struct engine_node *,
>                                               struct engine_arg *);
>
>  enum engine_node_state en_datapath_synced_logical_router_run(
>      struct engine_node *, void *data);
> -
> +void en_datapath_synced_logical_router_clear_tracked_data(void *data);
> +enum engine_input_handler_result
> +en_datapath_synced_logical_router_datapath_sync_handler(
> +        struct engine_node *node, void *data);
>  void en_datapath_synced_logical_router_cleanup(void *data);
>
>  enum engine_input_handler_result
> diff --git a/northd/en-datapath-logical-switch.c
> b/northd/en-datapath-logical-switch.c
> index 83d065dae..decdb4006 100644
> --- a/northd/en-datapath-logical-switch.c
> +++ b/northd/en-datapath-logical-switch.c
> @@ -198,12 +198,30 @@ en_datapath_logical_switch_cleanup(void *data)
>      ovn_unsynced_datapath_map_destroy(map);
>  }
>
> +struct ovn_synced_logical_switch *
> +ovn_synced_logical_switch_find(const struct ovn_synced_logical_switch_map
> *map,
> +                               const struct uuid *nb_uuid)
> +{
> +    struct ovn_synced_logical_switch *lsw;
> +    HMAP_FOR_EACH_WITH_HASH (lsw, hmap_node, uuid_hash(nb_uuid),
> +                             &map->synced_switches) {
> +        if (uuid_equals(&lsw->nb->header_.uuid, nb_uuid)) {
> +            return lsw;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
>  static void
>  synced_logical_switch_map_init(
>      struct ovn_synced_logical_switch_map *switch_map)
>  {
>      *switch_map = (struct ovn_synced_logical_switch_map) {
>          .synced_switches = HMAP_INITIALIZER(&switch_map->synced_switches),
> +        .new = HMAPX_INITIALIZER(&switch_map->new),
> +        .updated = HMAPX_INITIALIZER(&switch_map->updated),
> +        .deleted = HMAPX_INITIALIZER(&switch_map->deleted),
>      };
>  }
>
> @@ -211,7 +229,17 @@ static void
>  synced_logical_switch_map_destroy(
>      struct ovn_synced_logical_switch_map *switch_map)
>  {
> +    hmapx_destroy(&switch_map->new);
> +    hmapx_destroy(&switch_map->updated);
> +
> +    struct hmapx_node *node;
>      struct ovn_synced_logical_switch *ls;
> +    HMAPX_FOR_EACH_SAFE (node, &switch_map->deleted) {
> +        ls = node->data;
> +        free(ls);
> +        hmapx_delete(&switch_map->deleted, node);
> +    }
> +    hmapx_destroy(&switch_map->deleted);
>      HMAP_FOR_EACH_POP (ls, hmap_node, &switch_map->synced_switches) {
>          free(ls);
>      }
> @@ -229,6 +257,18 @@ en_datapath_synced_logical_switch_init(struct
> engine_node *node OVS_UNUSED,
>      return switch_map;
>  }
>
> +static struct ovn_synced_logical_switch *
> +synced_logical_switch_alloc(const struct ovn_synced_datapath *sdp)
> +{
> +    struct ovn_synced_logical_switch *lsw = xmalloc(sizeof *lsw);
> +    *lsw = (struct ovn_synced_logical_switch) {
> +        .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_switch,
> +                           header_),
> +        .sb = sdp->sb_dp,
> +    };
> +    return lsw;
> +}
> +
>  enum engine_node_state
>  en_datapath_synced_logical_switch_run(struct engine_node *node , void
> *data)
>  {
> @@ -244,12 +284,8 @@ en_datapath_synced_logical_switch_run(struct
> engine_node *node , void *data)
>          if (sdp->nb_row->table->class_ != &nbrec_table_logical_switch) {
>              continue;
>          }
> -        struct ovn_synced_logical_switch *lsw = xmalloc(sizeof *lsw);
> -        *lsw = (struct ovn_synced_logical_switch) {
> -            .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_switch,
> -                               header_),
> -            .sb = sdp->sb_dp,
> -        };
> +        struct ovn_synced_logical_switch *lsw =
> +            synced_logical_switch_alloc(sdp);
>          hmap_insert(&switch_map->synced_switches, &lsw->hmap_node,
>                      uuid_hash(&lsw->nb->header_.uuid));
>      }
> @@ -257,6 +293,85 @@ en_datapath_synced_logical_switch_run(struct
> engine_node *node , void *data)
>      return EN_UPDATED;
>  }
>
> +void
> +en_datapath_synced_logical_switch_clear_tracked_data(void *data)
> +{
> +    struct ovn_synced_logical_switch_map *switch_map = data;
> +
> +    hmapx_clear(&switch_map->new);
> +    hmapx_clear(&switch_map->updated);
> +
> +    struct hmapx_node *node;
> +    HMAPX_FOR_EACH_SAFE (node, &switch_map->deleted) {
> +        struct ovn_synced_logical_router *lr = node->data;
> +        free(lr);
> +        hmapx_delete(&switch_map->deleted, node);
> +    }
> +}
> +
> +
> +enum engine_input_handler_result
> +en_datapath_synced_logical_switch_datapath_sync_handler(
> +        struct engine_node *node, void *data)
> +{
> +    const struct ovn_synced_datapaths *dps =
> +        engine_get_input_data("datapath_sync", node);
> +    struct ovn_synced_logical_switch_map *switch_map = data;
> +
> +    if (hmapx_is_empty(&dps->deleted) &&
> +        hmapx_is_empty(&dps->new) &&
> +        hmapx_is_empty(&dps->updated)) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    enum engine_input_handler_result result = EN_HANDLED_UNCHANGED;
> +
> +    struct hmapx_node *hmapx_node;
> +    struct ovn_synced_datapath *sdp;
> +    struct ovn_synced_logical_switch *lsw;
> +    HMAPX_FOR_EACH (hmapx_node, &dps->new) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_switch) {
> +            continue;
> +        }
> +        lsw = synced_logical_switch_alloc(sdp);
> +        hmap_insert(&switch_map->synced_switches, &lsw->hmap_node,
> +                    uuid_hash(&lsw->nb->header_.uuid));
> +        hmapx_add(&switch_map->new, lsw);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +    HMAPX_FOR_EACH (hmapx_node, &dps->deleted) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_switch) {
> +            continue;
> +        }
> +        lsw = ovn_synced_logical_switch_find(switch_map,
> &sdp->nb_row->uuid);
> +        if (!lsw) {
> +            return EN_UNHANDLED;
> +        }
> +        hmap_remove(&switch_map->synced_switches, &lsw->hmap_node);
> +        hmapx_add(&switch_map->deleted, lsw);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +    HMAPX_FOR_EACH (hmapx_node, &dps->updated) {
> +        sdp = hmapx_node->data;
> +        if (sdp->nb_row->table->class_ != &nbrec_table_logical_switch) {
> +            continue;
> +        }
> +        lsw = ovn_synced_logical_switch_find(switch_map,
> &sdp->nb_row->uuid);
> +        if (!lsw) {
> +            return EN_UNHANDLED;
> +        }
> +        lsw->nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_switch,
> +                               header_);
> +        lsw->sb = sdp->sb_dp;
> +        hmapx_add(&switch_map->updated, lsw);
> +        result = EN_HANDLED_UPDATED;
> +    }
> +
> +    return result;
> +}
> +
>  void en_datapath_synced_logical_switch_cleanup(void *data)
>  {
>      struct ovn_synced_logical_switch_map *switch_map = data;
> diff --git a/northd/en-datapath-logical-switch.h
> b/northd/en-datapath-logical-switch.h
> index 2a5a97b18..f6366827b 100644
> --- a/northd/en-datapath-logical-switch.h
> +++ b/northd/en-datapath-logical-switch.h
> @@ -19,6 +19,7 @@
>
>  #include "lib/inc-proc-eng.h"
>  #include "openvswitch/hmap.h"
> +#include "lib/hmapx.h"
>
>  void *en_datapath_logical_switch_init(struct engine_node *,
>                                        struct engine_arg *);
> @@ -38,13 +39,26 @@ struct ovn_synced_logical_switch {
>
>  struct ovn_synced_logical_switch_map {
>      struct hmap synced_switches;
> +
> +    struct hmapx new;
> +    struct hmapx updated;
> +    struct hmapx deleted;
>  };
>
> +struct uuid;
> +struct ovn_synced_logical_switch *
> +ovn_synced_logical_switch_find(const struct ovn_synced_logical_switch_map
> *map,
> +                               const struct uuid *nb_uuid);
> +
>  void *en_datapath_synced_logical_switch_init(struct engine_node *,
>                                               struct engine_arg *);
>
>  enum engine_node_state en_datapath_synced_logical_switch_run(
>      struct engine_node *, void *data);
> +void en_datapath_synced_logical_switch_clear_tracked_data(void *data);
> +enum engine_input_handler_result
> +en_datapath_synced_logical_switch_datapath_sync_handler(
> +        struct engine_node *node, void *data);
>  void en_datapath_synced_logical_switch_cleanup(void *data);
>
>  #endif /* EN_DATAPATH_LOGICAL_SWITCH_H */
> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> index 166c0d814..c126c4fb3 100644
> --- a/northd/inc-proc-northd.c
> +++ b/northd/inc-proc-northd.c
> @@ -185,8 +185,8 @@ static ENGINE_NODE(group_ecmp_route,
> CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(datapath_logical_router, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(datapath_logical_switch, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(datapath_sync, CLEAR_TRACKED_DATA);
> -static ENGINE_NODE(datapath_synced_logical_router);
> -static ENGINE_NODE(datapath_synced_logical_switch);
> +static ENGINE_NODE(datapath_synced_logical_router, CLEAR_TRACKED_DATA);
> +static ENGINE_NODE(datapath_synced_logical_switch, CLEAR_TRACKED_DATA);
>
>  void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>                            struct ovsdb_idl_loop *sb)
> @@ -234,9 +234,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>                       datapath_sync_logical_router_handler);
>
>      engine_add_input(&en_datapath_synced_logical_router,
> &en_datapath_sync,
> -                     NULL);
> +
>  en_datapath_synced_logical_router_datapath_sync_handler);
>      engine_add_input(&en_datapath_synced_logical_switch,
> &en_datapath_sync,
> -                     NULL);
> +
>  en_datapath_synced_logical_switch_datapath_sync_handler);
>
>      engine_add_input(&en_northd, &en_nb_mirror, NULL);
>      engine_add_input(&en_northd, &en_nb_mirror_rule, NULL);
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index d3fd924fb..6b0711c54 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -17846,3 +17846,56 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  AT_CLEANUP
>  ])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([Synced logical switch and router incremental procesesing])
> +ovn_start
> +
> +# datapath_synced_logical_switch and datapath_synced_logical_router
> +# should only recompute if datapath_sync has to recompute. Therefore,
> +# andy situation where datapath_sync can run incrementally, the
> +# synced datapath nodes should also run incrementally.
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb ls-add sw0
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb set logical_switch sw0
> other_config:fdb_age_threshold=5
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb set logical_switch sw0
> other_config:requested-tnl-key=123
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb ls-del sw0
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lr-add lr0
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +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 lr0 options:ct-zone-limit=10
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb lr-del lr0
> +check_engine_stats datapath_synced_logical_switch norecompute compute
> +check_engine_stats datapath_synced_logical_router norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +
> +AT_CLEANUP
> +])
> --
> 2.49.0
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
There are a lot of CI failures. Please check them out.

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

Reply via email to