diff mbox series

[ovs-dev,branch-20.03,06/16] ofctrl.c: Merge opposite changes of tracked flows before installing.

Message ID d006f1dfa8a0bce7a0324ed08fd4271f0d5b115a.1613636533.git.frode.nordahl@canonical.com
State New
Headers show
Series Backport rollup | expand

Commit Message

Frode Nordahl Feb. 18, 2021, 8:50 a.m. UTC
From: Han Zhou <hzhou@ovn.org>

This patch optimizes the previous patch that incrementally processes
flow installation by merging the "add-after-delete" flow changes as
much as possible to avoid unnecessary OpenFlow updates.

Acked-by: Mark Michelson <mmichels@redhat.com>
Signed-off-by: Han Zhou <hzhou@ovn.org>
(cherry picked from commit f4e508dd7a6cfbfc2e3250a8c11a8d0fdc1dfdd0)
Signed-off-by: Frode Nordahl <frode.nordahl@canonical.com>
---
 controller/ofctrl.c | 74 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
diff mbox series

Patch

diff --git a/controller/ofctrl.c b/controller/ofctrl.c
index 3ff8604b1..b526c68f4 100644
--- a/controller/ofctrl.c
+++ b/controller/ofctrl.c
@@ -1631,10 +1631,84 @@  update_installed_flows_by_compare(struct ovn_desired_flow_table *flow_table,
     }
 }
 
+/* Finds and returns a desired_flow in 'deleted_flows' that is exactly the
+ * same as 'target', including cookie and actions.
+ */
+static struct desired_flow *
+deleted_flow_lookup(struct hmap *deleted_flows, struct ovn_flow *target)
+{
+    struct desired_flow *d;
+    HMAP_FOR_EACH_WITH_HASH (d, match_hmap_node, target->hash,
+                             deleted_flows) {
+        struct ovn_flow *f = &d->flow;
+        if (f->table_id == target->table_id
+            && f->priority == target->priority
+            && minimatch_equal(&f->match, &target->match)
+            && f->cookie == target->cookie
+            && ofpacts_equal(f->ofpacts, f->ofpacts_len, target->ofpacts,
+                             target->ofpacts_len)) {
+            return d;
+        }
+    }
+    return NULL;
+}
+
+/* This function scans the tracked flow changes in the order and merges "add"
+ * or "update" after "deleted" operations for exactly same flow (priority,
+ * table, match, action and cookie), to avoid unnecessary OF messages being
+ * sent to OVS. */
+static void
+merge_tracked_flows(struct ovn_desired_flow_table *flow_table)
+{
+    struct hmap deleted_flows = HMAP_INITIALIZER(&deleted_flows);
+    struct desired_flow *f, *next;
+    LIST_FOR_EACH_SAFE (f, next, track_list_node,
+                        &flow_table->tracked_flows) {
+        if (f->is_deleted) {
+            /* reuse f->match_hmap_node field since it is already removed from
+             * the desired flow table's match index. */
+            hmap_insert(&deleted_flows, &f->match_hmap_node,
+                        f->flow.hash);
+        } else {
+            struct desired_flow *del_f = deleted_flow_lookup(&deleted_flows,
+                                                             &f->flow);
+            if (!del_f) {
+                continue;
+            }
+
+            /* del_f must have been installed, otherwise it should have been
+             * removed during track_flow_add_or_modify. */
+            ovs_assert(del_f->installed_flow);
+            if (!f->installed_flow) {
+                /* f is not installed yet. */
+                struct installed_flow *i = del_f->installed_flow;
+                unlink_installed_to_desired(i, del_f);
+                link_installed_to_desired(i, f);
+            } else {
+                /* f has been installed before, and now was updated to exact
+                 * the same flow as del_f. */
+                ovs_assert(f->installed_flow == del_f->installed_flow);
+                unlink_installed_to_desired(del_f->installed_flow, del_f);
+            }
+            hmap_remove(&deleted_flows, &del_f->match_hmap_node);
+            ovs_list_remove(&del_f->track_list_node);
+            desired_flow_destroy(del_f);
+
+            ovs_list_remove(&f->track_list_node);
+            ovs_list_init(&f->track_list_node);
+        }
+    }
+    HMAP_FOR_EACH_SAFE (f, next, match_hmap_node, &deleted_flows) {
+        hmap_remove(&deleted_flows, &f->match_hmap_node);
+    }
+    hmap_destroy(&deleted_flows);
+}
+
 static void
 update_installed_flows_by_track(struct ovn_desired_flow_table *flow_table,
                                 struct ovs_list *msgs)
 {
+    merge_tracked_flows(flow_table);
     struct desired_flow *f, *f_next;
     LIST_FOR_EACH_SAFE (f, f_next, track_list_node,
                         &flow_table->tracked_flows) {