From 1c969ac38acc1fc2be1a7bbedcbe41f646c8559e Mon Sep 17 00:00:00 2001
From: Andy Zhou <azhou@nicira.com>
Date: Wed, 19 Jun 2013 13:25:35 -0700
Subject: [PATCH] datapath: Make mask list per table

---
 datapath/datapath.c |    4 ++--
 datapath/flow.c     |   53 ++++++++++++++++++++++++++++-----------------------
 datapath/flow.h     |    8 ++++++--
 3 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 0a0fe43..4849074 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -1319,7 +1319,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 		clear_stats(flow);
 
 		/* Make sure mask is unique in the system */
-		mask_p = ovs_sw_flow_mask_find(&mask);
+		mask_p = ovs_sw_flow_mask_find(table, &mask);
 		if (!mask_p) {
 			/* Allocate a new mask if none exsits. */
 			mask_p = ovs_sw_flow_mask_alloc();
@@ -1327,7 +1327,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 				goto err_flow_free;
 			mask_p->key = mask.key;
 			mask_p->range = mask.range;
-			ovs_sw_flow_mask_insert(mask_p);
+			ovs_sw_flow_mask_insert(table, mask_p);
 		}
 
 		ovs_sw_flow_mask_add_ref(mask_p);
diff --git a/datapath/flow.c b/datapath/flow.c
index d79190f..86f3896 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -46,7 +46,6 @@
 #include "vlan.h"
 
 static struct kmem_cache *flow_cache;
-static LIST_HEAD(mask_list);  /* List access is proteced by ovs_mutex. */
 
 static void ovs_sw_flow_mask_set(struct sw_flow_mask *mask,
 		struct sw_flow_key_range *range, u8 val);
@@ -120,7 +119,7 @@ void ovs_match_init(struct sw_flow_match *match,
 static bool ovs_match_validate(const struct sw_flow_match *match,
 		u64 key_attrs, u64 mask_attrs)
 {
-	u64 key_expected = OVS_KEY_ATTR_ETHERNET;
+	u64 key_expected = 1ULL << OVS_KEY_ATTR_ETHERNET;
 	u64 mask_allowed = key_attrs;  /* At most allow all key attributes */
 
 	/* The following mask attributes allowed only if they
@@ -462,6 +461,7 @@ struct flow_table *ovs_flow_tbl_alloc(int new_size)
 	table->node_ver = 0;
 	table->keep_flows = false;
 	get_random_bytes(&table->hash_seed, sizeof(u32));
+	INIT_LIST_HEAD(&table->mask_list);
 
 	return table;
 }
@@ -480,12 +480,22 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
 		struct sw_flow *flow;
 		struct hlist_head *head = flex_array_get(table->buckets, i);
 		struct hlist_node *n;
+		struct list_head *ml, *tmp;
 		int ver = table->node_ver;
 
 		hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
 			hlist_del_rcu(&flow->hash_node[ver]);
+			flow->mask = NULL;
 			ovs_flow_free(flow);
 		}
+
+		/* Delete the entire mask list, free all masks on the list. */
+		list_for_each_safe(ml, tmp, &table->mask_list) {
+			struct sw_flow_mask *mask;
+			mask = container_of(ml, struct sw_flow_mask, list);
+			list_del_rcu(&mask->list);
+			kfree(mask);
+		}
 	}
 
 skip_flows:
@@ -562,6 +572,8 @@ static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new
 		hlist_for_each_entry(flow, head, hash_node[old_ver])
 			__tbl_insert(new, flow);
 	}
+
+	new->mask_list = old->mask_list;
 	old->keep_flows = true;
 }
 
@@ -588,19 +600,14 @@ struct flow_table *ovs_flow_tbl_expand(struct flow_table *table)
 	return __flow_tbl_rehash(table, table->n_buckets * 2);
 }
 
-static void __flow_free(struct sw_flow *flow)
-{
-	kfree((struct sf_flow_acts __force *)flow->sf_acts);
-	kmem_cache_free(flow_cache, flow);
-}
-
 void ovs_flow_free(struct sw_flow *flow)
 {
 	if (unlikely(!flow))
 		return;
 
-	ovs_sw_flow_mask_del_ref(ovsl_dereference(flow->mask));
-	__flow_free(flow);
+	BUG_ON(flow->mask);
+	kfree((struct sf_flow_acts __force *)flow->sf_acts);
+	kmem_cache_free(flow_cache, flow);
 }
 
 /* RCU callback used by ovs_flow_deferred_free. */
@@ -608,7 +615,8 @@ static void rcu_free_flow_callback(struct rcu_head *rcu)
 {
 	struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);
 
-	__flow_free(flow);
+	flow->mask = NULL;
+	ovs_flow_free(flow);
 }
 
 /* Schedules 'flow' to be freed after the next RCU grace period.
@@ -1035,7 +1043,7 @@ struct sw_flow *ovs_flow_lookup(struct flow_table *tbl,
 	struct sw_flow *flow = NULL;
 	struct sw_flow_mask *mask;
 
-	list_for_each_entry_rcu(mask, &mask_list, list) {
+	list_for_each_entry_rcu(mask, &tbl->mask_list, list) {
 		flow = ovs_masked_flow_lookup(tbl, key, mask);
 		if (flow)  /* Found */
 			break;
@@ -1816,12 +1824,6 @@ static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu)
 	kfree(mask);
 }
 
-static void ovs_sw_flow_mask_deferred_destroy(struct sw_flow_mask *mask)
-{
-	list_del_rcu(&mask->list);
-	call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
-}
-
 void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *mask)
 {
 	if (!mask)
@@ -1830,8 +1832,10 @@ void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *mask)
 	BUG_ON(!mask->ref_count);
 	mask->ref_count--;
 
-	if (!mask->ref_count)
-		ovs_sw_flow_mask_deferred_destroy(mask);
+	if (!mask->ref_count) {
+		list_del_rcu(&mask->list);
+		call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
+	}
 }
 
 static bool ovs_sw_flow_mask_equal(const struct sw_flow_mask *a,
@@ -1845,11 +1849,12 @@ static bool ovs_sw_flow_mask_equal(const struct sw_flow_mask *a,
 		&& (memcmp(a_, b_, ovs_sw_flow_mask_actual_size(a)) == 0);
 }
 
-struct sw_flow_mask *ovs_sw_flow_mask_find(const struct sw_flow_mask *mask)
+struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *tbl,
+                                           const struct sw_flow_mask *mask)
 {
 	struct list_head *ml;
 
-	list_for_each(ml, &mask_list) {
+	list_for_each(ml, &tbl->mask_list) {
 		struct sw_flow_mask *m;
 		m = container_of(ml, struct sw_flow_mask, list);
 		if (ovs_sw_flow_mask_equal(mask, m))
@@ -1864,9 +1869,9 @@ struct sw_flow_mask *ovs_sw_flow_mask_find(const struct sw_flow_mask *mask)
  * The caller needs to make sure that 'mask' is not the same
  * as any masks that are already on the list.
  */
-void ovs_sw_flow_mask_insert(struct sw_flow_mask *mask)
+void ovs_sw_flow_mask_insert(struct flow_table *tbl, struct sw_flow_mask *mask)
 {
-	list_add_rcu(&mask->list, &mask_list);
+	list_add_rcu(&mask->list, &tbl->mask_list);
 }
 
 /**
diff --git a/datapath/flow.h b/datapath/flow.h
index be0bc2f..d29b621 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -194,6 +194,9 @@ struct flow_table {
 	struct flex_array *buckets;
 	unsigned int count, n_buckets;
 	struct rcu_head rcu;
+	struct list_head mask_list;  /* Mask list. Changes to the list
+					are protected ovs_mutex when flow
+					table is in use. */
 	int node_ver;
 	u32 hash_seed;
 	bool keep_flows;
@@ -258,6 +261,7 @@ ovs_sw_flow_mask_size_roundup(const struct sw_flow_mask *mask)
 struct sw_flow_mask *ovs_sw_flow_mask_alloc(void);
 void ovs_sw_flow_mask_add_ref(struct sw_flow_mask *);
 void ovs_sw_flow_mask_del_ref(struct sw_flow_mask *);
-void ovs_sw_flow_mask_insert(struct sw_flow_mask *);
-struct sw_flow_mask *ovs_sw_flow_mask_find(const struct sw_flow_mask *);
+void ovs_sw_flow_mask_insert(struct flow_table *, struct sw_flow_mask *);
+struct sw_flow_mask *ovs_sw_flow_mask_find(const struct flow_table *,
+		const struct sw_flow_mask *);
 #endif /* flow.h */
-- 
1.7.9.5

