[ovs-dev] [PATCH ovn v6 7/9] ovn-controller: Handle runtime data changes in flow output engine

numans at ovn.org numans at ovn.org
Sat May 16 17:57:10 UTC 2020


From: Numan Siddique <numans at ovn.org>

In order to handle runtime data changes incrementally, the flow outut
runtime data handle should know the changed runtime data.
Runtime data now tracks the changed data for any OVS interface
and SB port binding changes. The tracked data contains a hmap
of tracked datapaths (which changed during runtime data processing.

The flow outout runtime_data handler in this patch doesn't do much
with the tracked data. It returns false if there is tracked data available
so that flow_output run is called. If no tracked data is available
then there is no need for flow computation and the handler returns true.

Next patch in the series processes the tracked data incrementally.

Co-Authored-by: Venkata Anil <anilvenkata at redhat.com>
Signed-off-by: Venkata Anil <anilvenkata at redhat.com>
Signed-off-by: Numan Siddique <numans at ovn.org>
---
 controller/binding.c        | 158 ++++++++++++++++++++++++++++++++----
 controller/binding.h        |  21 +++++
 controller/ovn-controller.c |  62 +++++++++++++-
 tests/ovn-performance.at    |  28 +++----
 4 files changed, 240 insertions(+), 29 deletions(-)

diff --git a/controller/binding.c b/controller/binding.c
index 7e8adacd9..91542f8a1 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -69,13 +69,20 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
     ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_type);
 }
 
+static struct tracked_binding_datapath *tracked_binding_datapath_create(
+    const struct sbrec_datapath_binding *,
+    bool is_new, struct hmap *tracked_dps);
+static struct tracked_binding_datapath *tracked_binding_datapath_find(
+    struct hmap *, const struct sbrec_datapath_binding *);
+
 static void
 add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
                      struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
                      struct ovsdb_idl_index *sbrec_port_binding_by_name,
                      const struct sbrec_datapath_binding *datapath,
                      bool has_local_l3gateway, int depth,
-                     struct hmap *local_datapaths)
+                     struct hmap *local_datapaths,
+                     struct hmap *updated_dp_bindings)
 {
     uint32_t dp_key = datapath->tunnel_key;
     struct local_datapath *ld = get_local_datapath(local_datapaths, dp_key);
@@ -92,6 +99,11 @@ add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
     ld->localnet_port = NULL;
     ld->has_local_l3gateway = has_local_l3gateway;
 
+    if (updated_dp_bindings &&
+        !tracked_binding_datapath_find(updated_dp_bindings, datapath)) {
+        tracked_binding_datapath_create(datapath, true, updated_dp_bindings);
+    }
+
     if (depth >= 100) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
         VLOG_WARN_RL(&rl, "datapaths nested too deep");
@@ -124,7 +136,8 @@ add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
                                              sbrec_port_binding_by_datapath,
                                              sbrec_port_binding_by_name,
                                              peer->datapath, false,
-                                             depth + 1, local_datapaths);
+                                             depth + 1, local_datapaths,
+                                             updated_dp_bindings);
                     }
                     ld->n_peer_ports++;
                     if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
@@ -147,12 +160,14 @@ add_local_datapath(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
                    struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
                    struct ovsdb_idl_index *sbrec_port_binding_by_name,
                    const struct sbrec_datapath_binding *datapath,
-                   bool has_local_l3gateway, struct hmap *local_datapaths)
+                   bool has_local_l3gateway, struct hmap *local_datapaths,
+                   struct hmap *updated_dp_bindings)
 {
     add_local_datapath__(sbrec_datapath_binding_by_key,
                          sbrec_port_binding_by_datapath,
                          sbrec_port_binding_by_name,
-                         datapath, has_local_l3gateway, 0, local_datapaths);
+                         datapath, has_local_l3gateway, 0, local_datapaths,
+                         updated_dp_bindings);
 }
 
 static void
@@ -609,6 +624,71 @@ is_lport_container(const struct sbrec_port_binding *pb)
     return !pb->type[0] && pb->parent_port && pb->parent_port[0];
 }
 
+static struct tracked_binding_datapath *
+tracked_binding_datapath_create(const struct sbrec_datapath_binding *dp,
+                                bool is_new,
+                                struct hmap *tracked_datapaths)
+{
+    struct tracked_binding_datapath *t_dp = xzalloc(sizeof *t_dp);
+    t_dp->dp = dp;
+    t_dp->is_new = is_new;
+    ovs_list_init(&t_dp->lports_head);
+    hmap_insert(tracked_datapaths, &t_dp->node, uuid_hash(&dp->header_.uuid));
+    return t_dp;
+}
+
+static struct tracked_binding_datapath *
+tracked_binding_datapath_find(struct hmap *tracked_datapaths,
+                              const struct sbrec_datapath_binding *dp)
+{
+    struct tracked_binding_datapath *t_dp;
+    size_t hash = uuid_hash(&dp->header_.uuid);
+    HMAP_FOR_EACH_WITH_HASH (t_dp, node, hash, tracked_datapaths) {
+        if (uuid_equals(&t_dp->dp->header_.uuid, &dp->header_.uuid)) {
+            return t_dp;
+        }
+    }
+
+    return NULL;
+}
+
+static void
+tracked_binding_datapath_lport_add(const struct sbrec_port_binding *pb,
+                                   bool deleted,
+                                   struct hmap *tracked_datapaths)
+{
+    if (!tracked_datapaths) {
+        return;
+    }
+
+    struct tracked_binding_datapath *tracked_dp =
+        tracked_binding_datapath_find(tracked_datapaths, pb->datapath);
+    if (!tracked_dp) {
+        tracked_dp = tracked_binding_datapath_create(pb->datapath, false,
+                                                     tracked_datapaths);
+    }
+    struct tracked_binding_lport *lport = xmalloc(sizeof *lport);
+    lport->pb = pb;
+    lport->deleted = deleted;
+    ovs_list_push_back(&tracked_dp->lports_head, &lport->list_node);
+}
+
+void
+binding_tracked_dp_destroy(struct hmap *tracked_datapaths)
+{
+    struct tracked_binding_datapath *t_dp;
+    HMAP_FOR_EACH_POP (t_dp, node, tracked_datapaths) {
+    struct tracked_binding_lport *lport, *next;
+        LIST_FOR_EACH_SAFE (lport, next, list_node, &t_dp->lports_head) {
+            ovs_list_remove(&lport->list_node);
+            free(lport);
+        }
+        free(t_dp);
+    }
+
+    hmap_destroy(tracked_datapaths);
+}
+
 /* Corresponds to each Port_Binding.type. */
 enum en_lport_type {
     LP_VIF,
@@ -751,7 +831,8 @@ can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec,
 
 static bool
 release_local_binding_children(struct local_binding *lbinding,
-                               bool sb_readonly)
+                               bool sb_readonly,
+                               struct hmap *tracked_dp_bindings)
 {
     struct shash_node *node;
     SHASH_FOR_EACH (node, &lbinding->children) {
@@ -759,15 +840,22 @@ release_local_binding_children(struct local_binding *lbinding,
         if (!release_lport(l->pb, sb_readonly)) {
             return false;
         }
+        if (tracked_dp_bindings) {
+            tracked_binding_datapath_lport_add(l->pb, true,
+                                               tracked_dp_bindings);
+        }
     }
 
     return true;
 }
 
 static bool
-release_local_binding(struct local_binding *lbinding, bool sb_readonly)
+release_local_binding(struct local_binding *lbinding,
+                      bool sb_readonly,
+                      struct hmap *tracked_dp_bindings)
 {
-    if (!release_local_binding_children(lbinding, sb_readonly)) {
+    if (!release_local_binding_children(lbinding, sb_readonly,
+                                        tracked_dp_bindings)) {
         return false;
     }
 
@@ -775,6 +863,10 @@ release_local_binding(struct local_binding *lbinding, bool sb_readonly)
         return false;
     }
 
+    if (tracked_dp_bindings) {
+        tracked_binding_datapath_lport_add(lbinding->pb, true,
+                                           tracked_dp_bindings);
+    }
     return true;
 }
 
@@ -798,7 +890,8 @@ consider_vif_lport_(const struct sbrec_port_binding *pb,
             add_local_datapath(b_ctx_in->sbrec_datapath_binding_by_key,
                             b_ctx_in->sbrec_port_binding_by_datapath,
                             b_ctx_in->sbrec_port_binding_by_name,
-                            pb->datapath, false, b_ctx_out->local_datapaths);
+                            pb->datapath, false, b_ctx_out->local_datapaths,
+                            b_ctx_out->tracked_dp_bindings);
             update_local_lport_ids(b_ctx_out->local_lport_ids, pb);
             if (lbinding->iface && qos_map && b_ctx_in->ovs_idl_txn) {
                 get_qos_params(pb, qos_map);
@@ -960,7 +1053,8 @@ consider_nonvif_lport_(const struct sbrec_port_binding *pb,
                            b_ctx_in->sbrec_port_binding_by_datapath,
                            b_ctx_in->sbrec_port_binding_by_name,
                            pb->datapath, has_local_l3gateway,
-                           b_ctx_out->local_datapaths);
+                           b_ctx_out->local_datapaths,
+                           b_ctx_out->tracked_dp_bindings);
 
         update_local_lport_ids(b_ctx_out->local_lport_ids, pb);
         return claim_lport(pb, b_ctx_in->chassis_rec, NULL,
@@ -1037,7 +1131,8 @@ consider_ha_lport(const struct sbrec_port_binding *pb,
                            b_ctx_in->sbrec_port_binding_by_datapath,
                            b_ctx_in->sbrec_port_binding_by_name,
                            pb->datapath, false,
-                           b_ctx_out->local_datapaths);
+                           b_ctx_out->local_datapaths,
+                           b_ctx_out->tracked_dp_bindings);
     }
 
     return consider_nonvif_lport_(pb, our_chassis, false, b_ctx_in, b_ctx_out);
@@ -1305,7 +1400,8 @@ add_local_datapath_peer_port(const struct sbrec_port_binding *pb,
                              b_ctx_in->sbrec_port_binding_by_datapath,
                              b_ctx_in->sbrec_port_binding_by_name,
                              peer->datapath, false,
-                             1, b_ctx_out->local_datapaths);
+                             1, b_ctx_out->local_datapaths,
+                             b_ctx_out->tracked_dp_bindings);
         return;
     }
 
@@ -1382,6 +1478,18 @@ remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
     }
 }
 
+static void
+update_lport_tracking(const struct sbrec_port_binding *pb,
+                      bool old_claim, bool new_claim,
+                      struct hmap *tracked_dp_bindings)
+{
+    if (!tracked_dp_bindings || !pb || (old_claim == new_claim)) {
+        return;
+    }
+
+    tracked_binding_datapath_lport_add(pb, old_claim, tracked_dp_bindings);
+}
+
 static bool
 handle_iface_add(const struct ovsrec_interface *iface_rec,
                  const char *iface_id,
@@ -1410,12 +1518,17 @@ handle_iface_add(const struct ovsrec_interface *iface_rec,
         }
     }
 
+    bool claimed = is_lbinding_this_chassis(lbinding, b_ctx_in->chassis_rec);
     if (lbinding->pb) {
         if (!consider_vif_lport(lbinding->pb, b_ctx_in, b_ctx_out, qos_map)) {
             return false;
         }
     }
 
+    bool now_claimed =
+        is_lbinding_this_chassis(lbinding, b_ctx_in->chassis_rec);
+    update_lport_tracking(lbinding->pb, claimed, now_claimed,
+                          b_ctx_out->tracked_dp_bindings);
     /* Update the child local_binding's iface (if any children) and try to
      *  claim the container lbindings. */
     struct shash_node *node;
@@ -1423,10 +1536,15 @@ handle_iface_add(const struct ovsrec_interface *iface_rec,
         struct local_binding *child = node->data;
         child->iface = iface_rec;
         if (child->type == BT_CONTAINER) {
+            claimed = is_lbinding_this_chassis(child, b_ctx_in->chassis_rec);
             if (!consider_container_lport(child->pb, b_ctx_in, b_ctx_out,
                                           qos_map)) {
                 return false;
             }
+            now_claimed =
+                is_lbinding_this_chassis(child, b_ctx_in->chassis_rec);
+            update_lport_tracking(child->pb, claimed, now_claimed,
+                                  b_ctx_out->tracked_dp_bindings);
         }
     }
 
@@ -1444,7 +1562,8 @@ handle_iface_delete(const char *lport_name, const char *iface_name,
     if (lbinding && lbinding->pb &&
         lbinding->pb->chassis == b_ctx_in->chassis_rec) {
 
-        if (!release_local_binding(lbinding, !b_ctx_in->ovnsb_idl_txn)) {
+        if (!release_local_binding(lbinding, !b_ctx_in->ovnsb_idl_txn,
+                                   b_ctx_out->tracked_dp_bindings)) {
             return false;
         }
 
@@ -1496,6 +1615,7 @@ binding_handle_ovs_interface_changes(struct binding_ctx_in *b_ctx_in,
     struct hmap *qos_map_ptr =
         sset_is_empty(b_ctx_out->egress_ifaces) ? NULL : &qos_map;
 
+    *b_ctx_out->local_lports_changed = false;
     const struct ovsrec_interface *iface_rec;
     OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec,
                                              b_ctx_in->iface_table) {
@@ -1618,8 +1738,9 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb,
          * clear the 'chassis' column of 'pb'. But we need to do
          * for the local_binding's children. */
         if (lbinding->type == BT_VIF &&
-                !release_local_binding_children(lbinding,
-                                                !b_ctx_in->ovnsb_idl_txn)) {
+                !release_local_binding_children(
+                    lbinding, !b_ctx_in->ovnsb_idl_txn,
+                    b_ctx_out->tracked_dp_bindings)) {
             return false;
         }
 
@@ -1661,6 +1782,9 @@ handle_updated_vif_lport(const struct sbrec_port_binding *pb,
         return true;
     }
 
+    update_lport_tracking(pb, claimed, now_claimed,
+                          b_ctx_out->tracked_dp_bindings);
+
     struct local_binding *lbinding =
         local_binding_find(b_ctx_out->local_bindings, pb->logical_port);
 
@@ -1670,11 +1794,17 @@ handle_updated_vif_lport(const struct sbrec_port_binding *pb,
     SHASH_FOR_EACH (node, &lbinding->children) {
         struct local_binding *child = node->data;
         if (child->type == BT_CONTAINER) {
+            claimed = is_lbinding_this_chassis(child, b_ctx_in->chassis_rec);
             handled = consider_container_lport(child->pb, b_ctx_in, b_ctx_out,
                                                qos_map);
             if (!handled) {
                 return false;
             }
+
+            now_claimed = is_lbinding_this_chassis(child,
+                                                   b_ctx_in->chassis_rec);
+            update_lport_tracking(child->pb, claimed, now_claimed,
+                                  b_ctx_out->tracked_dp_bindings);
         }
     }
 
diff --git a/controller/binding.h b/controller/binding.h
index 21118ecd4..fc2a673e5 100644
--- a/controller/binding.h
+++ b/controller/binding.h
@@ -19,6 +19,9 @@
 
 #include <stdbool.h>
 #include "openvswitch/shash.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/uuid.h"
+#include "openvswitch/list.h"
 
 struct hmap;
 struct ovsdb_idl;
@@ -58,6 +61,8 @@ struct binding_ctx_out {
     struct sset *local_lport_ids;
     struct sset *egress_ifaces;
     struct smap *local_iface_ids;
+    struct hmap *tracked_dp_bindings;
+    bool *local_lports_changed;
 };
 
 enum local_binding_type {
@@ -82,6 +87,21 @@ local_binding_find(struct shash *local_bindings, const char *name)
     return shash_find_data(local_bindings, name);
 }
 
+/* Represents a tracked binding logical port. */
+struct tracked_binding_lport {
+    const struct sbrec_port_binding *pb;
+    struct ovs_list list_node;
+    bool deleted;
+};
+
+/* Represent a tracked binding datapath. */
+struct tracked_binding_datapath {
+    struct hmap_node node;
+    const struct sbrec_datapath_binding *dp;
+    bool is_new;
+    struct ovs_list lports_head; /* List of struct tracked_binding_lport. */
+};
+
 void binding_register_ovs_idl(struct ovsdb_idl *);
 void binding_run(struct binding_ctx_in *, struct binding_ctx_out *);
 bool binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn,
@@ -96,4 +116,5 @@ bool binding_handle_ovs_interface_changes(struct binding_ctx_in *,
 bool binding_handle_port_binding_changes(struct binding_ctx_in *,
                                          struct binding_ctx_out *,
                                          bool *changed);
+void binding_tracked_dp_destroy(struct hmap *tracked_datapaths);
 #endif /* controller/binding.h */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 10da807e4..282081e79 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -978,6 +978,23 @@ struct ed_type_runtime_data {
     struct smap local_iface_ids;
 };
 
+struct ed_type_runtime_tracked_data {
+    struct hmap tracked_dp_bindings;
+    bool local_lports_changed;
+    bool tracked;
+};
+
+static void
+en_runtime_clear_tracked_data(void *tracked_data)
+{
+    struct ed_type_runtime_tracked_data *data = tracked_data;
+
+    binding_tracked_dp_destroy(&data->tracked_dp_bindings);
+    hmap_init(&data->tracked_dp_bindings);
+    data->local_lports_changed = false;
+    data->tracked = false;
+}
+
 static void *
 en_runtime_data_init(struct engine_node *node OVS_UNUSED,
                      struct engine_arg *arg OVS_UNUSED)
@@ -991,6 +1008,13 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED,
     sset_init(&data->egress_ifaces);
     smap_init(&data->local_iface_ids);
     local_bindings_init(&data->local_bindings);
+
+    struct ed_type_runtime_tracked_data *tracked_data =
+        xzalloc(sizeof *tracked_data);
+    hmap_init(&tracked_data->tracked_dp_bindings);
+    node->tracked_data = tracked_data;
+    node->clear_tracked_data = en_runtime_clear_tracked_data;
+
     return data;
 }
 
@@ -1094,6 +1118,8 @@ init_binding_ctx(struct engine_node *node,
     b_ctx_out->egress_ifaces = &rt_data->egress_ifaces;
     b_ctx_out->local_bindings = &rt_data->local_bindings;
     b_ctx_out->local_iface_ids = &rt_data->local_iface_ids;
+    b_ctx_out->tracked_dp_bindings = NULL;
+    b_ctx_out->local_lports_changed = NULL;
 }
 
 static void
@@ -1105,6 +1131,8 @@ en_runtime_data_run(struct engine_node *node, void *data)
     struct sset *local_lport_ids = &rt_data->local_lport_ids;
     struct sset *active_tunnels = &rt_data->active_tunnels;
 
+    en_runtime_clear_tracked_data(node->tracked_data);
+
     static bool first_run = true;
     if (first_run) {
         /* don't cleanup since there is no data yet */
@@ -1157,9 +1185,13 @@ static bool
 runtime_data_ovs_interface_handler(struct engine_node *node, void *data)
 {
     struct ed_type_runtime_data *rt_data = data;
+    struct ed_type_runtime_tracked_data *tracked_data = node->tracked_data;
     struct binding_ctx_in b_ctx_in;
     struct binding_ctx_out b_ctx_out;
     init_binding_ctx(node, rt_data, &b_ctx_in, &b_ctx_out);
+    tracked_data->tracked = true;
+    b_ctx_out.tracked_dp_bindings = &tracked_data->tracked_dp_bindings;
+    b_ctx_out.local_lports_changed = &tracked_data->local_lports_changed;
 
     bool changed = false;
     if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out,
@@ -1192,6 +1224,10 @@ runtime_data_sb_port_binding_handler(struct engine_node *node, void *data)
         return false;
     }
 
+    struct ed_type_runtime_tracked_data *tracked_data = node->tracked_data;
+    tracked_data->tracked = true;
+    b_ctx_out.tracked_dp_bindings = &tracked_data->tracked_dp_bindings;
+
     bool changed = false;
     if (!binding_handle_port_binding_changes(&b_ctx_in, &b_ctx_out,
                                              &changed)) {
@@ -1863,6 +1899,29 @@ physical_flow_changes_ovs_iface_handler(struct engine_node *node OVS_UNUSED,
     return true;
 }
 
+static bool
+flow_output_runtime_data_handler(struct engine_node *node,
+                                 void *data OVS_UNUSED)
+{
+    struct ed_type_runtime_tracked_data *tracked_data =
+        engine_get_input_tracked_data("runtime_data", node);
+
+    if (!tracked_data || !tracked_data->tracked) {
+        return false;
+    }
+
+    if (!hmap_is_empty(&tracked_data->tracked_dp_bindings)) {
+        /* We are not yet handling the tracked datapath binding
+         * changes. Return false to trigger full recompute. */
+        return false;
+    }
+
+    if (tracked_data->local_lports_changed) {
+        engine_set_node_state(node, EN_UPDATED);
+    }
+    return true;
+}
+
 struct ovn_controller_exit_args {
     bool *exiting;
     bool *restart;
@@ -2014,7 +2073,8 @@ main(int argc, char *argv[])
                      flow_output_addr_sets_handler);
     engine_add_input(&en_flow_output, &en_port_groups,
                      flow_output_port_groups_handler);
-    engine_add_input(&en_flow_output, &en_runtime_data, NULL);
+    engine_add_input(&en_flow_output, &en_runtime_data,
+                     flow_output_runtime_data_handler);
     engine_add_input(&en_flow_output, &en_mff_ovn_geneve, NULL);
     engine_add_input(&en_flow_output, &en_physical_flow_changes,
                      flow_output_physical_flow_changes_handler);
diff --git a/tests/ovn-performance.at b/tests/ovn-performance.at
index 5cc1960b6..6e064e64f 100644
--- a/tests/ovn-performance.at
+++ b/tests/ovn-performance.at
@@ -274,7 +274,7 @@ for i in 1 2; do
     )
 
     # Add router port to $ls
-    OVN_CONTROLLER_EXPECT_HIT(
+    OVN_CONTROLLER_EXPECT_NO_HIT(
         [hv1 hv2], [lflow_run],
         [ovn-nbctl --wait=hv lrp-add lr1 $lrp 02:00:00:00:0$i:01 10.0.$i.1/24]
     )
@@ -282,15 +282,15 @@ for i in 1 2; do
         [hv1 hv2], [lflow_run],
         [ovn-nbctl --wait=hv lsp-add $ls $lsp]
     )
-    OVN_CONTROLLER_EXPECT_HIT(
+    OVN_CONTROLLER_EXPECT_NO_HIT(
         [hv1 hv2], [lflow_run],
         [ovn-nbctl --wait=hv lsp-set-type $lsp router]
     )
-    OVN_CONTROLLER_EXPECT_HIT(
+    OVN_CONTROLLER_EXPECT_NO_HIT(
         [hv1 hv2], [lflow_run],
         [ovn-nbctl --wait=hv lsp-set-options $lsp router-port=$lrp]
     )
-    OVN_CONTROLLER_EXPECT_HIT(
+    OVN_CONTROLLER_EXPECT_NO_HIT(
         [hv1 hv2], [lflow_run],
         [ovn-nbctl --wait=hv lsp-set-addresses $lsp router]
     )
@@ -404,8 +404,8 @@ for i in 1 2; do
     lp=lp$i
 
     # Delete port $lp
-    OVN_CONTROLLER_EXPECT_HIT_COND(
-        [hv$i hv$j], [lflow_run], [>0 =0],
+    OVN_CONTROLLER_EXPECT_NO_HIT(
+        [hv$i hv$j], [lflow_run],
         [ovn-nbctl --wait=hv lsp-del $lp]
     )
 done
@@ -416,15 +416,15 @@ OVN_CONTROLLER_EXPECT_NO_HIT(
     [ovn-nbctl --wait=hv destroy Port_Group pg1]
 )
 
-for i in 1 2; do
-    ls=ls$i
+OVN_CONTROLLER_EXPECT_HIT(
+    [hv1 hv2], [lflow_run],
+    [ovn-nbctl --wait=hv ls-del ls1]
+)
 
-    # Delete switch $ls
-    OVN_CONTROLLER_EXPECT_HIT(
-        [hv1 hv2], [lflow_run],
-        [ovn-nbctl --wait=hv ls-del $ls]
-    )
-done
+OVN_CONTROLLER_EXPECT_NO_HIT(
+    [hv1 hv2], [lflow_run],
+    [ovn-nbctl --wait=hv ls-del ls2]
+)
 
 # Delete router lr1
 OVN_CONTROLLER_EXPECT_NO_HIT(
-- 
2.26.2



More information about the dev mailing list