bbaaef
From b52c176dd76bc0321d9c8bfe1c9b4832daf64835 Mon Sep 17 00:00:00 2001
bbaaef
From: Mark Michelson <mmichels@redhat.com>
bbaaef
Date: Fri, 25 Oct 2019 13:25:12 -0400
bbaaef
Subject: [PATCH 2/2] Combine conjunctions with identical matches into one
bbaaef
 flow.
bbaaef
bbaaef
As stated in previous commits, conjunctive matches have an issue where
bbaaef
it is possible to install multiple flows that have identical matches.
bbaaef
This results in ambiguity, and can lead to features (such as ACLs) not
bbaaef
functioning properly.
bbaaef
bbaaef
This change fixes the problem by combining conjunctions with identical
bbaaef
matches into a single flow. As an example, in the past we may have had
bbaaef
something like:
bbaaef
bbaaef
nw_dst=10.0.0.1 actions=conjunction(2,1/2)
bbaaef
nw_dst=10.0.0.1 actions=conjunction(3,1/2)
bbaaef
bbaaef
This commit changes this into
bbaaef
bbaaef
nw_dst=10.0.0.1 actions=conjunction(2,1/2),conjunction(3,1/2)
bbaaef
bbaaef
This way, there is only a single flow with the proscribed match, and
bbaaef
there is no ambiguity.
bbaaef
bbaaef
Signed-off-by: Mark Michelson <mmichels@redhat.com>
bbaaef
---
bbaaef
 ovn/controller/lflow.c  |  5 ++--
bbaaef
 ovn/controller/ofctrl.c | 74 +++++++++++++++++++++++++++++++++++++++++++++--------
bbaaef
 ovn/controller/ofctrl.h |  6 +++++
bbaaef
 tests/ovn.at        | 17 +++++-------
bbaaef
 4 files changed, 80 insertions(+), 22 deletions(-)
bbaaef
bbaaef
diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
bbaaef
index 24e3a521e..f34abcebc 100644
bbaaef
--- a/ovn/controller/lflow.c
bbaaef
+++ b/ovn/controller/lflow.c
bbaaef
@@ -734,8 +734,9 @@ consider_logical_flow(
bbaaef
                 dst->clause = src->clause;
bbaaef
                 dst->n_clauses = src->n_clauses;
bbaaef
             }
bbaaef
-            ofctrl_add_flow(flow_table, ptable, lflow->priority, 0, &m->match,
bbaaef
-                            &conj, &lflow->header_.uuid);
bbaaef
+
bbaaef
+            ofctrl_add_or_append_flow(flow_table, ptable, lflow->priority, 0,
bbaaef
+                                      &m->match, &conj, &lflow->header_.uuid);
bbaaef
             ofpbuf_uninit(&conj;;
bbaaef
         }
bbaaef
     }
bbaaef
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
bbaaef
index 3131baff0..10edd84fb 100644
bbaaef
--- a/ovn/controller/ofctrl.c
bbaaef
+++ b/ovn/controller/ofctrl.c
bbaaef
@@ -69,6 +69,11 @@ struct ovn_flow {
bbaaef
     uint64_t cookie;
bbaaef
 };
bbaaef
 
bbaaef
+static struct ovn_flow *ovn_flow_alloc(uint8_t table_id, uint16_t priority,
bbaaef
+                                       uint64_t cookie,
bbaaef
+                                       const struct match *match,
bbaaef
+                                       const struct ofpbuf *actions,
bbaaef
+                                       const struct uuid *sb_uuid);
bbaaef
 static uint32_t ovn_flow_match_hash(const struct ovn_flow *);
bbaaef
 static struct ovn_flow *ovn_flow_lookup(struct hmap *flow_table,
bbaaef
                                         const struct ovn_flow *target,
bbaaef
@@ -657,16 +662,8 @@ ofctrl_check_and_add_flow(struct ovn_desired_flow_table *flow_table,
bbaaef
                           const struct uuid *sb_uuid,
bbaaef
                           bool log_duplicate_flow)
bbaaef
 {
bbaaef
-    struct ovn_flow *f = xmalloc(sizeof *f);
bbaaef
-    f->table_id = table_id;
bbaaef
-    f->priority = priority;
bbaaef
-    minimatch_init(&f->match, match);
bbaaef
-    f->ofpacts = xmemdup(actions->data, actions->size);
bbaaef
-    f->ofpacts_len = actions->size;
bbaaef
-    f->sb_uuid = *sb_uuid;
bbaaef
-    f->match_hmap_node.hash = ovn_flow_match_hash(f);
bbaaef
-    f->uuid_hindex_node.hash = uuid_hash(&f->sb_uuid);
bbaaef
-    f->cookie = cookie;
bbaaef
+    struct ovn_flow *f = ovn_flow_alloc(table_id, priority, cookie, match,
bbaaef
+                                        actions, sb_uuid);
bbaaef
 
bbaaef
     ovn_flow_log(f, "ofctrl_add_flow");
bbaaef
 
bbaaef
@@ -721,9 +718,66 @@ ofctrl_add_flow(struct ovn_desired_flow_table *desired_flows,
bbaaef
     ofctrl_check_and_add_flow(desired_flows, table_id, priority, cookie,
bbaaef
                               match, actions, sb_uuid, true);
bbaaef
 }
bbaaef
+
bbaaef
+void
bbaaef
+ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
bbaaef
+                          uint8_t table_id, uint16_t priority, uint64_t cookie,
bbaaef
+                          const struct match *match,
bbaaef
+                          const struct ofpbuf *actions,
bbaaef
+                          const struct uuid *sb_uuid)
bbaaef
+{
bbaaef
+    struct ovn_flow *f = ovn_flow_alloc(table_id, priority, cookie, match,
bbaaef
+                                        actions, sb_uuid);
bbaaef
+
bbaaef
+    ovn_flow_log(f, "ofctrl_add_or_append_flow");
bbaaef
+
bbaaef
+    struct ovn_flow *existing;
bbaaef
+    existing = ovn_flow_lookup(&desired_flows->match_flow_table, f, false);
bbaaef
+    if (existing) {
bbaaef
+        /* There's already a flow with this particular match. Append the
bbaaef
+         * action to that flow rather than adding a new flow
bbaaef
+         */
bbaaef
+        uint64_t compound_stub[64 / 8];
bbaaef
+        struct ofpbuf compound;
bbaaef
+        ofpbuf_use_stub(&compound, compound_stub, sizeof(compound_stub));
bbaaef
+        ofpbuf_put(&compound, existing->ofpacts, existing->ofpacts_len);
bbaaef
+        ofpbuf_put(&compound, f->ofpacts, f->ofpacts_len);
bbaaef
+
bbaaef
+        free(existing->ofpacts);
bbaaef
+        existing->ofpacts = xmemdup(compound.data, compound.size);
bbaaef
+        existing->ofpacts_len = compound.size;
bbaaef
+
bbaaef
+        ofpbuf_uninit(&compound);
bbaaef
+        ovn_flow_destroy(f);
bbaaef
+    } else {
bbaaef
+        hmap_insert(&desired_flows->match_flow_table, &f->match_hmap_node,
bbaaef
+                    f->match_hmap_node.hash);
bbaaef
+        hindex_insert(&desired_flows->uuid_flow_table, &f->uuid_hindex_node,
bbaaef
+                      f->uuid_hindex_node.hash);
bbaaef
+    }
bbaaef
+}
bbaaef
 
bbaaef
 /* ovn_flow. */
bbaaef
 
bbaaef
+static struct ovn_flow *
bbaaef
+ovn_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie,
bbaaef
+               const struct match *match, const struct ofpbuf *actions,
bbaaef
+               const struct uuid *sb_uuid)
bbaaef
+{
bbaaef
+    struct ovn_flow *f = xmalloc(sizeof *f);
bbaaef
+    f->table_id = table_id;
bbaaef
+    f->priority = priority;
bbaaef
+    minimatch_init(&f->match, match);
bbaaef
+    f->ofpacts = xmemdup(actions->data, actions->size);
bbaaef
+    f->ofpacts_len = actions->size;
bbaaef
+    f->sb_uuid = *sb_uuid;
bbaaef
+    f->match_hmap_node.hash = ovn_flow_match_hash(f);
bbaaef
+    f->uuid_hindex_node.hash = uuid_hash(&f->sb_uuid);
bbaaef
+    f->cookie = cookie;
bbaaef
+
bbaaef
+    return f;
bbaaef
+}
bbaaef
+
bbaaef
 /* Returns a hash of the match key in 'f'. */
bbaaef
 static uint32_t
bbaaef
 ovn_flow_match_hash(const struct ovn_flow *f)
bbaaef
diff --git a/ovn/controller/ofctrl.h b/ovn/controller/ofctrl.h
bbaaef
index 1e9ac16b9..21d2ce648 100644
bbaaef
--- a/ovn/controller/ofctrl.h
bbaaef
+++ b/ovn/controller/ofctrl.h
bbaaef
@@ -70,6 +70,12 @@ void ofctrl_add_flow(struct ovn_desired_flow_table *, uint8_t table_id,
bbaaef
                      const struct match *, const struct ofpbuf *ofpacts,
bbaaef
                      const struct uuid *);
bbaaef
 
bbaaef
+void ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
bbaaef
+                               uint8_t table_id, uint16_t priority,
bbaaef
+                               uint64_t cookie, const struct match *match,
bbaaef
+                               const struct ofpbuf *actions,
bbaaef
+                               const struct uuid *sb_uuid);
bbaaef
+
bbaaef
 void ofctrl_remove_flows(struct ovn_desired_flow_table *, const struct uuid *);
bbaaef
 
bbaaef
 void ovn_desired_flow_table_init(struct ovn_desired_flow_table *);
bbaaef
diff --git a/tests/ovn.at b/tests/ovn.at
bbaaef
index 641a646fc..50d8efeec 100644
bbaaef
--- a/tests/ovn.at
bbaaef
+++ b/tests/ovn.at
bbaaef
@@ -12247,7 +12247,7 @@ ovn-nbctl create Address_Set name=set1 \
bbaaef
 addresses=\"10.0.0.4\",\"10.0.0.5\",\"10.0.0.6\"
bbaaef
 ovn-nbctl create Address_Set name=set2 \
bbaaef
 addresses=\"10.0.0.7\",\"10.0.0.8\",\"10.0.0.9\"
bbaaef
-ovn-nbctl acl-add ls1 to-lport 1002 \
bbaaef
+ovn-nbctl acl-add ls1 to-lport 1001 \
bbaaef
 'ip4 && ip4.src == $set1 && ip4.dst == $set1' allow
bbaaef
 ovn-nbctl acl-add ls1 to-lport 1001 \
bbaaef
 'ip4 && ip4.src == $set1 && ip4.dst == $set2' drop
bbaaef
@@ -12296,7 +12296,7 @@ cat 2.expected > expout
bbaaef
 $PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
bbaaef
 AT_CHECK([cat 2.packets], [0], [expout])
bbaaef
 
bbaaef
-# There should be total of 12 flows present with conjunction action and 2 flows
bbaaef
+# There should be total of 9 flows present with conjunction action and 2 flows
bbaaef
 # with conj match. Eg.
bbaaef
 # table=44, priority=2002,conj_id=2,metadata=0x1 actions=resubmit(,45)
bbaaef
 # table=44, priority=2001,conj_id=3,metadata=0x1 actions=drop
bbaaef
@@ -12306,14 +12306,11 @@ AT_CHECK([cat 2.packets], [0], [expout])
bbaaef
 # priority=2001,ip,metadata=0x1,nw_dst=10.0.0.7 actions=conjunction(3,2/2)
bbaaef
 # priority=2001,ip,metadata=0x1,nw_dst=10.0.0.9 actions=conjunction(3,2/2)
bbaaef
 # priority=2001,ip,metadata=0x1,nw_dst=10.0.0.8 actions=conjunction(3,2/2)
bbaaef
-# priority=2002,ip,metadata=0x1,nw_src=10.0.0.6 actions=conjunction(2,1/2)
bbaaef
-# priority=2002,ip,metadata=0x1,nw_src=10.0.0.4 actions=conjunction(2,1/2)
bbaaef
-# priority=2002,ip,metadata=0x1,nw_src=10.0.0.5 actions=conjunction(2,1/2)
bbaaef
-# priority=2001,ip,metadata=0x1,nw_src=10.0.0.6 actions=conjunction(3,1/2)
bbaaef
-# priority=2001,ip,metadata=0x1,nw_src=10.0.0.4 actions=conjunction(3,1/2)
bbaaef
-# priority=2001,ip,metadata=0x1,nw_src=10.0.0.5 actions=conjunction(3,1/2)
bbaaef
-
bbaaef
-OVS_WAIT_UNTIL([test 12 = `as hv1 ovs-ofctl dump-flows br-int | \
bbaaef
+# priority=2002,ip,metadata=0x1,nw_src=10.0.0.6 actions=conjunction(2,1/2),conjunction(3,1/2)
bbaaef
+# priority=2002,ip,metadata=0x1,nw_src=10.0.0.4 actions=conjunction(2,1/2),conjunction(3,1/2)
bbaaef
+# priority=2002,ip,metadata=0x1,nw_src=10.0.0.5 actions=conjunction(2,1/2),conjunction(3,1/2)
bbaaef
+
bbaaef
+OVS_WAIT_UNTIL([test 9 = `as hv1 ovs-ofctl dump-flows br-int | \
bbaaef
 grep conjunction | wc -l`])
bbaaef
 OVS_WAIT_UNTIL([test 2 = `as hv1 ovs-ofctl dump-flows br-int | \
bbaaef
 grep conj_id | wc -l`])
bbaaef
-- 
bbaaef
2.14.5
bbaaef