Prior to this commit, an lflow_ref_node would be created the first time
that an lflow was added to an lflow_ref. If this lflow was added for a
single datapath, then the lflow_ref_node would reference that single
datapath. If the lflow was added for a datapath_group, then the
lflow_ref_node would reference all datapaths in the group.

If the same lflow were added to the same lflow_ref a second time, but
specified a different datapath than the first time the lflow was added,
then the lflow_ref_node remained unchanged, even though the lflow now
applied to one or more new datapaths.

In most cases, this is fine, because lflows are only added once per
lflow_ref. The IGMP lflow_ref, on the other hand, works differently.
There is only a single lflow_ref for all of IGMP. Therefore, it is
possible (probable, even) for the same lflow to be added multiple times
to the same lflow_ref, each time for a different datapath.

Most lflow input node handlers start by calling lflow_ref_unlink_lflows().
This removes all of the datapath references from the lflow_ref and sets all
lflow_ref_nodes within the lflow_ref to be unlinked. Then the handler re-builds
the relevant lflows, causing any corresponding lflow_ref_nodes to be re-linked,
based on the datapath the lflow was added for. Finally, the handler calls
lflow_ref_sync_lflows(). This causes all lflows in the lflow_ref to be
synced with the southbound Logical_Flow table. Any lflow_ref_nodes that were
unlinked and not re-linked will either have their lflow's corresponding
Logical_Flow datapath-related columns updated, or they will have their
record deleted entirely if the lflow no longer has any datapath references.

This particular workflow breaks in the case that the lflow was added
multiple times to the lflow_ref, each with a different datapath. The
lflow_ref_node is only aware of the first datapath for which the lflow
was added. So when the lflow_ref_node is unlinked, only the reference to
that particular datapath is removed from the lflow. Therefore, the lflow
may still have references to datapaths in its dpg_bitmap field that
should have been removed when the lflow_ref_node was unlinked. After
rebuilding the flows and re-syncing, those leftover datapaths will still
be in the lflow, resulting in the southbound Logical_Flow referencing
datapaths for which the flow should have been removed. This translates
to the datapath in question having the lflow installed when it should
have been removed.

The IGMP lflow handler gets around this by calling
lflow_ref_resync_flows() instead of lflow_ref_unlink_lflows() at the
beginning. This causes the lflow_ref_nodes to be unlinked and synced
immediately before attempting to rebuild the lflows. Since no
lflow_ref_nodes had a chance to be re-linked, it results in all of the
lflows in the IGMP lflow_ref being deleted (both in memory and in the
Southbound Logical_Flow table), then the lflows are rebuilt from scratch.
Since the lflows are re-created entirely, there is no possibility of stray
datapaths being referenced.

The next change in this series is going to separate lflow_ref
unlinking/rebuilding into one engine node and lflow_ref syncing into a
separate one. Because of that, the en-lflow IGMP input handler can no longer
call lflow_ref_resync_flows(). It needs to use lflow_ref_unlink_lflows() like
the other lflow input handlers do. But as stated in an earlier paragraph, this
causes stray datapaths to be referenced by the southbound Logical_Flow table.

This change modifies how lflow_ref_nodes handle their datapath
references. lflow_ref_nodes can now have their datapath references updated
when an lflow is added to an lflow_ref multiple times. To accomplish this, the
lflow_ref_node dgrp_bitmap and dp_index fields have been combined into a
bitmap field, dp_bitmap. Whether a single datapath or a datapath group is
referenced by the added lflow, we handle it the same in the lflow_ref_node, by
using the dp_bitmap.

Signed-off-by: Mark Michelson <mmich...@redhat.com>
---
 northd/lflow-mgr.c | 79 +++++++++++++++++++---------------------------
 1 file changed, 33 insertions(+), 46 deletions(-)

diff --git a/northd/lflow-mgr.c b/northd/lflow-mgr.c
index 0f7b989cf..aa8e60478 100644
--- a/northd/lflow-mgr.c
+++ b/northd/lflow-mgr.c
@@ -558,13 +558,11 @@ struct lflow_ref_node {
     /* Indicates whether the lflow was added with a dp_group using the
      * ovn_lflow_add_with_dp_group() macro. */
     bool dpgrp_lflow;
-    /* dpgrp bitmap and bitmap length.  Valid only of dpgrp_lflow is true. */
-    unsigned long *dpgrp_bitmap;
-    size_t dpgrp_bitmap_len;
-
-    /* Index id of the datapath this lflow_ref_node belongs to.
-     * Valid only if dpgrp_lflow is false. */
-    size_t dp_index;
+    /* dp bitmap and bitmap length.  Used to track all datapaths that
+     * the lflow references
+     */
+    unsigned long *dp_bitmap;
+    size_t dp_bitmap_len;
 
     /* Indicates if the lflow_ref_node for an lflow - L(M, A) is linked
      * to datapath(s) or not.
@@ -600,10 +598,11 @@ lflow_ref_destroy(struct lflow_ref *lflow_ref)
 }
 
 /* Unlinks the lflows referenced by the 'lflow_ref'.
- * For each lflow_ref_node (lrn) in the lflow_ref, it basically clears
- * the datapath id (lrn->dp_index) or all the datapath id bits in the
- * dp group bitmap (set when ovn_lflow_add_with_dp_group macro was used)
- * from the lrn->lflow's dpg bitmap
+ * For each lflow_ref_node (lrn) in the lflow_ref, it removes the
+ * datapath references in the lrn. If all references are removed
+ * for a particular datapath index, then the bit is cleared from
+ * the lflow's dpg_bitmap, indicating the lflow no longer applies
+ * to the corresponding datapath.
  */
 void
 lflow_ref_unlink_lflows(struct lflow_ref *lflow_ref)
@@ -611,21 +610,12 @@ lflow_ref_unlink_lflows(struct lflow_ref *lflow_ref)
     struct lflow_ref_node *lrn;
 
     HMAP_FOR_EACH (lrn, ref_node, &lflow_ref->lflow_ref_nodes) {
-        if (lrn->dpgrp_lflow) {
-            size_t index;
-            BITMAP_FOR_EACH_1 (index, lrn->dpgrp_bitmap_len,
-                               lrn->dpgrp_bitmap) {
-                if (dp_refcnt_release(&lrn->lflow->dp_refcnts_map, index)) {
-                    bitmap_set0(lrn->lflow->dpg_bitmap, index);
-                }
-            }
-        } else {
-            if (dp_refcnt_release(&lrn->lflow->dp_refcnts_map,
-                                  lrn->dp_index)) {
-                bitmap_set0(lrn->lflow->dpg_bitmap, lrn->dp_index);
+        size_t index;
+        BITMAP_FOR_EACH_1 (index, lrn->dp_bitmap_len, lrn->dp_bitmap) {
+            if (dp_refcnt_release(&lrn->lflow->dp_refcnts_map, index)) {
+                bitmap_set0(lrn->lflow->dpg_bitmap, index);
             }
         }
-
         lrn->linked = false;
     }
 }
@@ -673,9 +663,10 @@ lflow_ref_sync_lflows(struct lflow_ref *lflow_ref,
  *
  * If 'lflow_ref' is not NULL then
  *    - it first checks if the lflow is present in the lflow_ref or not
- *    - if present, then it does nothing
  *    - if not present, then it creates an lflow_ref_node object for
  *      the [L(M, A), dp index] and adds ito the lflow_ref hmap.
+ *    - if present, then the lflow_ref_node object's dp_bitmap is
+ *      updated to include the new datapath.
  *
  * Note that this function is not thread safe for 'lflow_ref'.
  * If 2 or more threads calls this function for the same 'lflow_ref',
@@ -719,31 +710,27 @@ lflow_table_add_lflow(struct lflow_table *lflow_table,
             lrn = xzalloc(sizeof *lrn);
             lrn->lflow = lflow;
             lrn->lflow_ref = lflow_ref;
-            lrn->dpgrp_lflow = !od;
-            if (lrn->dpgrp_lflow) {
-                lrn->dpgrp_bitmap = bitmap_clone(dp_bitmap, dp_bitmap_len);
-                lrn->dpgrp_bitmap_len = dp_bitmap_len;
-            } else {
-                lrn->dp_index = od->index;
-            }
+            lrn->dp_bitmap_len = od ? ods_size(od->datapaths) : dp_bitmap_len;
+            lrn->dp_bitmap = bitmap_allocate(lrn->dp_bitmap_len);
             ovs_list_insert(&lflow->referenced_by, &lrn->ref_list_node);
             hmap_insert(&lflow_ref->lflow_ref_nodes, &lrn->ref_node, hash);
         }
 
-        if (!lrn->linked) {
-            if (lrn->dpgrp_lflow) {
-                ovs_assert(lrn->dpgrp_bitmap_len == dp_bitmap_len);
-                size_t index;
-                BITMAP_FOR_EACH_1 (index, dp_bitmap_len, dp_bitmap) {
-                    /* Allocate a reference counter only if already used. */
-                    if (bitmap_is_set(lflow->dpg_bitmap, index)) {
-                        dp_refcnt_use(&lflow->dp_refcnts_map, index);
-                    }
-                }
-            } else {
+        /* Add refcounts for any datapaths already being used by this
+         * lflow.
+         */
+        if (od) {
+            bitmap_set1(lrn->dp_bitmap, od->index);
+            if (bitmap_is_set(lflow->dpg_bitmap, od->index)) {
+                dp_refcnt_use(&lflow->dp_refcnts_map, od->index);
+            }
+        } else {
+            size_t index;
+            BITMAP_FOR_EACH_1 (index, dp_bitmap_len, dp_bitmap) {
+                bitmap_set1(lrn->dp_bitmap, index);
                 /* Allocate a reference counter only if already used. */
-                if (bitmap_is_set(lflow->dpg_bitmap, lrn->dp_index)) {
-                    dp_refcnt_use(&lflow->dp_refcnts_map, lrn->dp_index);
+                if (bitmap_is_set(lflow->dpg_bitmap, index)) {
+                    dp_refcnt_use(&lflow->dp_refcnts_map, index);
                 }
             }
         }
@@ -1434,7 +1421,7 @@ lflow_ref_node_destroy(struct lflow_ref_node *lrn)
     hmap_remove(&lrn->lflow_ref->lflow_ref_nodes, &lrn->ref_node);
     ovs_list_remove(&lrn->ref_list_node);
     if (lrn->dpgrp_lflow) {
-        bitmap_free(lrn->dpgrp_bitmap);
+        bitmap_free(lrn->dp_bitmap);
     }
     free(lrn);
 }
-- 
2.47.0

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

Reply via email to