Skip to content

Commit

Permalink
dpif-netdev: Add SMC cache after EMC cache
Browse files Browse the repository at this point in the history
This patch adds a signature match cache (SMC) after exact match
cache (EMC). The difference between SMC and EMC is SMC only stores
a signature of a flow thus it is much more memory efficient. With
same memory space, EMC can store 8k flows while SMC can store 1M
flows. It is generally beneficial to turn on SMC but turn off EMC
when traffic flow count is much larger than EMC size.

SMC cache will map a signature to an dp_netdev_flow index in
flow_table. Thus, we add two new APIs in cmap for lookup key by
index and lookup index by key.

For now, SMC is an experimental feature that it is turned off by
default. One can turn it on using ovsdb options.

Signed-off-by: Yipeng Wang <[email protected]>
Co-authored-by: Jan Scheurich <[email protected]>
Signed-off-by: Jan Scheurich <[email protected]>
Acked-by: Billy O'Mahony <[email protected]>
Signed-off-by: Ian Stokes <[email protected]>
  • Loading branch information
2 people authored and istokes committed Jul 24, 2018
1 parent 1ac6908 commit 60d8cca
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 39 deletions.
15 changes: 15 additions & 0 deletions Documentation/topics/dpdk/bridge.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,18 @@ For certain traffic profiles with many parallel flows, it's recommended to set
``N`` to '0' to achieve higher forwarding performance.

For more information on the EMC refer to :doc:`/intro/install/dpdk` .


SMC cache (experimental)
-------------------------

SMC cache or signature match cache is a new cache level after EMC cache.
The difference between SMC and EMC is SMC only stores a signature of a flow
thus it is much more memory efficient. With same memory space, EMC can store 8k
flows while SMC can store 1M flows. When traffic flow count is much larger than
EMC size, it is generally beneficial to turn off EMC and turn on SMC. It is
currently turned off by default and an experimental feature.

To turn on SMC::

$ ovs-vsctl --no-wait set Open_vSwitch . other_config:smc-enable=true
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Post-v2.9.0
ovs-appctl dpif-netdev/pmd-perf-show
* Supervision of PMD performance metrics and logging of suspicious
iterations
* Add signature match cache (SMC) as experimental feature. When turned on,
it improves throughput when traffic has many more flows than EMC size.
- ERSPAN:
* Implemented ERSPAN protocol (draft-foschiano-erspan-00.txt) for
both kernel datapath and userspace datapath.
Expand Down
74 changes: 74 additions & 0 deletions lib/cmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,80 @@ cmap_find(const struct cmap *cmap, uint32_t hash)
hash);
}

/* Find a node by the index of the entry of cmap. Index N means the N/CMAP_K
* bucket and N%CMAP_K entry in that bucket.
* Notice that it is not protected by the optimistic lock (versioning) because
* it does not compare the hashes. Currently it is only used by the datapath
* SMC cache.
*
* Return node for the entry of index or NULL if the index beyond boundary */
const struct cmap_node *
cmap_find_by_index(const struct cmap *cmap, uint32_t index)
{
const struct cmap_impl *impl = cmap_get_impl(cmap);

uint32_t b = index / CMAP_K;
uint32_t e = index % CMAP_K;

if (b > impl->mask) {
return NULL;
}

const struct cmap_bucket *bucket = &impl->buckets[b];

return cmap_node_next(&bucket->nodes[e]);
}

/* Find the index of certain hash value. Currently only used by the datapath
* SMC cache.
*
* Return the index of the entry if found, or UINT32_MAX if not found. The
* function assumes entry index cannot be larger than UINT32_MAX. */
uint32_t
cmap_find_index(const struct cmap *cmap, uint32_t hash)
{
const struct cmap_impl *impl = cmap_get_impl(cmap);
uint32_t h1 = rehash(impl, hash);
uint32_t h2 = other_hash(h1);

uint32_t b_index1 = h1 & impl->mask;
uint32_t b_index2 = h2 & impl->mask;

uint32_t c1, c2;
uint32_t index = UINT32_MAX;

const struct cmap_bucket *b1 = &impl->buckets[b_index1];
const struct cmap_bucket *b2 = &impl->buckets[b_index2];

do {
do {
c1 = read_even_counter(b1);
for (int i = 0; i < CMAP_K; i++) {
if (b1->hashes[i] == hash) {
index = b_index1 * CMAP_K + i;
}
}
} while (OVS_UNLIKELY(counter_changed(b1, c1)));
if (index != UINT32_MAX) {
break;
}
do {
c2 = read_even_counter(b2);
for (int i = 0; i < CMAP_K; i++) {
if (b2->hashes[i] == hash) {
index = b_index2 * CMAP_K + i;
}
}
} while (OVS_UNLIKELY(counter_changed(b2, c2)));

if (index != UINT32_MAX) {
break;
}
} while (OVS_UNLIKELY(counter_changed(b1, c1)));

return index;
}

/* Looks up multiple 'hashes', when the corresponding bit in 'map' is 1,
* and sets the corresponding pointer in 'nodes', if the hash value was
* found from the 'cmap'. In other cases the 'nodes' values are not changed,
Expand Down
11 changes: 11 additions & 0 deletions lib/cmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ size_t cmap_replace(struct cmap *, struct cmap_node *old_node,
const struct cmap_node *cmap_find(const struct cmap *, uint32_t hash);
struct cmap_node *cmap_find_protected(const struct cmap *, uint32_t hash);

/* Find node by index or find index by hash. The 'index' of a cmap entry is a
* way to combine the specific bucket and the entry of the bucket into a
* convenient single integer value. In other words, it is the index of the
* entry and each entry has an unique index. It is not used internally by
* cmap.
* Currently the functions assume index will not be larger than uint32_t. In
* OvS table size is usually much smaller than this size.*/
const struct cmap_node * cmap_find_by_index(const struct cmap *,
uint32_t index);
uint32_t cmap_find_index(const struct cmap *, uint32_t hash);

/* Looks up multiple 'hashes', when the corresponding bit in 'map' is 1,
* and sets the corresponding pointer in 'nodes', if the hash value was
* found from the 'cmap'. In other cases the 'nodes' values are not changed,
Expand Down
1 change: 1 addition & 0 deletions lib/dpif-netdev-perf.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ extern "C" {

enum pmd_stat_type {
PMD_STAT_EXACT_HIT, /* Packets that had an exact match (emc). */
PMD_STAT_SMC_HIT, /* Packets that had a sig match hit (SMC). */
PMD_STAT_MASKED_HIT, /* Packets that matched in the flow table. */
PMD_STAT_MISS, /* Packets that did not match and upcall was ok. */
PMD_STAT_LOST, /* Packets that did not match and upcall failed. */
Expand Down
Loading

0 comments on commit 60d8cca

Please sign in to comment.