> On 7/19/25 3:54 AM, Lorenzo Bianconi via dev wrote:
> > This patch handles the logical switch creation incrementally
> > in the northd engine node.  The dependent engine nodes - ls_stateful,
> > lflow and few others still fall back to full recompute, which
> > will be handled in separate patches.
> > 
> > Reported-at: https://issues.redhat.com/browse/FDP-754
> > Co-authored-by: Numan Siddique <num...@ovn.org>
> > Signed-off-by: Numan Siddique <num...@ovn.org>
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
> > ---
> >   northd/en-lflow.c        |  4 ++
> >   northd/en-ls-stateful.c  |  4 ++
> >   northd/inc-proc-northd.c |  5 ++-
> >   northd/northd.c          | 84 ++++++++++++++++++++++++++++++++++++----
> >   northd/northd.h          | 15 +++++++
> >   tests/ovn-northd.at      | 68 ++++++++++++++++++++++++++++++++
> >   6 files changed, 172 insertions(+), 8 deletions(-)
> > 
> > diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> > index 63565ef80..539113556 100644
> > --- a/northd/en-lflow.c
> > +++ b/northd/en-lflow.c
> > @@ -135,6 +135,10 @@ lflow_northd_handler(struct engine_node *node,
> >           return EN_UNHANDLED;
> >       }
> > +    if (northd_has_lswitchs_in_tracked_data(&northd_data->trk_data)) {
> > +        return EN_UNHANDLED;
> > +    }
> > +
> >       const struct engine_context *eng_ctx = engine_get_context();
> >       struct lflow_data *lflow_data = data;
> > diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c
> > index 7f07a6506..448ccc3c4 100644
> > --- a/northd/en-ls-stateful.c
> > +++ b/northd/en-ls-stateful.c
> > @@ -131,6 +131,10 @@ ls_stateful_northd_handler(struct engine_node *node, 
> > void *data_)
> >           return EN_UNHANDLED;
> >       }
> > +    if (northd_has_lswitchs_in_tracked_data(&northd_data->trk_data)) {
> > +        return EN_UNHANDLED;
> > +    }
> > +
> >       if (!northd_has_ls_lbs_in_tracked_data(&northd_data->trk_data) &&
> >           !northd_has_ls_acls_in_tracked_data(&northd_data->trk_data)) {
> >           return EN_HANDLED_UNCHANGED;
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index 6bf8dde3f..b7be79946 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -249,7 +249,6 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >       engine_add_input(&en_northd, &en_sb_meter, NULL);
> >       engine_add_input(&en_northd, &en_sb_dns, NULL);
> >       engine_add_input(&en_northd, &en_sb_ha_chassis_group, NULL);
> > -    engine_add_input(&en_northd, &en_sb_ip_multicast, NULL);
> >       engine_add_input(&en_northd, &en_sb_service_monitor, NULL);
> >       engine_add_input(&en_northd, &en_sb_static_mac_binding, NULL);
> >       engine_add_input(&en_northd, &en_sb_chassis_template_var, NULL);
> > @@ -278,6 +277,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >       engine_add_input(&en_northd, &en_nb_port_group,
> >                        northd_nb_port_group_handler);
> > +    /* No need for an explicit handler for the SB datapath and
> > +     * SB IP Multicast changes.*/
> > +    engine_add_input(&en_northd, &en_sb_ip_multicast, engine_noop_handler);
> > +
> >       engine_add_input(&en_lr_nat, &en_northd, lr_nat_northd_handler);
> >       engine_add_input(&en_lr_stateful, &en_northd, 
> > lr_stateful_northd_handler);
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 0e990c19a..0ec18f516 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -811,8 +811,11 @@ ods_build_array_index(struct ovn_datapaths *datapaths)
> >        * doesn't matter if they are different on every iteration. */
> >       size_t index = 0;
> > -    datapaths->array = xrealloc(datapaths->array,
> > -                            ods_size(datapaths) * sizeof 
> > *datapaths->array);
> > +    datapaths->n_array = ods_size(datapaths);
> > +    datapaths->n_allocated_array = datapaths->n_array + 10;
> 
> Later in this patch, I recommend using a vector instead of an open-coded
> dynamic array. But, if for some reason the switch to a vector does not work
> out, then please make the 10 here a named constant instead of being
> hardcoded inline.

I am fine with it but since this array has not been introduced by this series I
guess we can do it with a follow-up patch. What do you think?

> 
> > +    datapaths->array = xrealloc(
> > +        datapaths->array,
> > +        datapaths->n_allocated_array * sizeof *datapaths->array);
> >       struct ovn_datapath *od;
> >       HMAP_FOR_EACH (od, key_node, &datapaths->datapaths) {
> > @@ -822,6 +825,23 @@ ods_build_array_index(struct ovn_datapaths *datapaths)
> >       }
> >   }
> > +static void
> > +ods_assign_array_index(struct ovn_datapaths *datapaths,
> > +                       struct ovn_datapath *od)
> > +{
> > +    ovs_assert(ods_size(datapaths) == (datapaths->n_array + 1));
> > +    od->index = datapaths->n_array;
> > +
> > +    if (datapaths->n_array == datapaths->n_allocated_array) {
> > +        datapaths->n_allocated_array += 10;
> > +        datapaths->array = xrealloc(
> > +            datapaths->array,
> > +            datapaths->n_allocated_array * sizeof *datapaths->array);
> > +    }
> > +    datapaths->array[datapaths->n_array++] = od;
> > +    od->datapaths = datapaths;
> > +}
> > +
> >   /* Initializes 'ls_datapaths' to contain a "struct ovn_datapath" for every
> >    * logical switch, and initializes 'lr_datapaths' to contain a
> >    * "struct ovn_datapath" for every logical router.
> > @@ -4337,6 +4357,12 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> >       sset_destroy(&active_ha_chassis_grps);
> >   }
> > +static void
> > +destroy_tracked_dps(struct tracked_dps *trk_dps)
> > +{
> > +    hmapx_clear(&trk_dps->crupdated);
> > +}
> > +
> >   static void
> >   destroy_tracked_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports)
> >   {
> > @@ -4373,6 +4399,7 @@ void
> >   destroy_northd_data_tracked_changes(struct northd_data *nd)
> >   {
> >       struct northd_tracked_data *trk_changes = &nd->trk_data;
> > +    destroy_tracked_dps(&trk_changes->trk_switches);
> >       destroy_tracked_ovn_ports(&trk_changes->trk_lsps);
> >       destroy_tracked_lbs(&trk_changes->trk_lbs);
> >       hmapx_clear(&trk_changes->trk_nat_lrs);
> > @@ -4386,6 +4413,7 @@ init_northd_tracked_data(struct northd_data *nd)
> >   {
> >       struct northd_tracked_data *trk_data = &nd->trk_data;
> >       trk_data->type = NORTHD_TRACKED_NONE;
> > +    hmapx_init(&trk_data->trk_switches.crupdated);
> >       hmapx_init(&trk_data->trk_lsps.created);
> >       hmapx_init(&trk_data->trk_lsps.updated);
> >       hmapx_init(&trk_data->trk_lsps.deleted);
> > @@ -4401,6 +4429,7 @@ destroy_northd_tracked_data(struct northd_data *nd)
> >   {
> >       struct northd_tracked_data *trk_data = &nd->trk_data;
> >       trk_data->type = NORTHD_TRACKED_NONE;
> > +    hmapx_destroy(&trk_data->trk_switches.crupdated);
> >       hmapx_destroy(&trk_data->trk_lsps.created);
> >       hmapx_destroy(&trk_data->trk_lsps.updated);
> >       hmapx_destroy(&trk_data->trk_lsps.deleted);
> > @@ -4701,7 +4730,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn 
> > *ovnsb_idl_txn,
> >           for (size_t i = 0; i < changed_ls->n_ports; i++) {
> >               if (nbrec_logical_switch_port_row_get_seqno(
> > -                changed_ls->ports[i], OVSDB_IDL_CHANGE_MODIFY) > 0) {
> > +                changed_ls->ports[i], OVSDB_IDL_CHANGE_MODIFY) > 0 ||
> > +                !ovn_port_find_in_datapath(od, changed_ls->ports[i])) {
> >                   ls_ports_changed = true;
> >                   break;
> >               }
> > @@ -4871,18 +4901,54 @@ northd_handle_ls_changes(struct ovsdb_idl_txn 
> > *ovnsb_idl_txn,
> >                            const struct northd_input *ni,
> >                            struct northd_data *nd)
> >   {
> > -    const struct nbrec_logical_switch *changed_ls;
> >       struct northd_tracked_data *trk_data = &nd->trk_data;
> > +    nd->trk_data.type = NORTHD_TRACKED_NONE;
> > -    if (!hmapx_is_empty(&ni->synced_lses->new) ||
> > -        !hmapx_is_empty(&ni->synced_lses->deleted)) {
> > +    if (!hmapx_is_empty(&ni->synced_lses->deleted)) {
> >           goto fail;
> >       }
> >       struct hmapx_node *node;
> > +
> > +    HMAPX_FOR_EACH (node, &ni->synced_lses->new) {
> > +        const struct ovn_synced_logical_switch *synced = node->data;
> > +        const struct nbrec_logical_switch *new_ls = synced->nb;
> > +
> > +        /* If a logical switch is created with the below columns set,
> > +         * then we can't handle this yet. Goto fail. */
> > +        if (new_ls->copp || new_ls->n_dns_records ||
> > +            new_ls->n_forwarding_groups || new_ls->n_qos_rules) {
> > +            goto fail;
> > +        }
> > +
> > +        struct ovn_datapath *od = ovn_datapath_create(
> > +            &nd->ls_datapaths.datapaths, &new_ls->header_.uuid, new_ls,
> > +            NULL, synced->sb);
> > +
> > +        ods_assign_array_index(&nd->ls_datapaths, od);
> > +        init_ipam_info_for_datapath(od);
> > +        init_mcast_info_for_datapath(od);
> > +
> > +        /* Create SB:IP_Multicast for the logical switch. */
> > +        const struct sbrec_ip_multicast *ip_mcast =
> > +            sbrec_ip_multicast_insert(ovnsb_idl_txn);
> > +        store_mcast_info_for_switch_datapath(ip_mcast, od);
> > +
> > +        if (!ls_handle_lsp_changes(ovnsb_idl_txn, new_ls,
> > +                                   ni, nd, od, &trk_data->trk_lsps)) {
> > +            goto fail;
> > +        }
> > +
> > +        if (new_ls->n_acls) {
> > +            hmapx_add(&trk_data->ls_with_changed_acls, od);
> > +        }
> > +        hmapx_add(&trk_data->trk_switches.crupdated, od);
> > +    }
> > +
> >       HMAPX_FOR_EACH (node, &ni->synced_lses->updated) {
> >           const struct ovn_synced_logical_switch *synced = node->data;
> > -        changed_ls = synced->nb;
> > +        const struct nbrec_logical_switch *changed_ls = synced->nb;
> > +
> >           struct ovn_datapath *od = ovn_datapath_find_(
> >                                       &nd->ls_datapaths.datapaths,
> >                                       &changed_ls->header_.uuid);
> > @@ -4909,6 +4975,10 @@ northd_handle_ls_changes(struct ovsdb_idl_txn 
> > *ovnsb_idl_txn,
> >           }
> >       }
> > +    if (!hmapx_is_empty(&trk_data->trk_switches.crupdated)) {
> > +        trk_data->type |= NORTHD_TRACKED_SWITCHES;
> > +    }
> > +
> >       if (!hmapx_is_empty(&trk_data->trk_lsps.created)
> >           || !hmapx_is_empty(&trk_data->trk_lsps.updated)
> >           || !hmapx_is_empty(&trk_data->trk_lsps.deleted)) {
> > diff --git a/northd/northd.h b/northd/northd.h
> > index 599a81d79..d0e7a1135 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -90,6 +90,8 @@ struct ovn_datapaths {
> >       /* The array index of each element in 'datapaths'. */
> >       struct ovn_datapath **array;
> > +    size_t n_array;
> > +    size_t n_allocated_array;
> 
> I think a good guideline to keep in mind is that if you are considering
> making a static array dynamic, it's probably a good idea to convert it to a
> vector instead of adding dynamic array mechanics on top. Many lines of code
> in this patch could be replaced with calls to existing vector functions
> instead.

ditto.

> 
> >   };
> >   static inline size_t
> > @@ -110,6 +112,11 @@ enum redirected_routing_protcol_flag_type {
> >       REDIRECT_BFD = (1 << 1),
> >   };
> > +struct tracked_dps {
> > +    /* Tracked created or updated datapaths. */
> > +    struct hmapx crupdated;
> > +};
> > +
> >   struct tracked_ovn_ports {
> >       /* tracked created ports.
> >        * hmapx node data is 'struct ovn_port *' */
> > @@ -141,6 +148,7 @@ enum northd_tracked_data_type {
> >       NORTHD_TRACKED_LR_NATS  = (1 << 2),
> >       NORTHD_TRACKED_LS_LBS   = (1 << 3),
> >       NORTHD_TRACKED_LS_ACLS  = (1 << 4),
> > +    NORTHD_TRACKED_SWITCHES = (1 << 5),
> >   };
> >   /* Track what's changed in the northd engine node.
> > @@ -149,6 +157,7 @@ enum northd_tracked_data_type {
> >   struct northd_tracked_data {
> >       /* Indicates the type of data tracked.  One or all of 
> > NORTHD_TRACKED_*. */
> >       enum northd_tracked_data_type type;
> > +    struct tracked_dps trk_switches;
> >       struct tracked_ovn_ports trk_lsps;
> >       struct tracked_lbs trk_lbs;
> > @@ -953,6 +962,12 @@ northd_has_ls_acls_in_tracked_data(struct 
> > northd_tracked_data *trk_nd_changes)
> >       return trk_nd_changes->type & NORTHD_TRACKED_LS_ACLS;
> >   }
> > +static inline bool
> > +northd_has_lswitchs_in_tracked_data(struct northd_tracked_data 
> > *trk_nd_changes)
> 
> s/lswitchs/lswitches/

ack, I will fix it.

> 
> > +{
> > +    return trk_nd_changes->type & NORTHD_TRACKED_SWITCHES;
> > +}
> > +
> >   /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the
> >    * IPs configured on the router port.
> >    */
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index d0843582a..305bd08e2 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -14656,6 +14656,74 @@ AT_CHECK([grep "lr_in_dnat" lr1flows | 
> > ovn_strip_lflows | grep "30.0.0.1"], [0],
> >   AT_CLEANUP
> >   ])
> > +OVN_FOR_EACH_NORTHD_NO_HV([
> > +AT_SETUP([Logical switch incremental processing])
> > +
> > +ovn_start
> > +
> > +net_add n1
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.11
> > +> +check ovn-sbctl chassis-add gw1 geneve 127.0.0.1
> > +check ovn-nbctl --wait=sb sync
> 
> Since this is a test of just northd (the test declaration says "NO_HV"), the
> lines after "ovn_start" up to this point are not necessary.
> 
> > +
> > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> > +check ovn-nbctl --wait=sb ls-add sw0
> > +check_engine_stats northd norecompute compute
> > +check_engine_stats ls_stateful norecompute compute
> > +check_engine_stats lflow recompute nocompute
> > +
> > +# For the below engine nodes, en_northd is input.  So check
> > +# their engine status.
> > +check_engine_stats lr_stateful norecompute compute
> > +check_engine_stats route_policies norecompute compute
> > +check_engine_stats routes norecompute compute
> > +check_engine_stats bfd_sync norecompute compute
> > +check_engine_stats sync_to_sb_lb norecompute compute
> > +check_engine_stats sync_to_sb_pb norecompute compute
> > +
> > +CHECK_NO_CHANGE_AFTER_RECOMPUTE((1))
> > +
> > +# Update the logical switch.
> > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> > +check ovn-nbctl --wait=sb set logical_switch sw0 other_config:foo=bar
> > +
> > +check_engine_stats northd recompute nocompute
> > +check_engine_stats ls_stateful recompute nocompute
> > +check_engine_stats lflow recompute nocompute
> > +
> > +# For the below engine nodes, en_northd is input.  So check
> > +# their engine status.
> > +check_engine_stats lr_stateful recompute nocompute
> > +check_engine_stats route_policies recompute nocompute
> > +check_engine_stats routes recompute nocompute
> > +check_engine_stats bfd_sync recompute nocompute
> > +check_engine_stats sync_to_sb_lb recompute nocompute
> > +check_engine_stats sync_to_sb_pb recompute nocompute
> > +
> > +# Delete the logical switch
> > +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> > +check ovn-nbctl --wait=sb ls-del sw0
> > +check_engine_stats northd recompute compute
> > +check_engine_stats ls_stateful recompute nocompute
> > +check_engine_stats lflow recompute nocompute
> > +
> > +# For the below engine nodes, en_northd is input.  So check
> > +# their engine status.
> > +check_engine_stats lr_stateful recompute nocompute
> > +check_engine_stats route_policies recompute nocompute
> > +check_engine_stats routes recompute nocompute
> > +check_engine_stats bfd_sync recompute nocompute
> > +check_engine_stats sync_to_sb_lb recompute nocompute
> > +check_engine_stats sync_to_sb_pb recompute nocompute
> > +
> > +OVN_CLEANUP([hv1])
> 
> If you remove the lines I mentioned earlier in the test, then you'll also
> need to remove this OVN_CLEANUP() line as well.

ack, I will fix it.

Regards,
Lorenzo

> 
> > +AT_CLEANUP
> > +])
> > +
> >   AT_SETUP([RBAC -- Recover builtin role and permissions])
> >   ovn_start
> 
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to