X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fflow.c;h=211203105218b279fb9e355e46203cdd05522414;hb=d4570fd8ba5f36f21b9b631628e812de0189fa20;hp=c6e5e070f28ae547c90cd43052c27989e2e914ad;hpb=b7807e4f64c8c64bb6000767de72368306a95c90;p=sliver-openvswitch.git diff --git a/lib/flow.c b/lib/flow.c index c6e5e070f..211203105 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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) @@ -823,65 +823,6 @@ flow_wildcards_or(struct flow_wildcards *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) @@ -943,23 +884,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 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; - return mhash_finish(hash, 13); + 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. */ + } + return hash; } /* Hashes 'flow' based on its L2 through L4 protocol information. */ @@ -1781,97 +1775,6 @@ miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct flow *b, 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); -} - /* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' * with minimask_destroy(). */ @@ -1956,26 +1859,17 @@ 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_', +/* Returns true if at least one bit matched by 'b' is wildcarded by 'a', * false otherwise. */ bool -minimask_has_extra(const struct minimask *a_, const struct minimask *b_) +minimask_has_extra(const struct minimask *a, const struct minimask *b) { - const struct miniflow *a = &a_->masks; - const struct miniflow *b = &b_->masks; + const uint32_t *p = b->masks.values; uint64_t map; - for (map = a->map | b->map; map; map = zero_rightmost_1bit(map)) { - int ofs = raw_ctz(map); - uint32_t a_u32 = miniflow_get(a, ofs); - uint32_t b_u32 = miniflow_get(b, ofs); + for (map = b->masks.map; map; map = zero_rightmost_1bit(map)) { + uint32_t a_u32 = minimask_get(a, raw_ctz(map)); + uint32_t b_u32 = *p++; if ((a_u32 & b_u32) != b_u32) { return true; @@ -1984,20 +1878,3 @@ minimask_has_extra(const struct minimask *a_, const struct minimask *b_) return false; } - -/* Returns true if 'mask' matches every packet, false if 'mask' fixes any bits - * or fields. */ -bool -minimask_is_catchall(const struct minimask *mask_) -{ - const struct miniflow *mask = &mask_->masks; - const uint32_t *p = mask->values; - uint64_t map; - - for (map = mask->map; map; map = zero_rightmost_1bit(map)) { - if (*p++) { - return false; - } - } - return true; -}