2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

flow: Split miniflow's map.

Use two maps in miniflow to allow for expansion of struct flow past
512 bytes.  We now have one map for tunnel related fields, and another
for the rest of the packet metadata and actual packet header fields.
This split has the benefit that for non-tunneled packets the overhead
should be minimal.

Some miniflow utilities now exist in two variants, new ones operating
over all the data, and the old ones operating only on a single 64-bit
map at a time.  The old ones require doubling of code but should
execute faster, so those are used in the datapath and classifier's
lookup path.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2015-07-17 15:18:43 -07:00
parent 8cd27cfd1e
commit 361d808dd9
6 changed files with 504 additions and 268 deletions

View File

@@ -488,14 +488,15 @@ emc_cache_init(struct emc_cache *flow_cache)
{
int i;
BUILD_ASSERT(sizeof(struct miniflow) == sizeof(uint64_t));
BUILD_ASSERT(sizeof(struct miniflow) == 2 * sizeof(uint64_t));
flow_cache->sweep_idx = 0;
for (i = 0; i < ARRAY_SIZE(flow_cache->entries); i++) {
flow_cache->entries[i].flow = NULL;
flow_cache->entries[i].key.hash = 0;
flow_cache->entries[i].key.len = sizeof(struct miniflow);
flow_cache->entries[i].key.mf.map = 0;
flow_cache->entries[i].key.mf.tnl_map = 0;
flow_cache->entries[i].key.mf.pkt_map = 0;
}
}
@@ -1390,6 +1391,8 @@ dp_netdev_pmd_remove_flow(struct dp_netdev_pmd_thread *pmd,
struct cmap_node *node = CONST_CAST(struct cmap_node *, &flow->node);
dpcls_remove(&pmd->cls, &flow->cr);
flow->cr.mask = NULL; /* Accessing rule's mask after this is not safe. */
cmap_remove(&pmd->flow_table, node, dp_netdev_flow_hash(&flow->ufid));
flow->dead = true;
@@ -1518,20 +1521,19 @@ static bool dp_netdev_flow_ref(struct dp_netdev_flow *flow)
* miniflow_extract(), if the map is different the miniflow is different.
* Therefore we can be faster by comparing the map and the miniflow in a
* single memcmp().
* _ netdev_flow_key's miniflow has always inline values.
* - These functions can be inlined by the compiler.
*
* The following assertions make sure that what we're doing with miniflow is
* safe
* safe.
*/
BUILD_ASSERT_DECL(sizeof(struct miniflow) == sizeof(uint64_t));
BUILD_ASSERT_DECL(sizeof(struct miniflow) == 2 * sizeof(uint64_t));
/* Given the number of bits set in the miniflow map, returns the size of the
/* Given the number of bits set in miniflow's maps, returns the size of the
* 'netdev_flow_key.mf' */
static inline uint32_t
netdev_flow_key_size(uint32_t flow_u32s)
static inline size_t
netdev_flow_key_size(size_t flow_u64s)
{
return sizeof(struct miniflow) + MINIFLOW_VALUES_SIZE(flow_u32s);
return sizeof(struct miniflow) + MINIFLOW_VALUES_SIZE(flow_u64s);
}
static inline bool
@@ -1574,7 +1576,7 @@ netdev_flow_key_from_flow(struct netdev_flow_key *dst,
miniflow_extract(&packet, &dst->mf);
dp_packet_uninit(&packet);
dst->len = netdev_flow_key_size(count_1bits(dst->mf.map));
dst->len = netdev_flow_key_size(miniflow_n_values(&dst->mf));
dst->hash = 0; /* Not computed yet. */
}
@@ -1585,28 +1587,43 @@ netdev_flow_mask_init(struct netdev_flow_key *mask,
{
const uint64_t *mask_u64 = (const uint64_t *) &match->wc.masks;
uint64_t *dst = miniflow_values(&mask->mf);
uint64_t map, mask_map = 0;
struct miniflow maps;
uint64_t map;
uint32_t hash = 0;
int n;
/* Only check masks that make sense for the flow. */
map = flow_wc_map(&match->flow);
flow_wc_map(&match->flow, &maps);
memset(&mask->mf, 0, sizeof mask->mf); /* Clear maps. */
map = maps.tnl_map;
while (map) {
uint64_t rm1bit = rightmost_1bit(map);
int i = raw_ctz(map);
if (mask_u64[i]) {
mask_map |= rm1bit;
mask->mf.tnl_map |= rm1bit;
*dst++ = mask_u64[i];
hash = hash_add64(hash, mask_u64[i]);
}
map -= rm1bit;
}
mask_u64 += FLOW_TNL_U64S;
map = maps.pkt_map;
while (map) {
uint64_t rm1bit = rightmost_1bit(map);
int i = raw_ctz(map);
if (mask_u64[i]) {
mask->mf.pkt_map |= rm1bit;
*dst++ = mask_u64[i];
hash = hash_add64(hash, mask_u64[i]);
}
map -= rm1bit;
}
mask->mf.map = mask_map;
hash = hash_add64(hash, mask_map);
hash = hash_add64(hash, mask->mf.tnl_map);
hash = hash_add64(hash, mask->mf.pkt_map);
n = dst - miniflow_get_values(&mask->mf);
@@ -1614,7 +1631,7 @@ netdev_flow_mask_init(struct netdev_flow_key *mask,
mask->len = netdev_flow_key_size(n);
}
/* Initializes 'dst' as a copy of 'src' masked with 'mask'. */
/* Initializes 'dst' as a copy of 'flow' masked with 'mask'. */
static inline void
netdev_flow_key_init_masked(struct netdev_flow_key *dst,
const struct flow *flow,
@@ -1626,9 +1643,9 @@ netdev_flow_key_init_masked(struct netdev_flow_key *dst,
uint64_t value;
dst->len = mask->len;
dst->mf.map = mask->mf.map;
dst->mf = mask->mf; /* Copy maps. */
FLOW_FOR_EACH_IN_MAP(value, flow, mask->mf.map) {
FLOW_FOR_EACH_IN_MAPS(value, flow, mask->mf) {
*dst_u64 = value & *mask_u64++;
hash = hash_add64(hash, *dst_u64++);
}
@@ -1636,12 +1653,13 @@ netdev_flow_key_init_masked(struct netdev_flow_key *dst,
(dst_u64 - miniflow_get_values(&dst->mf)) * 8);
}
/* Iterate through all netdev_flow_key u64 values specified by 'MAP' */
#define NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(VALUE, KEY, MAP) \
for (struct mf_for_each_in_map_aux aux__ \
= { miniflow_get_values(&(KEY)->mf), (KEY)->mf.map, MAP }; \
mf_get_next_in_map(&aux__, &(VALUE)); \
)
/* Iterate through netdev_flow_key TNL u64 values specified by 'MAPS'. */
#define NETDEV_FLOW_KEY_FOR_EACH_IN_TNL_MAP(VALUE, KEY, MAPS) \
MINIFLOW_FOR_EACH_IN_TNL_MAP(VALUE, &(KEY)->mf, MAPS)
/* Iterate through netdev_flow_key PKT u64 values specified by 'MAPS'. */
#define NETDEV_FLOW_KEY_FOR_EACH_IN_PKT_MAP(VALUE, KEY, MAPS) \
MINIFLOW_FOR_EACH_IN_PKT_MAP(VALUE, &(KEY)->mf, MAPS)
/* Returns a hash value for the bits of 'key' where there are 1-bits in
* 'mask'. */
@@ -1653,7 +1671,10 @@ netdev_flow_key_hash_in_mask(const struct netdev_flow_key *key,
uint32_t hash = 0;
uint64_t key_u64;
NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(key_u64, key, mask->mf.map) {
NETDEV_FLOW_KEY_FOR_EACH_IN_TNL_MAP(key_u64, key, mask->mf) {
hash = hash_add64(hash, key_u64 & *p++);
}
NETDEV_FLOW_KEY_FOR_EACH_IN_PKT_MAP(key_u64, key, mask->mf) {
hash = hash_add64(hash, key_u64 & *p++);
}
@@ -1911,7 +1932,6 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
* mask->in_port.ofp_port, which only covers half of the 32-bit datapath
* port number mask->in_port.odp_port. */
mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
return 0;
}
@@ -1988,7 +2008,8 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
netdev_flow_mask_init(&mask, match);
/* Make sure wc does not have metadata. */
ovs_assert(!(mask.mf.map & (MINIFLOW_MAP(metadata) | MINIFLOW_MAP(regs))));
ovs_assert(!(mask.mf.pkt_map
& (MINIFLOW_PKT_MAP(metadata) | MINIFLOW_PKT_MAP(regs))));
/* Do not allocate extra space. */
flow = xmalloc(sizeof *flow - sizeof flow->cr.flow.mf + mask.len);
@@ -3218,7 +3239,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
for (i = 0; i < cnt; i++) {
/* Key length is needed in all the cases, hash computed on demand. */
keys[i].len = netdev_flow_key_size(count_1bits(keys[i].mf.map));
keys[i].len = netdev_flow_key_size(miniflow_n_values(&keys[i].mf));
}
any_miss = !dpcls_lookup(&pmd->cls, keys, rules, cnt);
if (OVS_UNLIKELY(any_miss) && !fat_rwlock_tryrdlock(&dp->upcall_rwlock)) {
@@ -3782,6 +3803,7 @@ dpcls_destroy(struct dpcls *cls)
struct dpcls_subtable *subtable;
CMAP_FOR_EACH (subtable, cmap_node, &cls->subtables_map) {
ovs_assert(cmap_count(&subtable->rules) == 0);
dpcls_destroy_subtable(cls, subtable);
}
cmap_destroy(&cls->subtables_map);
@@ -3848,10 +3870,8 @@ dpcls_remove(struct dpcls *cls, struct dpcls_rule *rule)
}
}
/* Returns true if 'target' satisifies 'key' in 'mask', that is, if each 1-bit
* in 'mask' the values in 'key' and 'target' are the same.
*
* Note: 'key' and 'mask' have the same mask, and 'key' is already masked. */
/* Returns true if 'target' satisfies 'key' in 'mask', that is, if each 1-bit
* in 'mask' the values in 'key' and 'target' are the same. */
static inline bool
dpcls_rule_matches_key(const struct dpcls_rule *rule,
const struct netdev_flow_key *target)
@@ -3860,7 +3880,12 @@ dpcls_rule_matches_key(const struct dpcls_rule *rule,
const uint64_t *maskp = miniflow_get_values(&rule->mask->mf);
uint64_t target_u64;
NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(target_u64, target, rule->flow.mf.map) {
NETDEV_FLOW_KEY_FOR_EACH_IN_TNL_MAP(target_u64, target, rule->flow.mf) {
if (OVS_UNLIKELY((target_u64 & *maskp++) != *keyp++)) {
return false;
}
}
NETDEV_FLOW_KEY_FOR_EACH_IN_PKT_MAP(target_u64, target, rule->flow.mf) {
if (OVS_UNLIKELY((target_u64 & *maskp++) != *keyp++)) {
return false;
}