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

lib/flow: Simplify miniflow accessors, add ipv6 support.

Add new macro MINIFLOW_MAP(FIELD) that returns the map covering the
given struct flow field.

Change the miniflow accessors to macros so that they can take the
field name directly.

Use these to add ipv6 support to miniflow_hash_5tuple().

Add ipv6 support to flow_hash_5tuple() as well so that these two
functions continue to return the same hash value for the corresponding
flows.

Also, simplify miniflow_get_metadata().

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ethan Jackson <ethan@nicira.com>
This commit is contained in:
Jarno Rajahalme
2014-04-29 15:50:38 -07:00
parent 003ce655b7
commit 28a560d97a
3 changed files with 95 additions and 88 deletions

View File

@@ -355,7 +355,7 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
}
/* Caller is responsible for initializing 'dst->values' with enough storage
* (FLOW_U64S * 8 bytes is enough). */
* for FLOW_U32S * 4 bytes. */
void
miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
struct miniflow *dst)
@@ -943,50 +943,76 @@ flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
wc->masks.regs[idx] = mask;
}
/* Calculates the 5-tuple hash from the given flow. */
/* Calculates the 5-tuple hash from the given miniflow.
* This returns the same value as flow_hash_5tuple for the corresponding
* flow. */
uint32_t
miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
{
uint32_t hash = 0;
uint32_t hash = basis;
if (!flow) {
return 0;
if (flow) {
ovs_be16 dl_type = MINIFLOW_GET_BE16(flow, dl_type);
hash = mhash_add(hash, MINIFLOW_GET_U8(flow, nw_proto));
/* Separate loops for better optimization. */
if (dl_type == htons(ETH_TYPE_IPV6)) {
uint64_t map = MINIFLOW_MAP(ipv6_src) | MINIFLOW_MAP(ipv6_dst)
| MINIFLOW_MAP(tp_src); /* Covers both ports */
uint32_t value;
MINIFLOW_FOR_EACH_IN_MAP(value, flow, map) {
hash = mhash_add(hash, value);
}
} else {
uint64_t map = MINIFLOW_MAP(nw_src) | MINIFLOW_MAP(nw_dst)
| MINIFLOW_MAP(tp_src); /* Covers both ports */
uint32_t value;
MINIFLOW_FOR_EACH_IN_MAP(value, flow, map) {
hash = mhash_add(hash, value);
}
}
hash = mhash_finish(hash, 42); /* Arbitrary number. */
}
hash = mhash_add(basis,
miniflow_get_u32(flow, offsetof(struct flow, nw_src)));
hash = mhash_add(hash,
miniflow_get_u32(flow, offsetof(struct flow, nw_dst)));
hash = mhash_add(hash,
miniflow_get_u32(flow, offsetof(struct flow, tp_src)));
hash = mhash_add(hash,
miniflow_get_u8(flow, offsetof(struct flow, nw_proto)));
return mhash_finish(hash, 13);
return hash;
}
BUILD_ASSERT_DECL(offsetof(struct flow, tp_src) + 2
== offsetof(struct flow, tp_dst) &&
offsetof(struct flow, tp_src) / 4
== offsetof(struct flow, tp_dst) / 4);
BUILD_ASSERT_DECL(offsetof(struct flow, ipv6_src) + 16
== offsetof(struct flow, ipv6_dst));
/* Calculates the 5-tuple hash from the given flow. */
uint32_t
flow_hash_5tuple(const struct flow *flow, uint32_t basis)
{
const uint32_t *flow_u32 = (const uint32_t *)flow;
uint32_t hash = 0;
uint32_t hash = basis;
if (!flow) {
return 0;
if (flow) {
const uint32_t *flow_u32 = (const uint32_t *)flow;
hash = mhash_add(hash, flow->nw_proto);
if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
int ofs = offsetof(struct flow, ipv6_src) / 4;
int end = ofs + 2 * sizeof flow->ipv6_src / 4;
while (ofs < end) {
hash = mhash_add(hash, flow_u32[ofs++]);
}
} else {
hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_src);
hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
}
hash = mhash_add(hash, flow_u32[offsetof(struct flow, tp_src) / 4]);
hash = mhash_finish(hash, 42); /* Arbitrary number. */
}
hash = mhash_add(basis, (OVS_FORCE uint32_t) flow->nw_src);
hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
hash = mhash_add(hash, flow_u32[offsetof(struct flow, tp_src) / 4]);
hash = mhash_add(hash, flow->nw_proto);
return mhash_finish(hash, 13);
return hash;
}
/* Hashes 'flow' based on its L2 through L4 protocol information. */