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/en-multicast.c    |   4 +
 northd/inc-proc-northd.c |   5 +-
 northd/lb.c              |   2 +-
 northd/lb.h              |   1 +
 northd/lflow-mgr.c       |   8 +-
 northd/northd.c          | 185 +++++++++++++++++++++++++++++++++------
 northd/northd.h          |  22 ++++-
 tests/ovn-northd.at      |  61 +++++++++++++
 10 files changed, 261 insertions(+), 35 deletions(-)

diff --git a/northd/en-lflow.c b/northd/en-lflow.c
index 63565ef80..8dc31165d 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_lswitches_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..8d64b4be2 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_lswitches_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/en-multicast.c b/northd/en-multicast.c
index d51db557e..669e6f73a 100644
--- a/northd/en-multicast.c
+++ b/northd/en-multicast.c
@@ -153,6 +153,10 @@ multicast_igmp_northd_handler(struct engine_node *node, 
void *data OVS_UNUSED)
         return EN_UNHANDLED;
     }
 
+    if (hmapx_count(&northd_data->trk_data.trk_switches.deleted)) {
+        return EN_UNHANDLED;
+    }
+
     /* This node uses the below data from the en_northd engine node.
      *      - northd_data->lr_datapaths
      *      - northd_data->ls_ports
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/lb.c b/northd/lb.c
index 2dc1359f1..b2b7dcf2a 100644
--- a/northd/lb.c
+++ b/northd/lb.c
@@ -597,7 +597,7 @@ ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *lb_dps)
     free(lb_dps);
 }
 
-static void
+void
 dynamic_bitmap_realloc(struct dynamic_bitmap *db, size_t new_n_elems)
 {
     if (new_n_elems > db->capacity) {
diff --git a/northd/lb.h b/northd/lb.h
index 1c27c2839..0bf493292 100644
--- a/northd/lb.h
+++ b/northd/lb.h
@@ -183,6 +183,7 @@ struct ovn_lb_datapaths *ovn_lb_datapaths_create(const 
struct ovn_northd_lb *,
 struct ovn_lb_datapaths *ovn_lb_datapaths_find(const struct hmap *,
                                                const struct uuid *);
 void ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *);
+void dynamic_bitmap_realloc(struct dynamic_bitmap *, size_t new_n_elems);
 
 void ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *, size_t n,
                              struct ovn_datapath **,
diff --git a/northd/lflow-mgr.c b/northd/lflow-mgr.c
index 18b88cf9e..b2a21dff5 100644
--- a/northd/lflow-mgr.c
+++ b/northd/lflow-mgr.c
@@ -1007,12 +1007,12 @@ sync_lflow_to_sb(struct ovn_lflow *lflow,
 
     if (ovn_stage_to_datapath_type(lflow->stage) == DP_SWITCH) {
         n_datapaths = ods_size(ls_datapaths);
-        datapaths_array = ls_datapaths->array;
+        datapaths_array = vector_get_array(&ls_datapaths->dps);
         dp_groups = &lflow_table->ls_dp_groups;
         is_switch = true;
     } else {
         n_datapaths = ods_size(lr_datapaths);
-        datapaths_array = lr_datapaths->array;
+        datapaths_array = vector_get_array(&lr_datapaths->dps);
         dp_groups = &lflow_table->lr_dp_groups;
         is_switch = false;
     }
@@ -1226,7 +1226,9 @@ ovn_sb_insert_or_update_logical_dp_group(
 
     sb = xmalloc(bitmap_count1(dpg_bitmap, ods_size(datapaths)) * sizeof *sb);
     BITMAP_FOR_EACH_1 (index, ods_size(datapaths), dpg_bitmap) {
-        sb[n++] = datapaths->array[index]->sb;
+        struct ovn_datapath *od = vector_get(&datapaths->dps, index,
+                                             struct ovn_datapath *);
+        sb[n++] = od->sb;
     }
     if (!dp_group) {
         struct uuid dpg_uuid = uuid_random();
diff --git a/northd/northd.c b/northd/northd.c
index fdcc9ee41..544a32509 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -806,22 +806,43 @@ parse_dynamic_routing_redistribute(
 static void
 ods_build_array_index(struct ovn_datapaths *datapaths)
 {
+    datapaths->dps = VECTOR_CAPACITY_INITIALIZER(struct ovn_datapath *,
+                                                 ods_size(datapaths));
+    datapaths->dps_index_map.map = bitmap_allocate(ods_size(datapaths));
+    datapaths->dps_index_map.capacity = ods_size(datapaths);
+
     /* Assign unique sequential indexes to all datapaths.  These are not
      * visible outside of the northd loop, so, unlike the tunnel keys, it
      * 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);
-
     struct ovn_datapath *od;
     HMAP_FOR_EACH (od, key_node, &datapaths->datapaths) {
+        size_t index = bitmap_scan(datapaths->dps_index_map.map, 0, 0,
+                                   datapaths->dps_index_map.capacity);
+        bitmap_set1(datapaths->dps_index_map.map, index);
+        datapaths->dps_index_map.n_elems++;
         od->index = index;
-        datapaths->array[index++] = od;
+        vector_push(&datapaths->dps, &od);
         od->datapaths = datapaths;
     }
 }
 
+static void
+ods_assign_array_index(struct ovn_datapaths *datapaths,
+                       struct ovn_datapath *od)
+{
+    ovs_assert(ods_size(datapaths) == (vector_len(&datapaths->dps) + 1));
+
+    dynamic_bitmap_realloc(&datapaths->dps_index_map,
+                           vector_len(&datapaths->dps) + 1);
+    size_t index = bitmap_scan(datapaths->dps_index_map.map, 0, 0,
+                               datapaths->dps_index_map.capacity);
+    vector_insert(&datapaths->dps, index, &od);
+    bitmap_set1(datapaths->dps_index_map.map, index);
+    datapaths->dps_index_map.n_elems++;
+    od->datapaths = datapaths;
+    od->index = index;
+}
+
 /* 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.
@@ -3780,7 +3801,8 @@ build_lswitch_lbs_from_lrouter(struct ovn_datapaths 
*lr_datapaths,
     HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
         BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths),
                            lb_dps->nb_lr_map.map) {
-            struct ovn_datapath *od = lr_datapaths->array[index];
+            struct ovn_datapath *od = vector_get(&lr_datapaths->dps, index,
+                                                 struct ovn_datapath *);
             ovn_lb_datapaths_add_ls(lb_dps, vector_len(&od->ls_peers),
                                     vector_get_array(&od->ls_peers),
                                     ods_size(ls_datapaths));
@@ -4338,6 +4360,18 @@ 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);
+
+    struct hmapx_node *n;
+    HMAPX_FOR_EACH (n, &trk_dps->deleted) {
+        free(n->data);
+    }
+    hmapx_clear(&trk_dps->deleted);
+}
+
 static void
 destroy_tracked_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports)
 {
@@ -4379,6 +4413,7 @@ destroy_northd_data_tracked_changes(struct northd_data 
*nd)
     hmapx_clear(&trk_changes->trk_nat_lrs);
     hmapx_clear(&trk_changes->ls_with_changed_lbs);
     hmapx_clear(&trk_changes->ls_with_changed_acls);
+    destroy_tracked_dps(&trk_changes->trk_switches);
     trk_changes->type = NORTHD_TRACKED_NONE;
 }
 
@@ -4387,6 +4422,8 @@ 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_switches.deleted);
     hmapx_init(&trk_data->trk_lsps.created);
     hmapx_init(&trk_data->trk_lsps.updated);
     hmapx_init(&trk_data->trk_lsps.deleted);
@@ -4402,7 +4439,12 @@ 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);
+    struct hmapx_node *n;
+    HMAPX_FOR_EACH (n, &trk_data->trk_switches.deleted) {
+        free(n->data);
+    }
     hmapx_destroy(&trk_data->trk_lsps.updated);
     hmapx_destroy(&trk_data->trk_lsps.deleted);
     hmapx_destroy(&trk_data->trk_lbs.crupdated);
@@ -4696,13 +4738,15 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
                       struct ovn_datapath *od,
                       struct tracked_ovn_ports *trk_lsps)
 {
-    bool ls_ports_changed = false;
+    bool ls_deleted = nbrec_logical_switch_is_deleted(changed_ls);
+    bool ls_ports_changed = ls_deleted;
     if (!nbrec_logical_switch_is_updated(changed_ls,
                                          NBREC_LOGICAL_SWITCH_COL_PORTS)) {
 
         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;
             }
@@ -4789,7 +4833,7 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn,
                                    od->tunnel_key, old_tunnel_key);
             }
         }
-        op->visited = true;
+        op->visited = !ls_deleted;
     }
 
     /* Check for deleted ports */
@@ -4872,18 +4916,49 @@ 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)) {
-        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);
     }
 
-    struct hmapx_node *node;
     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);
@@ -4910,6 +4985,54 @@ northd_handle_ls_changes(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
         }
     }
 
+    HMAPX_FOR_EACH (node, &ni->synced_lses->deleted) {
+        const struct ovn_synced_logical_switch *synced = node->data;
+        const struct nbrec_logical_switch *deleted_ls = synced->nb;
+
+        struct ovn_datapath *od = ovn_datapath_find_(
+                                    &nd->ls_datapaths.datapaths,
+                                    &deleted_ls->header_.uuid);
+        if (!od) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+            VLOG_WARN_RL(&rl, "Internal error: a tracked updated LS doesn't "
+                         "exist in ls_datapaths: "UUID_FMT,
+                         UUID_ARGS(&deleted_ls->header_.uuid));
+            goto fail;
+        }
+
+        if (deleted_ls->copp || deleted_ls->n_dns_records ||
+            deleted_ls->n_forwarding_groups || deleted_ls->n_qos_rules ||
+            deleted_ls->n_load_balancer || deleted_ls->n_load_balancer_group) {
+            goto fail;
+        }
+
+        if (!ls_handle_lsp_changes(ovnsb_idl_txn, deleted_ls,
+                                   ni, nd, od, &trk_data->trk_lsps)) {
+            goto fail;
+        }
+
+        hmap_remove(&nd->ls_datapaths.datapaths, &od->key_node);
+        vector_remove(&nd->ls_datapaths.dps, od->index, NULL);
+        bitmap_set0(nd->ls_datapaths.dps_index_map.map, od->index);
+        nd->ls_datapaths.dps_index_map.n_elems--;
+
+        const struct sbrec_ip_multicast *ip_mcast =
+            ip_mcast_lookup(ni->sbrec_ip_mcast_by_dp, od->sb);
+        if (ip_mcast) {
+            sbrec_ip_multicast_delete(ip_mcast);
+        }
+
+        if (is_ls_acls_changed(deleted_ls)) {
+            hmapx_add(&trk_data->ls_with_changed_acls, od);
+        }
+        hmapx_add(&trk_data->trk_switches.deleted, od);
+    }
+
+    if (!hmapx_is_empty(&trk_data->trk_switches.crupdated) ||
+        !hmapx_is_empty(&trk_data->trk_switches.deleted)) {
+        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)) {
@@ -5274,7 +5397,7 @@ northd_handle_lb_data_changes(struct tracked_lb_data 
*trk_lb_data,
         size_t index;
         BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths),
                            lb_dps->nb_ls_map.map) {
-            od = ls_datapaths->array[index];
+            od = vector_get(&ls_datapaths->dps, index, struct ovn_datapath *);
 
             /* Add the ls datapath to the northd tracked data. */
             hmapx_add(&nd_changes->ls_with_changed_lbs, od);
@@ -5410,7 +5533,7 @@ northd_handle_lb_data_changes(struct tracked_lb_data 
*trk_lb_data,
         size_t index;
         BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths),
                            lb_dps->nb_ls_map.map) {
-            od = ls_datapaths->array[index];
+            od = vector_get(&ls_datapaths->dps, index, struct ovn_datapath *);
 
             /* Add the ls datapath to the northd tracked data. */
             hmapx_add(&nd_changes->ls_with_changed_lbs, od);
@@ -8345,7 +8468,8 @@ build_lb_rules(struct lflow_table *lflows, struct 
ovn_lb_datapaths *lb_dps,
                                         ods_size(ls_datapaths));
             BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths),
                                lb_dps->nb_ls_map.map) {
-                struct ovn_datapath *od = ls_datapaths->array[index];
+                struct ovn_datapath *od = vector_get(&ls_datapaths->dps, index,
+                                                     struct ovn_datapath *);
 
                 meter = copp_meter_get(COPP_REJECT, od->nbs->copp,
                                        meter_groups);
@@ -12235,7 +12359,8 @@ build_gw_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
     if (ctx->reject) {
         dp_non_meter = bitmap_clone(dp_bitmap, bitmap_len);
         BITMAP_FOR_EACH_1 (index, bitmap_len, dp_bitmap) {
-            struct ovn_datapath *od = lr_datapaths->array[index];
+            struct ovn_datapath *od = vector_get(&lr_datapaths->dps, index,
+                                                 struct ovn_datapath *);
             const char *meter;
 
             meter = copp_meter_get(COPP_REJECT, od->nbr->copp,
@@ -12369,7 +12494,8 @@ build_lrouter_nat_flows_for_lb(
     bool use_stateless_nat = smap_get_bool(&lb->nlb->options,
                                            "use_stateless_nat", false);
     BITMAP_FOR_EACH_1 (index, bitmap_len, lb_dps->nb_lr_map.map) {
-        struct ovn_datapath *od = lr_datapaths->array[index];
+        struct ovn_datapath *od = vector_get(&lr_datapaths->dps, index,
+                                             struct ovn_datapath *);
         enum lrouter_nat_lb_flow_type type;
 
         const struct lr_stateful_record *lr_stateful_rec =
@@ -12469,7 +12595,8 @@ build_lswitch_flows_for_lb(struct ovn_lb_datapaths 
*lb_dps,
         size_t index;
         BITMAP_FOR_EACH_1 (index, ods_size(ls_datapaths),
                            lb_dps->nb_ls_map.map) {
-            struct ovn_datapath *od = ls_datapaths->array[index];
+            struct ovn_datapath *od = vector_get(&ls_datapaths->dps, index,
+                                                 struct ovn_datapath *);
 
             ovn_lflow_add_with_hint__(lflows, od,
                                       S_SWITCH_IN_PRE_LB, 130, ds_cstr(match),
@@ -12547,7 +12674,8 @@ build_lrouter_allow_vip_traffic_template(struct 
lflow_table *lflows,
 
     size_t index;
     BITMAP_FOR_EACH_1 (index, ods_size(lr_dps), lb_dps->nb_lr_map.map) {
-        struct ovn_datapath *od = lr_dps->array[index];
+        struct ovn_datapath *od = vector_get(&lr_dps->dps, index,
+                                             struct ovn_datapath *);
         /* Do not drop ip traffic with destination the template VIP. */
         ds_clear(&match);
         ds_put_format(&match, "ip%d.dst == %s",
@@ -12594,7 +12722,8 @@ build_lrouter_flows_for_lb(struct ovn_lb_datapaths 
*lb_dps,
 
         BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths),
                            lb_dps->nb_lr_map.map) {
-            struct ovn_datapath *od = lr_datapaths->array[index];
+            struct ovn_datapath *od = vector_get(&lr_datapaths->dps, index,
+                                                 struct ovn_datapath *);
 
             ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT,
                                       130, ds_cstr(match), ds_cstr(action),
@@ -12609,7 +12738,8 @@ build_lrouter_flows_for_lb(struct ovn_lb_datapaths 
*lb_dps,
     if (lb->skip_snat) {
         BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths),
                            lb_dps->nb_lr_map.map) {
-            struct ovn_datapath *od = lr_datapaths->array[index];
+            struct ovn_datapath *od = vector_get(&lr_datapaths->dps, index,
+                                                 struct ovn_datapath *);
 
             ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 120,
                           "flags.skip_snat_for_lb == 1 && ip", "next;",
@@ -18991,7 +19121,6 @@ static void
 ovn_datapaths_init(struct ovn_datapaths *datapaths)
 {
     hmap_init(&datapaths->datapaths);
-    datapaths->array = NULL;
 }
 
 static void
@@ -19003,8 +19132,8 @@ ovn_datapaths_destroy(struct ovn_datapaths *datapaths)
     }
     hmap_destroy(&datapaths->datapaths);
 
-    free(datapaths->array);
-    datapaths->array = NULL;
+    bitmap_free(datapaths->dps_index_map.map);
+    vector_destroy(&datapaths->dps);
 }
 
 static void
diff --git a/northd/northd.h b/northd/northd.h
index 599a81d79..3ffe80430 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -22,6 +22,7 @@
 #include "lib/sset.h"
 #include "northd/en-port-group.h"
 #include "northd/ipam.h"
+#include "northd/lb.h"
 #include "openvswitch/hmap.h"
 #include "simap.h"
 #include "ovs-thread.h"
@@ -89,7 +90,8 @@ struct ovn_datapaths {
     struct hmap datapaths;
 
     /* The array index of each element in 'datapaths'. */
-    struct ovn_datapath **array;
+    struct dynamic_bitmap dps_index_map;
+    struct vector dps;
 };
 
 static inline size_t
@@ -110,6 +112,13 @@ enum redirected_routing_protcol_flag_type {
     REDIRECT_BFD = (1 << 1),
 };
 
+struct tracked_dps {
+    /* Tracked created or updated datapaths. */
+    struct hmapx crupdated;
+    /* Tracked deleted datapaths. */
+    struct hmapx deleted;
+};
+
 struct tracked_ovn_ports {
     /* tracked created ports.
      * hmapx node data is 'struct ovn_port *' */
@@ -141,6 +150,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 +159,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;
 
@@ -433,7 +444,7 @@ ovn_datapaths_find_by_index(const struct ovn_datapaths 
*ovn_datapaths,
                             size_t od_index)
 {
     ovs_assert(od_index <= hmap_count(&ovn_datapaths->datapaths));
-    return ovn_datapaths->array[od_index];
+    return vector_get(&ovn_datapaths->dps, od_index, struct ovn_datapath *);
 }
 
 struct ovn_datapath *ovn_datapath_from_sbrec(
@@ -953,6 +964,13 @@ 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_lswitches_in_tracked_data(
+        struct northd_tracked_data *trk_nd_changes)
+{
+    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..22d11095a 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -14656,6 +14656,67 @@ 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
+
+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
+
+# Create a logical port
+check ovn-nbctl --wait=sb lsp-add sw0 lsp0
+
+# 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 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
+
+AT_CLEANUP
+])
+
 AT_SETUP([RBAC -- Recover builtin role and permissions])
 ovn_start
 
-- 
2.50.1

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

Reply via email to