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

> From: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
>
> Introduce Incremental Processing logic for en-datapath-logical-switch
> node.
>
> Reported-at: https://issues.redhat.com/browse/FDP-1519
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
> ---
>

Hi Mark and Lorenzo,

thank you for the patch. I have one minor comment down below.


>  northd/en-datapath-logical-switch.c | 182 ++++++++++++++++++++--------
>  northd/en-datapath-logical-switch.h |   3 +
>  northd/inc-proc-northd.c            |   8 +-
>  tests/ovn-northd.at                 |  28 +++++
>  4 files changed, 168 insertions(+), 53 deletions(-)
>
> diff --git a/northd/en-datapath-logical-switch.c
> b/northd/en-datapath-logical-switch.c
> index 23fa9725f..83d065dae 100644
> --- a/northd/en-datapath-logical-switch.c
> +++ b/northd/en-datapath-logical-switch.c
> @@ -38,72 +38,154 @@ en_datapath_logical_switch_init(struct engine_node
> *node OVS_UNUSED,
>      return map;
>  }
>
> -enum engine_node_state
> -en_datapath_logical_switch_run(struct engine_node *node , void *data)
> +static uint32_t
> +get_requested_tunnel_key(const struct nbrec_logical_switch *nbs,
> +                         bool vxlan_mode)
> +{
> +    uint32_t requested_tunnel_key = smap_get_int(&nbs->other_config,
> +                                                 "requested-tnl-key", 0);
> +    const char *ts = smap_get(&nbs->other_config, "interconn-ts");
> +
> +    if (!ts && vxlan_mode && requested_tunnel_key >= 1 << 12) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +        VLOG_WARN_RL(&rl, "Tunnel key %"PRIu32" for datapath %s is "
> +                     "incompatible with VXLAN", requested_tunnel_key,
> +                     nbs->name);
> +        requested_tunnel_key = 0;
> +    }
> +
> +    return requested_tunnel_key;
> +}
> +
> +static void
> +gather_external_ids(const struct nbrec_logical_switch *nbs,
> +                    struct smap *external_ids)
> +{
> +    smap_add(external_ids, "name", nbs->name);
> +    const char *neutron_network = smap_get(&nbs->other_config,
> +                                           "neutron:network_name");
> +    if (neutron_network && neutron_network[0]) {
> +        smap_add(external_ids, "name2", neutron_network);
> +    }
> +
> +    int64_t ct_zone_limit = ovn_smap_get_llong(&nbs->other_config,
> +                                               "ct-zone-limit", -1);
> +    if (ct_zone_limit > 0) {
> +        smap_add_format(external_ids, "ct-zone-limit", "%"PRId64,
> +                        ct_zone_limit);
> +    }
> +
> +    const char *ts = smap_get(&nbs->other_config, "interconn-ts");
> +    if (ts) {
> +        smap_add(external_ids, "interconn-ts", ts);
> +    }
> +
> +    uint32_t age_threshold = smap_get_uint(&nbs->other_config,
> +                                           "fdb_age_threshold", 0);
> +    if (age_threshold) {
> +        smap_add_format(external_ids, "fdb_age_threshold",
> +                        "%u", age_threshold);
> +    }
> +
> +    /* For backwards-compatibility, also store the NB UUID in
> +     * external-ids:logical-switch. This is useful if ovn-controller
> +     * has not updated and expects this to be where to find the
> +     * UUID.
> +     */
> +    smap_add_format(external_ids, "logical-switch", UUID_FMT,
> +                    UUID_ARGS(&nbs->header_.uuid));
> +}
> +
> +static struct ovn_unsynced_datapath *
> +datapath_unsynced_new_logical_switch_handler(
> +        const struct nbrec_logical_switch *nbs,
> +        const struct ed_type_global_config *global_config,
> +        struct ovn_unsynced_datapath_map *map)
> +{
> +    uint32_t requested_tunnel_key = get_requested_tunnel_key(
> +        nbs, global_config->vxlan_mode);
> +
> +    struct ovn_unsynced_datapath *udp =
> +        ovn_unsynced_datapath_alloc(nbs->name, DP_SWITCH,
> +                                    requested_tunnel_key, &nbs->header_);
> +
> +    gather_external_ids(nbs, &udp->external_ids);
> +    hmap_insert(&map->dps, &udp->hmap_node,
> uuid_hash(&nbs->header_.uuid));
> +    return udp;
> +}
> +
> +enum engine_input_handler_result
> +datapath_logical_switch_handler(struct engine_node *node, void *data)
>  {
>      const struct nbrec_logical_switch_table *nb_ls_table =
>          EN_OVSDB_GET(engine_get_input("NB_logical_switch", node));
>      const struct ed_type_global_config *global_config =
>          engine_get_input_data("global_config", node);
> -
> +    enum engine_input_handler_result ret = EN_HANDLED_UNCHANGED;
>      struct ovn_unsynced_datapath_map *map = data;
>
> -    ovn_unsynced_datapath_map_destroy(map);
> -    ovn_unsynced_datapath_map_init(map, DP_SWITCH);
> -
>      const struct nbrec_logical_switch *nbs;
> -    NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH (nbs, nb_ls_table) {
> -        uint32_t requested_tunnel_key = smap_get_int(&nbs->other_config,
> -                                                     "requested-tnl-key",
> 0);
> -        const char *ts = smap_get(&nbs->other_config, "interconn-ts");
> -
> -        if (!ts && global_config->vxlan_mode &&
> -            requested_tunnel_key >= 1 << 12) {
> -            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> -            VLOG_WARN_RL(&rl, "Tunnel key %"PRIu32" for datapath %s is "
> -                         "incompatible with VXLAN", requested_tunnel_key,
> -                         nbs->name);
> -            requested_tunnel_key = 0;
> -        }
> +    NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (nbs, nb_ls_table) {
> +        struct ovn_unsynced_datapath *udp =
> +            ovn_unsynced_datapath_find(map, &nbs->header_.uuid);
>
> -        struct ovn_unsynced_datapath *dp
> -            = ovn_unsynced_datapath_alloc(nbs->name, DP_SWITCH,
> -                                          requested_tunnel_key,
> &nbs->header_);
> +        if (nbrec_logical_switch_is_new(nbs)) {
> +            if (udp) {
> +                return EN_UNHANDLED;
> +            }
> +            udp = datapath_unsynced_new_logical_switch_handler(nbs,
> +
>  global_config,
> +                                                               map);
> +            hmapx_add(&map->new, udp);
> +            ret = EN_HANDLED_UPDATED;
> +        } else if (nbrec_logical_switch_is_deleted(nbs)) {
> +            if (!udp) {
> +                return EN_UNHANDLED;
> +            }
> +            hmap_remove(&map->dps, &udp->hmap_node);
> +            hmapx_add(&map->deleted, udp);
> +            ret = EN_HANDLED_UPDATED;
> +        } else {
> +            if (!udp) {
> +                return EN_UNHANDLED;
> +            }
>
> -        smap_add(&dp->external_ids, "name", dp->name);
> -        const char *neutron_network = smap_get(&nbs->other_config,
> -                                               "neutron:network_name");
> -        if (neutron_network && neutron_network[0]) {
> -            smap_add(&dp->external_ids, "name2", neutron_network);
> +            udp->requested_tunnel_key = get_requested_tunnel_key(
> +                    nbs, global_config->vxlan_mode);
> +            smap_destroy(&udp->external_ids);
> +            smap_init(&udp->external_ids);
> +            gather_external_ids(nbs, &udp->external_ids);
> +            hmapx_add(&map->updated, udp);
> +            ret = EN_HANDLED_UPDATED;
>          }
> +    }
>
> -        int64_t ct_zone_limit = ovn_smap_get_llong(&nbs->other_config,
> -                                                   "ct-zone-limit", -1);
> -        if (ct_zone_limit > 0) {
> -            smap_add_format(&dp->external_ids, "ct-zone-limit", "%"PRId64,
> -                            ct_zone_limit);
> -        }
>

nit: You could check if all hmapx have anything in them
and return based on that.

+    return ret;
> +}
>
> -        if (ts) {
> -            smap_add(&dp->external_ids, "interconn-ts", ts);
> -        }
> +void
> +en_datapath_logical_switch_clear_tracked_data(void *data)
> +{
> +    struct ovn_unsynced_datapath_map *map = data;
> +    ovn_unsynced_datapath_map_clear_tracked_data(map);
> +}
>
> -        uint32_t age_threshold = smap_get_uint(&nbs->other_config,
> -                                               "fdb_age_threshold", 0);
> -        if (age_threshold) {
> -            smap_add_format(&dp->external_ids, "fdb_age_threshold",
> -                            "%u", age_threshold);
> -        }
> +enum engine_node_state
> +en_datapath_logical_switch_run(struct engine_node *node , void *data)
> +{
> +    const struct nbrec_logical_switch_table *nb_ls_table =
> +        EN_OVSDB_GET(engine_get_input("NB_logical_switch", node));
> +    const struct ed_type_global_config *global_config =
> +        engine_get_input_data("global_config", node);
>
> -        /* For backwards-compatibility, also store the NB UUID in
> -         * external-ids:logical-switch. This is useful if ovn-controller
> -         * has not updated and expects this to be where to find the
> -         * UUID.
> -         */
> -        smap_add_format(&dp->external_ids, "logical-switch", UUID_FMT,
> -                        UUID_ARGS(&nbs->header_.uuid));
> +    struct ovn_unsynced_datapath_map *map = data;
> +
> +    ovn_unsynced_datapath_map_destroy(map);
> +    ovn_unsynced_datapath_map_init(map, DP_SWITCH);
>
> -        hmap_insert(&map->dps, &dp->hmap_node,
> uuid_hash(&nbs->header_.uuid));
> +    const struct nbrec_logical_switch *nbs;
> +    NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH (nbs, nb_ls_table) {
> +        datapath_unsynced_new_logical_switch_handler(nbs, global_config,
> map);
>      }
>
>      return EN_UPDATED;
> diff --git a/northd/en-datapath-logical-switch.h
> b/northd/en-datapath-logical-switch.h
> index 1bd5fea83..2a5a97b18 100644
> --- a/northd/en-datapath-logical-switch.h
> +++ b/northd/en-datapath-logical-switch.h
> @@ -23,9 +23,12 @@
>  void *en_datapath_logical_switch_init(struct engine_node *,
>                                        struct engine_arg *);
>
> +enum engine_input_handler_result
> +datapath_logical_switch_handler(struct engine_node *, void *data);
>  enum engine_node_state en_datapath_logical_switch_run(struct engine_node
> *,
>                                                        void *data);
>  void en_datapath_logical_switch_cleanup(void *data);
> +void en_datapath_logical_switch_clear_tracked_data(void *data);
>
>  struct ovn_synced_logical_switch {
>      struct hmap_node hmap_node;
> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> index bf1a09c08..0dfbf00b5 100644
> --- a/northd/inc-proc-northd.c
> +++ b/northd/inc-proc-northd.c
> @@ -183,7 +183,7 @@ static ENGINE_NODE(learned_route_sync,
> CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(dynamic_routes);
>  static ENGINE_NODE(group_ecmp_route, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(datapath_logical_router, CLEAR_TRACKED_DATA);
> -static ENGINE_NODE(datapath_logical_switch);
> +static ENGINE_NODE(datapath_logical_switch, CLEAR_TRACKED_DATA);
>  static ENGINE_NODE(datapath_sync);
>  static ENGINE_NODE(datapath_synced_logical_router);
>  static ENGINE_NODE(datapath_synced_logical_switch);
> @@ -217,8 +217,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>      engine_add_input(&en_acl_id, &en_nb_acl, NULL);
>      engine_add_input(&en_acl_id, &en_sb_acl_id, NULL);
>
> -    engine_add_input(&en_datapath_logical_switch, &en_nb_logical_switch,
> NULL);
> -    engine_add_input(&en_datapath_logical_switch, &en_global_config,
> NULL);
> +    engine_add_input(&en_datapath_logical_switch, &en_nb_logical_switch,
> +                     datapath_logical_switch_handler);
> +    engine_add_input(&en_datapath_logical_switch, &en_global_config,
> +                     datapath_logical_switch_handler);
>
>      engine_add_input(&en_datapath_logical_router, &en_nb_logical_router,
>                       en_datapath_logical_router_logical_router_handler);
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 64506e79e..76b59408c 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -17778,3 +17778,31 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  AT_CLEANUP
>  ])
> +
> +OVN_FOR_EACH_NORTHD_NO_HV([
> +AT_SETUP([Datapath Logical switch incremental processing])
> +ovn_start
> +
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +check ovn-nbctl --wait=sb ls-add sw0
> +check_engine_stats datapath_logical_switch 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_logical_switch 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_logical_switch 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_logical_switch 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
>
>
With that addressed:
Acked-by: Ales Musil <amu...@redhat.com>

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

Reply via email to