5f9769
From 47afa0664d6a41d0a75a65f0ba927974d957cb62 Mon Sep 17 00:00:00 2001
5f9769
From: Dumitru Ceara <dceara@redhat.com>
5f9769
Date: Mon, 18 Jan 2021 17:50:33 +0100
5f9769
Subject: [PATCH 2/2] binding: Always delete child port bindings first.
5f9769
5f9769
When incrementally processing changes, child Port Bindings (container
5f9769
and virtual ports) must be deleted first, before their parents, because
5f9769
they need to be removed from their parent's children hash to avoid
5f9769
parents with children with NULL port bindings.
5f9769
5f9769
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
5f9769
Signed-off-by: Numan Siddique <numans@ovn.org>
5f9769
(cherry picked from master commit de8030e6abc7b51dd2ee48bbe2c76592ef8b064c)
5f9769
5f9769
Change-Id: I382f463b757df1ff0f3b5b0e6ec2050d4e7811ed
5f9769
---
5f9769
 controller/binding.c | 75 +++++++++++++++++++++++++++++++++++++++++++++-------
5f9769
 tests/ovn.at         | 18 +++++++++++++
5f9769
 2 files changed, 83 insertions(+), 10 deletions(-)
5f9769
5f9769
diff --git a/controller/binding.c b/controller/binding.c
5f9769
index 3512a1d..c8e8591 100644
5f9769
--- a/controller/binding.c
5f9769
+++ b/controller/binding.c
5f9769
@@ -2147,13 +2147,26 @@ bool
5f9769
 binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in,
5f9769
                                     struct binding_ctx_out *b_ctx_out)
5f9769
 {
5f9769
-    bool handled = true;
5f9769
+    /* Run the tracked port binding loop twice to ensure correctness:
5f9769
+     * 1. First to handle deleted changes.  This is split in four sub-parts
5f9769
+     *    because child local bindings must be cleaned up first:
5f9769
+     *    a. Container ports first.
5f9769
+     *    b. Then virtual ports.
5f9769
+     *    c. Then regular VIFs.
5f9769
+     *    d. Last other ports.
5f9769
+     * 2. Second to handle add/update changes.
5f9769
+     */
5f9769
+    struct shash deleted_container_pbs =
5f9769
+        SHASH_INITIALIZER(&deleted_container_pbs);
5f9769
+    struct shash deleted_virtual_pbs =
5f9769
+        SHASH_INITIALIZER(&deleted_virtual_pbs);
5f9769
+    struct shash deleted_vif_pbs =
5f9769
+        SHASH_INITIALIZER(&deleted_vif_pbs);
5f9769
+    struct shash deleted_other_pbs =
5f9769
+        SHASH_INITIALIZER(&deleted_other_pbs);
5f9769
     const struct sbrec_port_binding *pb;
5f9769
+    bool handled = true;
5f9769
 
5f9769
-    /* Run the tracked port binding loop twice. One to handle deleted
5f9769
-     * changes. And another to handle add/update changes.
5f9769
-     * This will ensure correctness.
5f9769
-     */
5f9769
     SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb,
5f9769
                                                b_ctx_in->port_binding_table) {
5f9769
         if (!sbrec_port_binding_is_deleted(pb)) {
5f9769
@@ -2161,18 +2174,60 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in,
5f9769
         }
5f9769
 
5f9769
         enum en_lport_type lport_type = get_lport_type(pb);
5f9769
-        if (lport_type == LP_VIF || lport_type == LP_VIRTUAL) {
5f9769
-            handled = handle_deleted_vif_lport(pb, lport_type, b_ctx_in,
5f9769
-                                               b_ctx_out);
5f9769
+
5f9769
+        if (lport_type == LP_VIF) {
5f9769
+            if (is_lport_container(pb)) {
5f9769
+                shash_add(&deleted_container_pbs, pb->logical_port, pb);
5f9769
+            } else {
5f9769
+                shash_add(&deleted_vif_pbs, pb->logical_port, pb);
5f9769
+            }
5f9769
+        } else if (lport_type == LP_VIRTUAL) {
5f9769
+            shash_add(&deleted_virtual_pbs, pb->logical_port, pb);
5f9769
         } else {
5f9769
-            handle_deleted_lport(pb, b_ctx_in, b_ctx_out);
5f9769
+            shash_add(&deleted_other_pbs, pb->logical_port, pb);
5f9769
+        }
5f9769
+    }
5f9769
+
5f9769
+    struct shash_node *node;
5f9769
+    struct shash_node *node_next;
5f9769
+    SHASH_FOR_EACH_SAFE (node, node_next, &deleted_container_pbs) {
5f9769
+        handled = handle_deleted_vif_lport(node->data, LP_VIF, b_ctx_in,
5f9769
+                                           b_ctx_out);
5f9769
+        shash_delete(&deleted_container_pbs, node);
5f9769
+        if (!handled) {
5f9769
+            goto delete_done;
5f9769
         }
5f9769
+    }
5f9769
 
5f9769
+    SHASH_FOR_EACH_SAFE (node, node_next, &deleted_virtual_pbs) {
5f9769
+        handled = handle_deleted_vif_lport(node->data, LP_VIRTUAL, b_ctx_in,
5f9769
+                                           b_ctx_out);
5f9769
+        shash_delete(&deleted_virtual_pbs, node);
5f9769
         if (!handled) {
5f9769
-            break;
5f9769
+            goto delete_done;
5f9769
+        }
5f9769
+    }
5f9769
+
5f9769
+    SHASH_FOR_EACH_SAFE (node, node_next, &deleted_vif_pbs) {
5f9769
+        handled = handle_deleted_vif_lport(node->data, LP_VIF, b_ctx_in,
5f9769
+                                           b_ctx_out);
5f9769
+        shash_delete(&deleted_vif_pbs, node);
5f9769
+        if (!handled) {
5f9769
+            goto delete_done;
5f9769
         }
5f9769
     }
5f9769
 
5f9769
+    SHASH_FOR_EACH_SAFE (node, node_next, &deleted_other_pbs) {
5f9769
+        handle_deleted_lport(node->data, b_ctx_in, b_ctx_out);
5f9769
+        shash_delete(&deleted_other_pbs, node);
5f9769
+    }
5f9769
+
5f9769
+delete_done:
5f9769
+    shash_destroy(&deleted_container_pbs);
5f9769
+    shash_destroy(&deleted_virtual_pbs);
5f9769
+    shash_destroy(&deleted_vif_pbs);
5f9769
+    shash_destroy(&deleted_other_pbs);
5f9769
+
5f9769
     if (!handled) {
5f9769
         return false;
5f9769
     }
5f9769
diff --git a/tests/ovn.at b/tests/ovn.at
5f9769
index 2cdc036..e2d2d8a 100644
5f9769
--- a/tests/ovn.at
5f9769
+++ b/tests/ovn.at
5f9769
@@ -22194,6 +22194,24 @@ check ovn-nbctl lsp-add ls2 lsp-cont1 lsp1 1
5f9769
 check ovn-nbctl --wait=hv sync
5f9769
 check_row_count Port_Binding 1 logical_port=lsp-cont1 chassis=$ch
5f9769
 
5f9769
+AS_BOX([delete both OVN VIF and OVN container port])
5f9769
+as hv1 ovn-appctl -t ovn-controller debug/pause
5f9769
+check ovn-nbctl lsp-del lsp1 \
5f9769
+    -- lsp-del lsp-cont1
5f9769
+check ovn-nbctl --wait=sb sync
5f9769
+as hv1 ovn-appctl -t ovn-controller debug/resume
5f9769
+
5f9769
+AS_BOX([readd both OVN VIF and OVN container port])
5f9769
+as hv1 ovn-appctl -t ovn-controller debug/pause
5f9769
+check ovn-nbctl lsp-add ls1 lsp1 \
5f9769
+    -- lsp-add ls2 lsp-cont1 lsp1 1
5f9769
+check ovn-nbctl --wait=sb sync
5f9769
+as hv1 ovn-appctl -t ovn-controller debug/resume
5f9769
+
5f9769
+check ovn-nbctl --wait=hv sync
5f9769
+wait_row_count Port_Binding 1 logical_port=lsp1 chassis=$ch
5f9769
+wait_row_count Port_Binding 1 logical_port=lsp-cont1 chassis=$ch
5f9769
+
5f9769
 OVN_CLEANUP([hv1])
5f9769
 AT_CLEANUP
5f9769
 
5f9769
-- 
5f9769
1.8.3.1
5f9769