}
/* 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)
}
}
-/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent
- * fields in 'dst', storing the result in 'dst'. */
-static void
-flow_union_with_miniflow(struct flow *dst, const struct miniflow *src)
-{
- uint32_t *dst_u32 = (uint32_t *) dst;
- const uint32_t *p = src->values;
- uint64_t map;
-
- for (map = src->map; map; map = zero_rightmost_1bit(map)) {
- dst_u32[raw_ctz(map)] |= *p++;
- }
-}
-
-/* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask. */
-void
-flow_wildcards_fold_minimask(struct flow_wildcards *wc,
- const struct minimask *mask)
-{
- flow_union_with_miniflow(&wc->masks, &mask->masks);
-}
-
-uint64_t
-miniflow_get_map_in_range(const struct miniflow *miniflow,
- uint8_t start, uint8_t end, unsigned int *offset)
-{
- uint64_t map = miniflow->map;
- *offset = 0;
-
- if (start > 0) {
- uint64_t msk = (UINT64_C(1) << start) - 1; /* 'start' LSBs set */
- *offset = count_1bits(map & msk);
- map &= ~msk;
- }
- if (end < FLOW_U32S) {
- uint64_t msk = (UINT64_C(1) << end) - 1; /* 'end' LSBs set */
- map &= msk;
- }
- return map;
-}
-
-/* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask
- * in range [start, end). */
-void
-flow_wildcards_fold_minimask_range(struct flow_wildcards *wc,
- const struct minimask *mask,
- uint8_t start, uint8_t end)
-{
- uint32_t *dst_u32 = (uint32_t *)&wc->masks;
- unsigned int offset;
- uint64_t map = miniflow_get_map_in_range(&mask->masks, start, end,
- &offset);
- const uint32_t *p = mask->masks.values + offset;
-
- for (; map; map = zero_rightmost_1bit(map)) {
- dst_u32[raw_ctz(map)] |= *p++;
- }
-}
-
/* Returns a hash of the wildcards in 'wc'. */
uint32_t
flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis)
wc->masks.regs[idx] = mask;
}
+/* 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 = basis;
+
+ 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. */
+ }
+ 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)
{
- 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(basis, (OVS_FORCE uint32_t) flow->nw_src);
- hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
- hash = mhash_add(hash, ((OVS_FORCE uint32_t) flow->tp_src << 16)
- | (OVS_FORCE uint32_t) flow->tp_dst);
- hash = mhash_add(hash, flow->nw_proto);
+ 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]);
- return mhash_finish(hash, 13);
+ hash = mhash_finish(hash, 42); /* Arbitrary number. */
+ }
+ return hash;
}
/* Hashes 'flow' based on its L2 through L4 protocol information. */
flow_union_with_miniflow(dst, src);
}
-static const uint32_t *
-miniflow_get__(const struct miniflow *flow, unsigned int u32_ofs)
-{
- if (!(flow->map & (UINT64_C(1) << u32_ofs))) {
- static const uint32_t zero = 0;
- return &zero;
- }
- return flow->values +
- count_1bits(flow->map & ((UINT64_C(1) << u32_ofs) - 1));
-}
-
/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'flow'
* were expanded into a "struct flow". */
-uint32_t
+static uint32_t
miniflow_get(const struct miniflow *flow, unsigned int u32_ofs)
{
- return *miniflow_get__(flow, u32_ofs);
-}
-
-/* Returns the ovs_be16 that would be at byte offset 'u8_ofs' if 'flow' were
- * expanded into a "struct flow". */
-static ovs_be16
-miniflow_get_be16(const struct miniflow *flow, unsigned int u8_ofs)
-{
- const uint32_t *u32p = miniflow_get__(flow, u8_ofs / 4);
- const ovs_be16 *be16p = (const ovs_be16 *) u32p;
- return be16p[u8_ofs % 4 != 0];
-}
-
-/* Returns the VID within the vlan_tci member of the "struct flow" represented
- * by 'flow'. */
-uint16_t
-miniflow_get_vid(const struct miniflow *flow)
-{
- ovs_be16 tci = miniflow_get_be16(flow, offsetof(struct flow, vlan_tci));
- return vlan_tci_to_vid(tci);
+ return (flow->map & UINT64_C(1) << u32_ofs)
+ ? *(flow->values +
+ count_1bits(flow->map & ((UINT64_C(1) << u32_ofs) - 1)))
+ : 0;
}
/* Returns true if 'a' and 'b' are the same flow, false otherwise. */
return true;
}
-/* Returns a hash value for 'flow', given 'basis'. */
-uint32_t
-miniflow_hash(const struct miniflow *flow, uint32_t basis)
-{
- const uint32_t *p = flow->values;
- uint32_t hash = basis;
- uint64_t hash_map = 0;
- uint64_t map;
-
- for (map = flow->map; map; map = zero_rightmost_1bit(map)) {
- if (*p) {
- hash = mhash_add(hash, *p);
- hash_map |= rightmost_1bit(map);
- }
- p++;
- }
- hash = mhash_add(hash, hash_map);
- hash = mhash_add(hash, hash_map >> 32);
-
- return mhash_finish(hash, p - flow->values);
-}
-
-/* Returns a hash value for the bits of 'flow' where there are 1-bits in
- * 'mask', given 'basis'.
- *
- * The hash values returned by this function are the same as those returned by
- * flow_hash_in_minimask(), only the form of the arguments differ. */
-uint32_t
-miniflow_hash_in_minimask(const struct miniflow *flow,
- const struct minimask *mask, uint32_t basis)
-{
- const uint32_t *p = mask->masks.values;
- uint32_t hash;
- uint64_t map;
-
- hash = basis;
-
- for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
- hash = mhash_add(hash, miniflow_get(flow, raw_ctz(map)) & *p++);
- }
-
- return mhash_finish(hash, (p - mask->masks.values) * 4);
-}
-
-/* Returns a hash value for the bits of 'flow' where there are 1-bits in
- * 'mask', given 'basis'.
- *
- * The hash values returned by this function are the same as those returned by
- * miniflow_hash_in_minimask(), only the form of the arguments differ. */
-uint32_t
-flow_hash_in_minimask(const struct flow *flow, const struct minimask *mask,
- uint32_t basis)
-{
- const uint32_t *flow_u32 = (const uint32_t *)flow;
- const uint32_t *p = mask->masks.values;
- uint32_t hash;
- uint64_t map;
-
- hash = basis;
- for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
- hash = mhash_add(hash, flow_u32[raw_ctz(map)] & *p++);
- }
-
- return mhash_finish(hash, (p - mask->masks.values) * 4);
-}
-
-/* Returns a hash value for the bits of range [start, end) in 'flow',
- * where there are 1-bits in 'mask', given 'hash'.
- *
- * The hash values returned by this function are the same as those returned by
- * minimatch_hash_range(), only the form of the arguments differ. */
-uint32_t
-flow_hash_in_minimask_range(const struct flow *flow,
- const struct minimask *mask,
- uint8_t start, uint8_t end, uint32_t *basis)
-{
- const uint32_t *flow_u32 = (const uint32_t *)flow;
- unsigned int offset;
- uint64_t map = miniflow_get_map_in_range(&mask->masks, start, end,
- &offset);
- const uint32_t *p = mask->masks.values + offset;
- uint32_t hash = *basis;
-
- for (; map; map = zero_rightmost_1bit(map)) {
- hash = mhash_add(hash, flow_u32[raw_ctz(map)] & *p++);
- }
-
- *basis = hash; /* Allow continuation from the unfinished value. */
- return mhash_finish(hash, (p - mask->masks.values) * 4);
-}
-
\f
/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
* with minimask_destroy(). */
return miniflow_get(&mask->masks, u32_ofs);
}
-/* Returns the VID mask within the vlan_tci member of the "struct
- * flow_wildcards" represented by 'mask'. */
-uint16_t
-minimask_get_vid_mask(const struct minimask *mask)
-{
- return miniflow_get_vid(&mask->masks);
-}
-
/* Returns true if 'a' and 'b' are the same flow mask, false otherwise. */
bool
minimask_equal(const struct minimask *a, const struct minimask *b)
return miniflow_equal(&a->masks, &b->masks);
}
-/* Returns a hash value for 'mask', given 'basis'. */
-uint32_t
-minimask_hash(const struct minimask *mask, uint32_t basis)
-{
- return miniflow_hash(&mask->masks, basis);
-}
-
/* Returns true if at least one bit is wildcarded in 'a_' but not in 'b_',
* false otherwise. */
bool