Due to the race condition in userspace, there is chance that two
overlapping megaflows could be installed in datapath.  And this
causes userspace unable to delete the less inclusive megaflow flow
even after it timeout, since the flow_del logic will stop at the
first match of masked flow.

This commit fixes the bug by making the kernel flow_del and flow_get
logic check all masks in that case.

Signed-off-by: Alex Wang <al...@nicira.com>
Acked-by: Andy Zhou <az...@nicira.com>
---
 datapath/datapath.c |    4 ++--
 datapath/flow.c     |   33 +++++++++++++++++++--------------
 datapath/flow.h     |    4 ++--
 3 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 6d523d6..90186a4 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -1426,7 +1426,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct 
genl_info *info)
        }
 
        table = ovsl_dereference(dp->table);
-       flow = ovs_flow_lookup_unmasked_key(table, &match);
+       flow = ovs_flow_lookup_exact(table, &match);
        if (!flow) {
                err = -ENOENT;
                goto unlock;
@@ -1476,7 +1476,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct 
genl_info *info)
                goto unlock;
 
        table = ovsl_dereference(dp->table);
-       flow = ovs_flow_lookup_unmasked_key(table, &match);
+       flow = ovs_flow_lookup_exact(table, &match);
        if (!flow) {
                err = -ENOENT;
                goto unlock;
diff --git a/datapath/flow.c b/datapath/flow.c
index 2e46866..b3bc683 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -28,6 +28,7 @@
 #include <linux/jhash.h>
 #include <linux/jiffies.h>
 #include <linux/llc.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include <linux/in.h>
 #include <linux/rcupdate.h>
@@ -1070,20 +1071,6 @@ bool ovs_flow_cmp_unmasked_key(const struct sw_flow 
*flow,
 
 }
 
-struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
-                                      struct sw_flow_match *match)
-{
-       struct sw_flow_key *unmasked = match->key;
-       int key_end = match->range.end;
-       struct sw_flow *flow;
-
-       flow = ovs_flow_lookup(table, unmasked);
-       if (flow && (!ovs_flow_cmp_unmasked_key(flow, unmasked, key_end)))
-               flow = NULL;
-
-       return flow;
-}
-
 static struct sw_flow *ovs_masked_flow_lookup(struct flow_table *table,
                                    const struct sw_flow_key *unmasked,
                                    struct sw_flow_mask *mask)
@@ -1107,6 +1094,24 @@ static struct sw_flow *ovs_masked_flow_lookup(struct 
flow_table *table,
        return NULL;
 }
 
+struct sw_flow *ovs_flow_lookup_exact(struct flow_table *tbl,
+                                     struct sw_flow_match *match)
+{
+       struct sw_flow_key *unmasked = match->key;
+       struct sw_flow *flow;
+       struct sw_flow_mask *mask;
+       int key_end = match->range.end;
+
+       /* Always called under ovs-mutex. */
+       list_for_each_entry(mask, tbl->mask_list, list) {
+               flow = ovs_masked_flow_lookup(tbl, unmasked, mask);
+               if (flow && ovs_flow_cmp_unmasked_key(flow, unmasked, key_end)) 
 /* Found */
+                       return flow;
+       }
+
+       return NULL;
+}
+
 struct sw_flow *ovs_flow_lookup(struct flow_table *tbl,
                                const struct sw_flow_key *key)
 {
diff --git a/datapath/flow.h b/datapath/flow.h
index 03eae03..cf7e2e2 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -220,8 +220,8 @@ static inline int ovs_flow_tbl_need_to_expand(struct 
flow_table *table)
 
 struct sw_flow *ovs_flow_lookup(struct flow_table *,
                                const struct sw_flow_key *);
-struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
-                                   struct sw_flow_match *match);
+struct sw_flow *ovs_flow_lookup_exact(struct flow_table *tbl,
+                                     struct sw_flow_match *match);
 
 void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
 struct flow_table *ovs_flow_tbl_alloc(int new_size);
-- 
1.7.9.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to