[ovs-dev] [mask array v3 1/2] Datapath: Simplify ovs_flow_tbl_lookup_stats()

Andy Zhou azhou at nicira.com
Wed Jun 4 20:53:04 UTC 2014


Signed-off-by: Andy Zhou <azhou at nicira.com>
---
 datapath/flow_table.c | 77 +++++++++++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 33 deletions(-)

diff --git a/datapath/flow_table.c b/datapath/flow_table.c
index 58a25c7..97b3283 100644
--- a/datapath/flow_table.c
+++ b/datapath/flow_table.c
@@ -554,8 +554,9 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
 {
 	struct mask_array *ma = rcu_dereference_ovsl(tbl->mask_array);
 	struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
-	struct mask_cache_entry  *entries, *ce, *del;
+	struct mask_cache_entry  *entries, *ce;
 	struct sw_flow *flow;
+	struct sw_flow_mask *cache;
 	u32 hash = skb_hash;
 	int seg;
 
@@ -566,42 +567,53 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
 		return flow_lookup(tbl, ti, ma, key, n_mask_hit, &mask_index);
 	}
 
-	del = NULL;
+	ce = NULL;
+	cache = NULL;
 	entries = this_cpu_ptr(tbl->mask_cache);
 
+	/* Find the cache entry 'ce' to operate on. */
 	for (seg = 0; seg < MC_HASH_SEGS; seg++) {
-		int index;
-
-		index = hash & (MC_HASH_ENTRIES - 1);
-		ce = &entries[index];
-
-		if (ce->skb_hash == skb_hash) {
-			struct sw_flow_mask *mask;
+		struct mask_cache_entry *e;
+		int index = hash & (MC_HASH_ENTRIES - 1);
+
+		e = &entries[index];
+		if (e->skb_hash == skb_hash) {
+			int i = e->mask_index;
+
+			if (i < ma->count)
+				cache = rcu_dereference_ovsl(ma->masks[i]);
+			else if (i < ma->max) {
+				cache = rcu_dereference_ovsl(ma->masks[i]);
+				i = tbl_mask_array_find_idx(ma, cache);
+				if (i < 0)
+					cache = NULL;
+			}
 
-			mask = rcu_dereference_ovsl(ma->masks[ce->mask_index]);
-			if (mask) {
-				flow = masked_flow_lookup(ti, key, mask,
-							  n_mask_hit);
-				if (flow)  /* Found */
-					return flow;
+			if (!cache)
+				e->skb_hash = 0; /* Not a valid cache entry. */
 
-			}
-			del = ce;
+			ce = e;  /* The best cache candidate. */
 			break;
 		}
 
-		if (!del || (del->skb_hash && !ce->skb_hash) ||
-		    (rcu_dereference_ovsl(ma->masks[del->mask_index]) &&
-		    !rcu_dereference_ovsl(ma->masks[ce->mask_index]))) {
-			del = ce;
-		}
+		if (!ce || e->skb_hash > ce->skb_hash)
+			ce = e;  /* A better replacement cache candidate. */
 
 		hash >>= MC_HASH_SHIFT;
 	}
 
-	flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &del->mask_index);
+	/* Try cached mask first if a cache entry is found.  */
+	if (cache) {
+		flow = masked_flow_lookup(ti, key, cache, n_mask_hit);
+		if (flow)
+			/* Cache hit. */
+			return flow;
+	}
+
+	/* Cache miss, do full lookup. */
+	flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &ce->mask_index);
 	if (flow)
-		del->skb_hash = skb_hash;
+		ce->skb_hash = skb_hash;
 
 	return flow;
 }
@@ -644,18 +656,17 @@ static void flow_mask_remove(struct flow_table *tbl, struct sw_flow_mask *mask)
 
 		if (!mask->ref_count) {
 			struct mask_array *ma;
-			int i;
 
 			ma = ovsl_dereference(tbl->mask_array);
-			for (i = 0; i < ma->max; i++) {
-				if (mask == ovsl_dereference(ma->masks[i])) {
-					RCU_INIT_POINTER(ma->masks[i], NULL);
-					ma->count--;
-					goto free;
-				}
+			/* Shrink the mask array if necessary. */
+			if (ma->max > MASK_ARRAY_SIZE_MIN * 2
+				&& ma->count <= ma->max / 4) {
+
+				tbl_mask_array_realloc(tbl, ma->max / 2);
+				ma = ovsl_dereference(tbl->mask_array);
 			}
-			BUG();
-free:
+
+			tbl_mask_array_delete_mask(ma, mask);
 			call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
 		}
 	}
-- 
1.9.1




More information about the dev mailing list