Jarno, I did some simple tests increasing flow_tnl size and trying to match on it looks good. Thanks for solving this. I have a question inline around miniflow_extract. Other than that the diff looks good to me.
Thanks. On Wed, Dec 17, 2014 at 10:30 AM, Jarno Rajahalme <jrajaha...@nicira.com> wrote: > > So far the compressed flow data in struct miniflow has been in 32-bit > words with a 63-bit map, allowing for a maximum size of struct flow of > 252 bytes. With the forthcoming Geneve options this is not sufficient > any more. > > This patch solves the problem by changing the miniflow data to 64-bit > words, doubling the flow max size to 504 bytes. Since the word size > is doubled, there is some loss in compression efficiency. To counter > this some of the flow fields have been reordered to keep related > fields together (e.g., the source and destination IP addresses share > the same 64-bit word). > > This change should speed up flow data processing on 64-bit CPUs, which > may help counterbalance the impact of making the struct flow bigger in > the future. > > Classifier lookup stage boundaries are also changed to 64-bit > alignment, as the current algorithm depends on each miniflow word to > not be split between ranges. This has resulted in new padding (part > of the 'mpls_lse' field). > > The 'dp_hash' field is also moved to packet metadata to eliminate > otherwise needed padding there. This allows the L4 to fit into one > 64-bit word, and also makes matches on 'dp_hash' more efficient as > misses can be found already on stage 1. > > Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> > Summary: > --- > lib/classifier-private.h | 60 +++--- > lib/classifier.c | 72 ++++---- > lib/dpif-netdev.c | 48 ++--- > lib/flow.c | 402 > +++++++++++++++++++++++------------------ > lib/flow.h | 270 +++++++++++++++------------ > lib/match.c | 10 +- > lib/nx-match.c | 2 +- > lib/odp-util.h | 2 +- > lib/ofp-util.c | 2 +- > lib/tnl-ports.c | 2 +- > ofproto/ofproto-dpif-upcall.c | 10 +- > ofproto/ofproto-dpif-xlate.c | 2 +- > ofproto/ofproto.c | 2 +- > tests/ofproto-dpif.at | 2 +- > tests/test-classifier.c | 23 +-- > 15 files changed, 499 insertions(+), 410 deletions(-) > > diff --git a/lib/classifier-private.h b/lib/classifier-private.h > index 17eed2c..cd64fed 100644 > --- a/lib/classifier-private.h > +++ b/lib/classifier-private.h > @@ -42,7 +42,7 @@ struct cls_subtable { > /* These fields are accessed by readers who care about wildcarding. */ > const tag_type tag; /* Tag generated from mask for > partitioning. */ > const uint8_t n_indices; /* How many indices to > use. */ > - const uint8_t index_ofs[CLS_MAX_INDICES]; /* u32 segment boundaries. > */ > + const uint8_t index_ofs[CLS_MAX_INDICES]; /* u64 segment boundaries. > */ > unsigned int trie_plen[CLS_MAX_TRIES]; /* Trie prefix length in > 'mask' > * (runtime configurable). */ > const int ports_mask_len; > @@ -112,7 +112,7 @@ miniflow_get_map_in_range(const struct miniflow > *miniflow, > *offset = count_1bits(map & msk); > map &= ~msk; > } > - if (end < FLOW_U32S) { > + if (end < FLOW_U64S) { > uint64_t msk = (UINT64_C(1) << end) - 1; /* 'end' LSBs set */ > map &= msk; > } > @@ -128,18 +128,18 @@ static inline uint32_t > flow_hash_in_minimask(const struct flow *flow, const struct minimask > *mask, > uint32_t basis) > { > - const uint32_t *mask_values = miniflow_get_u32_values(&mask->masks); > - const uint32_t *flow_u32 = (const uint32_t *)flow; > - const uint32_t *p = mask_values; > + const uint64_t *mask_values = miniflow_get_values(&mask->masks); > + const uint64_t *flow_u64 = (const uint64_t *)flow; > + const uint64_t *p = mask_values; > uint32_t hash; > int idx; > > hash = basis; > MAP_FOR_EACH_INDEX(idx, mask->masks.map) { > - hash = hash_add(hash, flow_u32[idx] & *p++); > + hash = hash_add64(hash, flow_u64[idx] & *p++); > } > > - return hash_finish(hash, (p - mask_values) * 4); > + return hash_finish(hash, (p - mask_values) * 8); > } > > /* Returns a hash value for the bits of 'flow' where there are 1-bits in > @@ -151,16 +151,16 @@ static inline uint32_t > miniflow_hash_in_minimask(const struct miniflow *flow, > const struct minimask *mask, uint32_t basis) > { > - const uint32_t *mask_values = miniflow_get_u32_values(&mask->masks); > - const uint32_t *p = mask_values; > + const uint64_t *mask_values = miniflow_get_values(&mask->masks); > + const uint64_t *p = mask_values; > uint32_t hash = basis; > - uint32_t flow_u32; > + uint64_t flow_u64; > > - MINIFLOW_FOR_EACH_IN_MAP(flow_u32, flow, mask->masks.map) { > - hash = hash_add(hash, flow_u32 & *p++); > + MINIFLOW_FOR_EACH_IN_MAP(flow_u64, flow, mask->masks.map) { > + hash = hash_add64(hash, flow_u64 & *p++); > } > > - return hash_finish(hash, (p - mask_values) * 4); > + return hash_finish(hash, (p - mask_values) * 8); > } > > /* Returns a hash value for the bits of range [start, end) in 'flow', > @@ -173,22 +173,22 @@ 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 *mask_values = miniflow_get_u32_values(&mask->masks); > - const uint32_t *flow_u32 = (const uint32_t *)flow; > + const uint64_t *mask_values = miniflow_get_values(&mask->masks); > + const uint64_t *flow_u64 = (const uint64_t *)flow; > unsigned int offset; > uint64_t map; > - const uint32_t *p; > + const uint64_t *p; > uint32_t hash = *basis; > int idx; > > map = miniflow_get_map_in_range(&mask->masks, start, end, &offset); > p = mask_values + offset; > MAP_FOR_EACH_INDEX(idx, map) { > - hash = hash_add(hash, flow_u32[idx] & *p++); > + hash = hash_add64(hash, flow_u64[idx] & *p++); > } > > *basis = hash; /* Allow continuation from the unfinished value. */ > - return hash_finish(hash, (p - mask_values) * 4); > + return hash_finish(hash, (p - mask_values) * 8); > } > > /* Fold minimask 'mask''s wildcard mask into 'wc's wildcard mask. */ > @@ -206,16 +206,16 @@ 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; > + uint64_t *dst_u64 = (uint64_t *)&wc->masks; > unsigned int offset; > uint64_t map; > - const uint32_t *p; > + const uint64_t *p; > int idx; > > map = miniflow_get_map_in_range(&mask->masks, start, end, &offset); > - p = miniflow_get_u32_values(&mask->masks) + offset; > + p = miniflow_get_values(&mask->masks) + offset; > MAP_FOR_EACH_INDEX(idx, map) { > - dst_u32[idx] |= *p++; > + dst_u64[idx] |= *p++; > } > } > > @@ -223,15 +223,15 @@ flow_wildcards_fold_minimask_range(struct > flow_wildcards *wc, > static inline uint32_t > miniflow_hash(const struct miniflow *flow, uint32_t basis) > { > - const uint32_t *values = miniflow_get_u32_values(flow); > - const uint32_t *p = values; > + const uint64_t *values = miniflow_get_values(flow); > + const uint64_t *p = 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 = hash_add(hash, *p); > + hash = hash_add64(hash, *p); > hash_map |= rightmost_1bit(map); > } > p++; > @@ -265,20 +265,20 @@ minimatch_hash_range(const struct minimatch *match, > uint8_t start, uint8_t end, > uint32_t *basis) > { > unsigned int offset; > - const uint32_t *p, *q; > + const uint64_t *p, *q; > uint32_t hash = *basis; > int n, i; > > n = count_1bits(miniflow_get_map_in_range(&match->mask.masks, start, > end, > &offset)); > - q = miniflow_get_u32_values(&match->mask.masks) + offset; > - p = miniflow_get_u32_values(&match->flow) + offset; > + q = miniflow_get_values(&match->mask.masks) + offset; > + p = miniflow_get_values(&match->flow) + offset; > > for (i = 0; i < n; i++) { > - hash = hash_add(hash, p[i] & q[i]); > + hash = hash_add64(hash, p[i] & q[i]); > } > *basis = hash; /* Allow continuation from the unfinished value. */ > - return hash_finish(hash, (offset + n) * 4); > + return hash_finish(hash, (offset + n) * 8); > } > > #endif > diff --git a/lib/classifier.c b/lib/classifier.c > index bbc5a4a..0ac5356 100644 > --- a/lib/classifier.c > +++ b/lib/classifier.c > @@ -34,6 +34,8 @@ struct trie_ctx; > /* Ports trie depends on both ports sharing the same ovs_be32. */ > #define TP_PORTS_OFS32 (offsetof(struct flow, tp_src) / 4) > BUILD_ASSERT_DECL(TP_PORTS_OFS32 == offsetof(struct flow, tp_dst) / 4); > +BUILD_ASSERT_DECL(TP_PORTS_OFS32 % 2 == 0); > +#define TP_PORTS_OFS64 (TP_PORTS_OFS32 / 2) > > static struct cls_match * > cls_match_alloc(const struct cls_rule *rule) > @@ -240,7 +242,7 @@ classifier_init(struct classifier *cls, const uint8_t > *flow_segments) > cls->n_flow_segments = 0; > if (flow_segments) { > while (cls->n_flow_segments < CLS_MAX_INDICES > - && *flow_segments < FLOW_U32S) { > + && *flow_segments < FLOW_U64S) { > cls->flow_segments[cls->n_flow_segments++] = *flow_segments++; > } > } > @@ -409,10 +411,9 @@ classifier_count(const struct classifier *cls) > } > > static uint32_t > -hash_metadata(ovs_be64 metadata_) > +hash_metadata(ovs_be64 metadata) > { > - uint64_t metadata = (OVS_FORCE uint64_t) metadata_; > - return hash_uint64(metadata); > + return hash_uint64((OVS_FORCE uint64_t) metadata); > } > > static struct cls_partition * > @@ -491,7 +492,7 @@ classifier_replace(struct classifier *cls, const > struct cls_rule *rule) > struct cls_match *new = cls_match_alloc(rule); > struct cls_subtable *subtable; > uint32_t ihash[CLS_MAX_INDICES]; > - uint8_t prev_be32ofs = 0; > + uint8_t prev_be64ofs = 0; > struct cls_match *head; > size_t n_rules = 0; > uint32_t basis; > @@ -508,11 +509,11 @@ classifier_replace(struct classifier *cls, const > struct cls_rule *rule) > /* Compute hashes in segments. */ > basis = 0; > for (i = 0; i < subtable->n_indices; i++) { > - ihash[i] = minimatch_hash_range(&rule->match, prev_be32ofs, > + ihash[i] = minimatch_hash_range(&rule->match, prev_be64ofs, > subtable->index_ofs[i], &basis); > - prev_be32ofs = subtable->index_ofs[i]; > + prev_be64ofs = subtable->index_ofs[i]; > } > - hash = minimatch_hash_range(&rule->match, prev_be32ofs, FLOW_U32S, > &basis); > + hash = minimatch_hash_range(&rule->match, prev_be64ofs, FLOW_U64S, > &basis); > > head = find_equal(subtable, &rule->match.flow, hash); > if (!head) { > @@ -674,7 +675,7 @@ classifier_remove(struct classifier *cls, const struct > cls_rule *rule) > struct cls_match *next; > int i; > uint32_t basis = 0, hash, ihash[CLS_MAX_INDICES]; > - uint8_t prev_be32ofs = 0; > + uint8_t prev_be64ofs = 0; > size_t n_rules; > > cls_match = rule->cls_match; > @@ -704,11 +705,11 @@ classifier_remove(struct classifier *cls, const > struct cls_rule *rule) > ovs_assert(subtable); > > for (i = 0; i < subtable->n_indices; i++) { > - ihash[i] = minimatch_hash_range(&rule->match, prev_be32ofs, > + ihash[i] = minimatch_hash_range(&rule->match, prev_be64ofs, > subtable->index_ofs[i], &basis); > - prev_be32ofs = subtable->index_ofs[i]; > + prev_be64ofs = subtable->index_ofs[i]; > } > - hash = minimatch_hash_range(&rule->match, prev_be32ofs, FLOW_U32S, > &basis); > + hash = minimatch_hash_range(&rule->match, prev_be64ofs, FLOW_U64S, > &basis); > > /* Head rule. Check if 'next' is an identical, lower-priority rule > that > * will replace 'rule' in the data structures. */ > @@ -943,7 +944,7 @@ classifier_rule_overlaps(const struct classifier *cls, > /* Iterate subtables in the descending max priority order. */ > PVECTOR_FOR_EACH_PRIORITY (subtable, target->priority - 1, 2, > sizeof(struct cls_subtable), > &cls->subtables) { > - uint32_t storage[FLOW_U32S]; > + uint64_t storage[FLOW_U64S]; > struct minimask mask; > const struct cls_rule *rule; > > @@ -1148,7 +1149,7 @@ insert_subtable(struct classifier *cls, const struct > minimask *mask) > /* Check if the rest of the subtable's mask adds any bits, > * and remove the last index if it doesn't. */ > if (index > 0) { > - flow_wildcards_fold_minimask_range(&new, mask, prev, FLOW_U32S); > + flow_wildcards_fold_minimask_range(&new, mask, prev, FLOW_U64S); > if (flow_wildcards_equal(&new, &old)) { > --index; > *CONST_CAST(uint8_t *, &subtable->index_ofs[index]) = 0; > @@ -1227,9 +1228,10 @@ check_tries(struct trie_ctx > trie_ctx[CLS_MAX_TRIES], unsigned int n_tries, > if (field_plen[j]) { > struct trie_ctx *ctx = &trie_ctx[j]; > uint8_t be32ofs = ctx->be32ofs; > + uint8_t be64ofs = be32ofs / 2; > > /* Is the trie field within the current range of fields? */ > - if (be32ofs >= ofs.start && be32ofs < ofs.end) { > + if (be64ofs >= ofs.start && be64ofs < ofs.end) { > /* On-demand trie lookup. */ > if (!ctx->lookup_done) { > memset(&ctx->match_plens, 0, sizeof ctx->match_plens); > @@ -1281,12 +1283,12 @@ miniflow_and_mask_matches_flow(const struct > miniflow *flow, > const struct minimask *mask, > const struct flow *target) > { > - const uint32_t *flowp = miniflow_get_u32_values(flow); > - const uint32_t *maskp = miniflow_get_u32_values(&mask->masks); > + const uint64_t *flowp = miniflow_get_values(flow); > + const uint64_t *maskp = miniflow_get_values(&mask->masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, mask->masks.map) { > - uint32_t diff = (*flowp++ ^ flow_u32_value(target, idx)) & > *maskp++; > + uint64_t diff = (*flowp++ ^ flow_u64_value(target, idx)) & > *maskp++; > > if (diff) { > return false; > @@ -1324,26 +1326,26 @@ miniflow_and_mask_matches_flow_wc(const struct > miniflow *flow, > const struct flow *target, > struct flow_wildcards *wc) > { > - const uint32_t *flowp = miniflow_get_u32_values(flow); > - const uint32_t *maskp = miniflow_get_u32_values(&mask->masks); > + const uint64_t *flowp = miniflow_get_values(flow); > + const uint64_t *maskp = miniflow_get_values(&mask->masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, mask->masks.map) { > - uint32_t mask = *maskp++; > - uint32_t diff = (*flowp++ ^ flow_u32_value(target, idx)) & mask; > + uint64_t mask = *maskp++; > + uint64_t diff = (*flowp++ ^ flow_u64_value(target, idx)) & mask; > > if (diff) { > /* Only unwildcard if none of the differing bits is already > * exact-matched. */ > - if (!(flow_u32_value(&wc->masks, idx) & diff)) { > + if (!(flow_u64_value(&wc->masks, idx) & diff)) { > /* Keep one bit of the difference. The selected bit may > be > * different in big-endian v.s. little-endian systems. */ > - *flow_u32_lvalue(&wc->masks, idx) |= rightmost_1bit(diff); > + *flow_u64_lvalue(&wc->masks, idx) |= rightmost_1bit(diff); > } > return false; > } > /* Fill in the bits that were looked at. */ > - *flow_u32_lvalue(&wc->masks, idx) |= mask; > + *flow_u64_lvalue(&wc->masks, idx) |= mask; > } > > return true; > @@ -1413,7 +1415,7 @@ find_match_wc(const struct cls_subtable *subtable, > const struct flow *flow, > } > ofs.start = ofs.end; > } > - ofs.end = FLOW_U32S; > + ofs.end = FLOW_U64S; > /* Trie check for the final range. */ > if (check_tries(trie_ctx, n_tries, subtable->trie_plen, ofs, flow, > wc)) { > fill_range_wc(subtable, wc, ofs.start); > @@ -1438,7 +1440,7 @@ find_match_wc(const struct cls_subtable *subtable, > const struct flow *flow, > > /* Unwildcard all bits in the mask upto the ports, as they were > used > * to determine there is no match. */ > - fill_range_wc(subtable, wc, TP_PORTS_OFS32); > + fill_range_wc(subtable, wc, TP_PORTS_OFS64); > return NULL; > } > > @@ -1727,12 +1729,11 @@ minimask_get_prefix_len(const struct minimask > *minimask, > const struct mf_field *mf) > { > unsigned int n_bits = 0, mask_tz = 0; /* Non-zero when end of mask > seen. */ > - uint8_t u32_ofs = mf->flow_be32ofs; > - uint8_t u32_end = u32_ofs + mf->n_bytes / 4; > + uint8_t be32_ofs = mf->flow_be32ofs; > + uint8_t be32_end = be32_ofs + mf->n_bytes / 4; > > - for (; u32_ofs < u32_end; ++u32_ofs) { > - uint32_t mask; > - mask = ntohl((OVS_FORCE ovs_be32)minimask_get(minimask, u32_ofs)); > + for (; be32_ofs < be32_end; ++be32_ofs) { > + uint32_t mask = ntohl(minimask_get_be32(minimask, be32_ofs)); > > /* Validate mask, count the mask length. */ > if (mask_tz) { > @@ -1760,8 +1761,11 @@ minimask_get_prefix_len(const struct minimask > *minimask, > static const ovs_be32 * > minimatch_get_prefix(const struct minimatch *match, const struct mf_field > *mf) > { > - return miniflow_get_be32_values(&match->flow) + > - count_1bits(match->flow.map & ((UINT64_C(1) << mf->flow_be32ofs) > - 1)); > + return (OVS_FORCE const ovs_be32 *) > + (miniflow_get_values(&match->flow) > + + count_1bits(match->flow.map & > + ((UINT64_C(1) << mf->flow_be32ofs / 2) - 1))) > + + (mf->flow_be32ofs & 1); > } > > /* Insert rule in to the prefix tree. > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index c23decb..18864f9 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -93,7 +93,7 @@ struct netdev_flow_key { > uint32_t hash; /* Hash function differs for different users. */ > uint32_t len; /* Length of the following miniflow (incl. map). > */ > struct miniflow mf; > - uint32_t buf[FLOW_MAX_PACKET_U32S - MINI_N_INLINE]; > + uint64_t buf[FLOW_MAX_PACKET_U64S - MINI_N_INLINE]; > }; > > /* Exact match cache for frequently used flows > @@ -1365,8 +1365,8 @@ static inline void > netdev_flow_mask_init(struct netdev_flow_key *mask, > const struct match *match) > { > - const uint32_t *mask_u32 = (const uint32_t *) &match->wc.masks; > - uint32_t *dst = mask->mf.inline_values; > + const uint64_t *mask_u64 = (const uint64_t *) &match->wc.masks; > + uint64_t *dst = mask->mf.inline_values; > uint64_t map, mask_map = 0; > uint32_t hash = 0; > int n; > @@ -1378,10 +1378,10 @@ netdev_flow_mask_init(struct netdev_flow_key *mask, > uint64_t rm1bit = rightmost_1bit(map); > int i = raw_ctz(map); > > - if (mask_u32[i]) { > + if (mask_u64[i]) { > mask_map |= rm1bit; > - *dst++ = mask_u32[i]; > - hash = hash_add(hash, mask_u32[i]); > + *dst++ = mask_u64[i]; > + hash = hash_add64(hash, mask_u64[i]); > } > map -= rm1bit; > } > @@ -1393,7 +1393,7 @@ netdev_flow_mask_init(struct netdev_flow_key *mask, > > n = dst - mask->mf.inline_values; > > - mask->hash = hash_finish(hash, n * 4); > + mask->hash = hash_finish(hash, n * 8); > mask->len = netdev_flow_key_size(n); > } > > @@ -1403,23 +1403,23 @@ netdev_flow_key_init_masked(struct netdev_flow_key > *dst, > const struct flow *flow, > const struct netdev_flow_key *mask) > { > - uint32_t *dst_u32 = dst->mf.inline_values; > - const uint32_t *mask_u32 = mask->mf.inline_values; > + uint64_t *dst_u64 = dst->mf.inline_values; > + const uint64_t *mask_u64 = mask->mf.inline_values; > uint32_t hash = 0; > - uint32_t value; > + uint64_t value; > > dst->len = mask->len; > dst->mf.values_inline = true; > dst->mf.map = mask->mf.map; > > FLOW_FOR_EACH_IN_MAP(value, flow, mask->mf.map) { > - *dst_u32 = value & *mask_u32++; > - hash = hash_add(hash, *dst_u32++); > + *dst_u64 = value & *mask_u64++; > + hash = hash_add64(hash, *dst_u64++); > } > - dst->hash = hash_finish(hash, (dst_u32 - dst->mf.inline_values) * 4); > + dst->hash = hash_finish(hash, (dst_u64 - dst->mf.inline_values) * 8); > } > > -/* Iterate through all netdev_flow_key u32 values specified by 'MAP' */ > +/* 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__ \ > = { (KEY)->mf.inline_values, (KEY)->mf.map, MAP }; \ > @@ -1432,15 +1432,15 @@ static inline uint32_t > netdev_flow_key_hash_in_mask(const struct netdev_flow_key *key, > const struct netdev_flow_key *mask) > { > - const uint32_t *p = mask->mf.inline_values; > + const uint64_t *p = mask->mf.inline_values; > uint32_t hash = 0; > - uint32_t key_u32; > + uint64_t key_u64; > > - NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(key_u32, key, mask->mf.map) { > - hash = hash_add(hash, key_u32 & *p++); > + NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(key_u64, key, mask->mf.map) { > + hash = hash_add64(hash, key_u64 & *p++); > } > > - return hash_finish(hash, (p - mask->mf.inline_values) * 4); > + return hash_finish(hash, (p - mask->mf.inline_values) * 8); > } > > static inline bool > @@ -3492,12 +3492,12 @@ static inline bool > dpcls_rule_matches_key(const struct dpcls_rule *rule, > const struct netdev_flow_key *target) > { > - const uint32_t *keyp = rule->flow.mf.inline_values; > - const uint32_t *maskp = rule->mask->mf.inline_values; > - uint32_t target_u32; > + const uint64_t *keyp = rule->flow.mf.inline_values; > + const uint64_t *maskp = rule->mask->mf.inline_values; > + uint64_t target_u64; > > - NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(target_u32, target, > rule->flow.mf.map) { > - if (OVS_UNLIKELY((target_u32 & *maskp++) != *keyp++)) { > + NETDEV_FLOW_KEY_FOR_EACH_IN_MAP(target_u64, target, > rule->flow.mf.map) { > + if (OVS_UNLIKELY((target_u64 & *maskp++) != *keyp++)) { > return false; > } > } > diff --git a/lib/flow.c b/lib/flow.c > index 521ee82..3c42ec1 100644 > --- a/lib/flow.c > +++ b/lib/flow.c > @@ -42,12 +42,12 @@ > COVERAGE_DEFINE(flow_extract); > COVERAGE_DEFINE(miniflow_malloc); > > -/* U32 indices for segmented flow classification. */ > -const uint8_t flow_segment_u32s[4] = { > - FLOW_SEGMENT_1_ENDS_AT / 4, > - FLOW_SEGMENT_2_ENDS_AT / 4, > - FLOW_SEGMENT_3_ENDS_AT / 4, > - FLOW_U32S > +/* U64 indices for segmented flow classification. */ > +const uint8_t flow_segment_u64s[4] = { > + FLOW_SEGMENT_1_ENDS_AT / sizeof(uint64_t), > + FLOW_SEGMENT_2_ENDS_AT / sizeof(uint64_t), > + FLOW_SEGMENT_3_ENDS_AT / sizeof(uint64_t), > + FLOW_U64S > }; > > /* miniflow_extract() assumes the following to be true to optimize the > @@ -70,11 +70,9 @@ BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) + 3 > offsetof(struct flow, nw_proto) / 4 > == offsetof(struct flow, nw_tos) / 4); > > -/* TCP flags in the first half of a BE32, zeroes in the other half. */ > -BUILD_ASSERT_DECL(offsetof(struct flow, tcp_flags) + 2 > - == offsetof(struct flow, pad2) && > - offsetof(struct flow, tcp_flags) / 4 > - == offsetof(struct flow, pad2) / 4); > +/* TCP flags in the middle of a BE64, zeroes in the other half. */ > +BUILD_ASSERT_DECL(offsetof(struct flow, tcp_flags) % 8 == 4); > + > #if WORDS_BIGENDIAN > #define TCP_FLAGS_BE32(tcp_ctl) ((OVS_FORCE > ovs_be32)TCP_FLAGS_BE16(tcp_ctl) \ > << 16) > @@ -111,8 +109,8 @@ data_try_pull(void **datap, size_t *sizep, size_t size) > /* Context for pushing data to a miniflow. */ > struct mf_ctx { > uint64_t map; > - uint32_t *data; > - uint32_t * const end; > + uint64_t *data; > + uint64_t * const end; > }; > > /* miniflow_push_* macros allow filling in a miniflow data values in > order. > @@ -121,7 +119,7 @@ struct mf_ctx { > * away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are > * defined as macros. */ > > -#if (FLOW_WC_SEQ != 28) > +#if (FLOW_WC_SEQ != 29) > #define MINIFLOW_ASSERT(X) ovs_assert(X) > BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " > "assertions enabled. Consider updating FLOW_WC_SEQ after " > @@ -130,76 +128,137 @@ BUILD_MESSAGE("FLOW_WC_SEQ changed: > miniflow_extract() will have runtime " > #define MINIFLOW_ASSERT(X) > #endif > > -#define miniflow_push_uint32_(MF, OFS, VALUE) \ > +#define miniflow_push_uint64_(MF, OFS, VALUE) \ > { \ > - MINIFLOW_ASSERT(MF.data < MF.end && (OFS) % 4 == 0 \ > - && !(MF.map & (UINT64_MAX << (OFS) / 4))); \ > + MINIFLOW_ASSERT(MF.data < MF.end && (OFS) % 8 == 0 \ > + && !(MF.map & (UINT64_MAX << (OFS) / 8))); \ > *MF.data++ = VALUE; \ > - MF.map |= UINT64_C(1) << (OFS) / 4; \ > + MF.map |= UINT64_C(1) << (OFS) / 8; \ > } > > -#define miniflow_push_be32_(MF, OFS, VALUE) \ > - miniflow_push_uint32_(MF, OFS, (OVS_FORCE uint32_t)(VALUE)) > +#define miniflow_push_be64_(MF, OFS, VALUE) \ > + miniflow_push_uint64_(MF, OFS, (OVS_FORCE uint64_t)(VALUE)) > > -#define miniflow_push_uint16_(MF, OFS, VALUE) \ > +#define miniflow_push_uint32_(MF, OFS, VALUE) \ > { \ > MINIFLOW_ASSERT(MF.data < MF.end && \ > - (((OFS) % 4 == 0 && !(MF.map & (UINT64_MAX << (OFS) / > 4))) \ > - || ((OFS) % 4 == 2 && MF.map & (UINT64_C(1) << (OFS) > / 4) \ > - && !(MF.map & (UINT64_MAX << ((OFS) / 4 + > 1)))))); \ > + (((OFS) % 8 == 0 && !(MF.map & (UINT64_MAX << (OFS) / > 8))) \ > + || ((OFS) % 8 == 4 && MF.map & (UINT64_C(1) << (OFS) > / 8) \ > + && !(MF.map & (UINT64_MAX << ((OFS) / 8 + > 1)))))); \ > + \ > + if ((OFS) % 8 == 0) { \ > + *(uint32_t *)MF.data = VALUE; \ > + MF.map |= UINT64_C(1) << (OFS) / 8; \ > + } else if ((OFS) % 8 == 4) { \ > + *((uint32_t *)MF.data + 1) = VALUE; \ > + MF.data++; \ > + } \ > +} > + > +#define miniflow_push_be32_(MF, OFS, VALUE) \ > + miniflow_push_uint32_(MF, OFS, (OVS_FORCE uint32_t)(VALUE)) > + > +#define miniflow_push_uint16_(MF, OFS, VALUE) \ > +{ \ > + MINIFLOW_ASSERT(MF.data < MF.end && \ > + (((OFS) % 8 == 0 && !(MF.map & (UINT64_MAX << (OFS) / > 8))) \ > + || ((OFS) % 2 == 0 && MF.map & (UINT64_C(1) << (OFS) > / 8) \ > + && !(MF.map & (UINT64_MAX << ((OFS) / 8 + > 1)))))); \ > \ > - if ((OFS) % 4 == 0) { \ > + if ((OFS) % 8 == 0) { \ > *(uint16_t *)MF.data = VALUE; \ > - MF.map |= UINT64_C(1) << (OFS) / 4; \ > - } else if ((OFS) % 4 == 2) { \ > + MF.map |= UINT64_C(1) << (OFS) / 8; \ > + } else if ((OFS) % 8 == 2) { \ > *((uint16_t *)MF.data + 1) = VALUE; \ > + } else if ((OFS) % 8 == 4) { \ > + *((uint16_t *)MF.data + 2) = VALUE; \ > + } else if ((OFS) % 8 == 6) { \ > + *((uint16_t *)MF.data + 3) = VALUE; \ > MF.data++; \ > } \ > } > So I am assuming these calls should come in groups of 4 for the increment to work ? This does not show up in the diff but was wondering how this would get incremented and map set for say the ethernet header where we have 468 vlan_tci = parse_vlan(&data, &size); 469 dl_type = parse_ethertype(&data, &size); 470 miniflow_push_be16(mf, dl_type, dl_type); 471 miniflow_push_be16(mf, vlan_tci, vlan_tci); 472 } > > -#define miniflow_push_be16_(MF, OFS, VALUE) \ > +#define miniflow_pad_to_64_(MF, OFS) \ > +{ \ > + MINIFLOW_ASSERT((OFS) % 8 != 0); \ > + MINIFLOW_ASSERT(MF.map & (UINT64_C(1) << (OFS) / 8)); \ > + MINIFLOW_ASSERT(!(MF.map & (UINT64_MAX << ((OFS) / 8 + 1)))); \ > + \ > + memset((uint8_t *)MF.data + (OFS) % 8, 0, 8 - (OFS) % 8); \ > + MF.data++; \ > +} > + > +#define miniflow_push_be16_(MF, OFS, VALUE) \ > miniflow_push_uint16_(MF, OFS, (OVS_FORCE uint16_t)VALUE); > > /* Data at 'valuep' may be unaligned. */ > #define miniflow_push_words_(MF, OFS, VALUEP, N_WORDS) \ > { \ > - int ofs32 = (OFS) / 4; \ > + int ofs64 = (OFS) / 8; \ > \ > - MINIFLOW_ASSERT(MF.data + (N_WORDS) <= MF.end && (OFS) % 4 == 0 \ > - && !(MF.map & (UINT64_MAX << ofs32))); \ > + MINIFLOW_ASSERT(MF.data + (N_WORDS) <= MF.end && (OFS) % 8 == 0 \ > + && !(MF.map & (UINT64_MAX << ofs64))); \ > \ > memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof *MF.data); \ > MF.data += (N_WORDS); \ > - MF.map |= ((UINT64_MAX >> (64 - (N_WORDS))) << ofs32); \ > + MF.map |= ((UINT64_MAX >> (64 - (N_WORDS))) << ofs64); \ > } > > -#define miniflow_push_uint32(MF, FIELD, VALUE) \ > - miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), VALUE) > +/* Push 32-bit words padded to 64-bits. */ > +#define miniflow_push_words_32_(MF, OFS, VALUEP, N_WORDS) \ > +{ \ > + int ofs64 = (OFS) / 8; \ > + \ > + MINIFLOW_ASSERT(MF.data + DIV_ROUND_UP(N_WORDS, 2) <= MF.end \ > + && (OFS) % 8 == 0 \ > + && !(MF.map & (UINT64_MAX << ofs64))); \ > + \ > + memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof(uint32_t)); \ > + MF.data += DIV_ROUND_UP(N_WORDS, 2); \ > + MF.map |= ((UINT64_MAX >> (64 - DIV_ROUND_UP(N_WORDS, 2))) << ofs64); > \ > + if ((N_WORDS) & 1) { \ > + *((uint32_t *)MF.data - 1) = 0; \ > + } \ > +} > > -#define miniflow_push_be32(MF, FIELD, VALUE) \ > - miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE) > +/* Data at 'valuep' may be unaligned. */ > +/* MACs start 64-aligned, and must be followed by other data or padding. > */ > +#define miniflow_push_macs_(MF, OFS, VALUEP) \ > +{ \ > + int ofs64 = (OFS) / 8; \ > + \ > + MINIFLOW_ASSERT(MF.data + 2 <= MF.end && (OFS) % 8 == 0 \ > + && !(MF.map & (UINT64_MAX << ofs64))); \ > + \ > + memcpy(MF.data, (VALUEP), 2 * ETH_ADDR_LEN); \ > + MF.data += 1; /* First word only. */ \ > + MF.map |= UINT64_C(3) << ofs64; /* Both words. */ \ > +} > > -#define miniflow_push_uint32_check(MF, FIELD, VALUE) \ > - { if (OVS_LIKELY(VALUE)) { \ > - miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), > VALUE); \ > - } \ > - } > +#define miniflow_push_uint32(MF, FIELD, VALUE) \ > + miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), VALUE) > > -#define miniflow_push_be32_check(MF, FIELD, VALUE) \ > - { if (OVS_LIKELY(VALUE)) { \ > - miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE); > \ > - } \ > - } > +#define miniflow_push_be32(MF, FIELD, VALUE) \ > + miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE) > > -#define miniflow_push_uint16(MF, FIELD, VALUE) \ > +#define miniflow_push_uint16(MF, FIELD, VALUE) \ > miniflow_push_uint16_(MF, offsetof(struct flow, FIELD), VALUE) > > -#define miniflow_push_be16(MF, FIELD, VALUE) \ > +#define miniflow_push_be16(MF, FIELD, VALUE) \ > miniflow_push_be16_(MF, offsetof(struct flow, FIELD), VALUE) > > +#define miniflow_pad_to_64(MF, FIELD) \ > + miniflow_pad_to_64_(MF, offsetof(struct flow, FIELD)) > + > #define miniflow_push_words(MF, FIELD, VALUEP, N_WORDS) \ > miniflow_push_words_(MF, offsetof(struct flow, FIELD), VALUEP, > N_WORDS) > > +#define miniflow_push_words_32(MF, FIELD, VALUEP, N_WORDS) \ > + miniflow_push_words_32_(MF, offsetof(struct flow, FIELD), VALUEP, > N_WORDS) > + > +#define miniflow_push_macs(MF, FIELD, VALUEP) \ > + miniflow_push_macs_(MF, offsetof(struct flow, FIELD), VALUEP) > + > /* Pulls the MPLS headers at '*datap' and returns the count of them. */ > static inline int > parse_mpls(void **datap, size_t *sizep) > @@ -349,7 +408,7 @@ flow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > { > struct { > struct miniflow mf; > - uint32_t buf[FLOW_U32S]; > + uint64_t buf[FLOW_U64S]; > } m; > > COVERAGE_INC(flow_extract); > @@ -360,15 +419,15 @@ flow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > } > > /* Caller is responsible for initializing 'dst' with enough storage for > - * FLOW_U32S * 4 bytes. */ > + * FLOW_U64S * 8 bytes. */ > void > miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, > struct miniflow *dst) > { > void *data = ofpbuf_data(packet); > size_t size = ofpbuf_size(packet); > - uint32_t *values = miniflow_values(dst); > - struct mf_ctx mf = { 0, values, values + FLOW_U32S }; > + uint64_t *values = miniflow_values(dst); > + struct mf_ctx mf = { 0, values, values + FLOW_U64S }; > char *l2; > ovs_be16 dl_type; > uint8_t nw_frag, nw_tos, nw_ttl, nw_proto; > @@ -377,12 +436,18 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > if (md) { > if (md->tunnel.ip_dst) { > miniflow_push_words(mf, tunnel, &md->tunnel, > - sizeof md->tunnel / 4); > + sizeof md->tunnel / sizeof(uint64_t)); > + } > + if (md->skb_priority || md->pkt_mark) { > + miniflow_push_uint32(mf, skb_priority, md->skb_priority); > + miniflow_push_uint32(mf, pkt_mark, md->pkt_mark); > } > - miniflow_push_uint32_check(mf, skb_priority, md->skb_priority); > - miniflow_push_uint32_check(mf, pkt_mark, md->pkt_mark); > - miniflow_push_uint32_check(mf, recirc_id, md->recirc_id); > + miniflow_push_uint32(mf, dp_hash, md->dp_hash); > miniflow_push_uint32(mf, in_port, > odp_to_u32(md->in_port.odp_port)); > + if (md->recirc_id) { > + miniflow_push_uint32(mf, recirc_id, md->recirc_id); > + miniflow_pad_to_64(mf, actset_output); > + } > } > > /* Initialize packet's layer pointer and offsets. */ > @@ -398,7 +463,7 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > /* Link layer. */ > BUILD_ASSERT(offsetof(struct flow, dl_dst) + 6 > == offsetof(struct flow, dl_src)); > - miniflow_push_words(mf, dl_dst, data, ETH_ADDR_LEN * 2 / 4); > + miniflow_push_macs(mf, dl_dst, data); > /* dl_type, vlan_tci. */ > vlan_tci = parse_vlan(&data, &size); > dl_type = parse_ethertype(&data, &size); > @@ -413,7 +478,7 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > > packet->l2_5_ofs = (char *)data - l2; > count = parse_mpls(&data, &size); > - miniflow_push_words(mf, mpls_lse, mpls, count); > + miniflow_push_words_32(mf, mpls_lse, mpls, count); > } > > /* Network layer. */ > @@ -447,7 +512,9 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > size = tot_len; /* Never pull padding. */ > > /* Push both source and destination address at once. */ > - miniflow_push_words(mf, nw_src, &nh->ip_src, 2); > + miniflow_push_words(mf, nw_src, &nh->ip_src, 1); > + > + miniflow_push_be32(mf, ipv6_label, 0); /* Padding for IPv4. */ > > nw_tos = nh->ip_tos; > nw_ttl = nh->ip_ttl; > @@ -481,14 +548,14 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > size = plen; /* Never pull padding. */ > > miniflow_push_words(mf, ipv6_src, &nh->ip6_src, > - sizeof nh->ip6_src / 4); > + sizeof nh->ip6_src / 8); > miniflow_push_words(mf, ipv6_dst, &nh->ip6_dst, > - sizeof nh->ip6_dst / 4); > + sizeof nh->ip6_dst / 8); > > tc_flow = get_16aligned_be32(&nh->ip6_flow); > { > ovs_be32 label = tc_flow & htonl(IPV6_LABEL_MASK); > - miniflow_push_be32_check(mf, ipv6_label, label); > + miniflow_push_be32(mf, ipv6_label, label); > } > > nw_tos = ntohl(tc_flow) >> 20; > @@ -569,11 +636,14 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > && OVS_LIKELY(arp->ar_pro == htons(ETH_TYPE_IP)) > && OVS_LIKELY(arp->ar_hln == ETH_ADDR_LEN) > && OVS_LIKELY(arp->ar_pln == 4)) { > - miniflow_push_words(mf, nw_src, &arp->ar_spa, 1); > - miniflow_push_words(mf, nw_dst, &arp->ar_tpa, 1); > + miniflow_push_be32(mf, nw_src, > + get_16aligned_be32(&arp->ar_spa)); > + miniflow_push_be32(mf, nw_dst, > + get_16aligned_be32(&arp->ar_tpa)); > > /* We only match on the lower 8 bits of the opcode. */ > if (OVS_LIKELY(ntohs(arp->ar_op) <= 0xff)) { > + miniflow_push_be32(mf, ipv6_label, 0); /* Pad with > ARP. */ > miniflow_push_be32(mf, nw_frag, > htonl(ntohs(arp->ar_op))); > } > > @@ -583,8 +653,8 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > > memcpy(arp_buf[0], arp->ar_sha, ETH_ADDR_LEN); > memcpy(arp_buf[1], arp->ar_tha, ETH_ADDR_LEN); > - miniflow_push_words(mf, arp_sha, arp_buf, > - ETH_ADDR_LEN * 2 / 4); > + miniflow_push_macs(mf, arp_sha, arp_buf); > + miniflow_pad_to_64(mf, tcp_flags); > } > } > goto out; > @@ -599,21 +669,25 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > if (OVS_LIKELY(size >= TCP_HEADER_LEN)) { > const struct tcp_header *tcp = data; > > + miniflow_push_be32(mf, arp_tha[2], 0); > miniflow_push_be32(mf, tcp_flags, > TCP_FLAGS_BE32(tcp->tcp_ctl)); > miniflow_push_words(mf, tp_src, &tcp->tcp_src, 1); > + miniflow_pad_to_64(mf, igmp_group_ip4); > } > } else if (OVS_LIKELY(nw_proto == IPPROTO_UDP)) { > if (OVS_LIKELY(size >= UDP_HEADER_LEN)) { > const struct udp_header *udp = data; > > miniflow_push_words(mf, tp_src, &udp->udp_src, 1); > + miniflow_pad_to_64(mf, igmp_group_ip4); > } > } else if (OVS_LIKELY(nw_proto == IPPROTO_SCTP)) { > if (OVS_LIKELY(size >= SCTP_HEADER_LEN)) { > const struct sctp_header *sctp = data; > > miniflow_push_words(mf, tp_src, &sctp->sctp_src, 1); > + miniflow_pad_to_64(mf, igmp_group_ip4); > } > } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMP)) { > if (OVS_LIKELY(size >= ICMP_HEADER_LEN)) { > @@ -621,6 +695,7 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > > miniflow_push_be16(mf, tp_src, htons(icmp->icmp_type)); > miniflow_push_be16(mf, tp_dst, htons(icmp->icmp_code)); > + miniflow_pad_to_64(mf, igmp_group_ip4); > } > } else if (OVS_LIKELY(nw_proto == IPPROTO_IGMP)) { > if (OVS_LIKELY(size >= IGMP_HEADER_LEN)) { > @@ -640,21 +715,19 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > memset(arp_buf, 0, sizeof arp_buf); > if (OVS_LIKELY(parse_icmpv6(&data, &size, icmp, > &nd_target, > arp_buf))) { > - miniflow_push_words(mf, arp_sha, arp_buf, > - ETH_ADDR_LEN * 2 / 4); > if (nd_target) { > miniflow_push_words(mf, nd_target, nd_target, > - sizeof *nd_target / 4); > + sizeof *nd_target / 8); > } > + miniflow_push_macs(mf, arp_sha, arp_buf); > + miniflow_pad_to_64(mf, tcp_flags); > miniflow_push_be16(mf, tp_src, > htons(icmp->icmp6_type)); > miniflow_push_be16(mf, tp_dst, > htons(icmp->icmp6_code)); > + miniflow_pad_to_64(mf, igmp_group_ip4); > } > } > } > } > - if (md) { > - miniflow_push_uint32_check(mf, dp_hash, md->dp_hash); > - } > out: > dst->map = mf.map; > } > @@ -664,12 +737,12 @@ miniflow_extract(struct ofpbuf *packet, const struct > pkt_metadata *md, > void > flow_zero_wildcards(struct flow *flow, const struct flow_wildcards > *wildcards) > { > - uint32_t *flow_u32 = (uint32_t *) flow; > - const uint32_t *wc_u32 = (const uint32_t *) &wildcards->masks; > + uint64_t *flow_u64 = (uint64_t *) flow; > + const uint64_t *wc_u64 = (const uint64_t *) &wildcards->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - flow_u32[i] &= wc_u32[i]; > + for (i = 0; i < FLOW_U64S; i++) { > + flow_u64[i] &= wc_u64[i]; > } > } > > @@ -689,7 +762,7 @@ flow_unwildcard_tp_ports(const struct flow *flow, > struct flow_wildcards *wc) > void > flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) > { > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > fmd->dp_hash = flow->dp_hash; > fmd->recirc_id = flow->recirc_id; > @@ -836,7 +909,7 @@ void flow_wildcards_init_for_packet(struct > flow_wildcards *wc, > memset(&wc->masks, 0x0, sizeof wc->masks); > > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > if (flow->tunnel.ip_dst) { > if (flow->tunnel.flags & FLOW_TNL_F_KEY) { > @@ -933,7 +1006,7 @@ uint64_t > flow_wc_map(const struct flow *flow) > { > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0; > > @@ -985,7 +1058,7 @@ void > flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc) > { > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata); > memset(&wc->masks.regs, 0, sizeof wc->masks.regs); > @@ -997,11 +1070,11 @@ flow_wildcards_clear_non_packet_fields(struct > flow_wildcards *wc) > bool > flow_wildcards_is_catchall(const struct flow_wildcards *wc) > { > - const uint32_t *wc_u32 = (const uint32_t *) &wc->masks; > + const uint64_t *wc_u64 = (const uint64_t *) &wc->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - if (wc_u32[i]) { > + for (i = 0; i < FLOW_U64S; i++) { > + if (wc_u64[i]) { > return false; > } > } > @@ -1016,13 +1089,13 @@ flow_wildcards_and(struct flow_wildcards *dst, > const struct flow_wildcards *src1, > const struct flow_wildcards *src2) > { > - uint32_t *dst_u32 = (uint32_t *) &dst->masks; > - const uint32_t *src1_u32 = (const uint32_t *) &src1->masks; > - const uint32_t *src2_u32 = (const uint32_t *) &src2->masks; > + uint64_t *dst_u64 = (uint64_t *) &dst->masks; > + const uint64_t *src1_u64 = (const uint64_t *) &src1->masks; > + const uint64_t *src2_u64 = (const uint64_t *) &src2->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - dst_u32[i] = src1_u32[i] & src2_u32[i]; > + for (i = 0; i < FLOW_U64S; i++) { > + dst_u64[i] = src1_u64[i] & src2_u64[i]; > } > } > > @@ -1034,13 +1107,13 @@ flow_wildcards_or(struct flow_wildcards *dst, > const struct flow_wildcards *src1, > const struct flow_wildcards *src2) > { > - uint32_t *dst_u32 = (uint32_t *) &dst->masks; > - const uint32_t *src1_u32 = (const uint32_t *) &src1->masks; > - const uint32_t *src2_u32 = (const uint32_t *) &src2->masks; > + uint64_t *dst_u64 = (uint64_t *) &dst->masks; > + const uint64_t *src1_u64 = (const uint64_t *) &src1->masks; > + const uint64_t *src2_u64 = (const uint64_t *) &src2->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - dst_u32[i] = src1_u32[i] | src2_u32[i]; > + for (i = 0; i < FLOW_U64S; i++) { > + dst_u64[i] = src1_u64[i] | src2_u64[i]; > } > } > > @@ -1066,12 +1139,12 @@ bool > flow_wildcards_has_extra(const struct flow_wildcards *a, > const struct flow_wildcards *b) > { > - const uint32_t *a_u32 = (const uint32_t *) &a->masks; > - const uint32_t *b_u32 = (const uint32_t *) &b->masks; > + const uint64_t *a_u64 = (const uint64_t *) &a->masks; > + const uint64_t *b_u64 = (const uint64_t *) &b->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - if ((a_u32[i] & b_u32[i]) != b_u32[i]) { > + for (i = 0; i < FLOW_U64S; i++) { > + if ((a_u64[i] & b_u64[i]) != b_u64[i]) { > return true; > } > } > @@ -1084,13 +1157,13 @@ bool > flow_equal_except(const struct flow *a, const struct flow *b, > const struct flow_wildcards *wc) > { > - const uint32_t *a_u32 = (const uint32_t *) a; > - const uint32_t *b_u32 = (const uint32_t *) b; > - const uint32_t *wc_u32 = (const uint32_t *) &wc->masks; > + const uint64_t *a_u64 = (const uint64_t *) a; > + const uint64_t *b_u64 = (const uint64_t *) b; > + const uint64_t *wc_u64 = (const uint64_t *) &wc->masks; > size_t i; > > - for (i = 0; i < FLOW_U32S; i++) { > - if ((a_u32[i] ^ b_u32[i]) & wc_u32[i]) { > + for (i = 0; i < FLOW_U64S; i++) { > + if ((a_u64[i] ^ b_u64[i]) & wc_u64[i]) { > return false; > } > } > @@ -1128,22 +1201,18 @@ miniflow_hash_5tuple(const struct miniflow *flow, > uint32_t basis) > > /* 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; > + uint64_t map = MINIFLOW_MAP(ipv6_src) | > MINIFLOW_MAP(ipv6_dst); > + uint64_t value; > > MINIFLOW_FOR_EACH_IN_MAP(value, flow, map) { > - hash = hash_add(hash, value); > + hash = hash_add64(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 = hash_add(hash, value); > - } > + hash = hash_add(hash, MINIFLOW_GET_U32(flow, nw_src)); > + hash = hash_add(hash, MINIFLOW_GET_U32(flow, nw_dst)); > } > + /* Add both ports at once. */ > + hash = hash_add(hash, MINIFLOW_GET_U32(flow, tp_src)); > hash = hash_finish(hash, 42); /* Arbitrary number. */ > } > return hash; > @@ -1163,23 +1232,24 @@ flow_hash_5tuple(const struct flow *flow, uint32_t > basis) > uint32_t hash = basis; > > if (flow) { > - const uint32_t *flow_u32 = (const uint32_t *)flow; > - > hash = hash_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; > + const uint64_t *flow_u64 = (const uint64_t *)flow; > + int ofs = offsetof(struct flow, ipv6_src) / 8; > + int end = ofs + 2 * sizeof flow->ipv6_src / 8; > > - while (ofs < end) { > - hash = hash_add(hash, flow_u32[ofs++]); > + for (;ofs < end; ofs++) { > + hash = hash_add64(hash, flow_u64[ofs]); > } > } else { > hash = hash_add(hash, (OVS_FORCE uint32_t) flow->nw_src); > hash = hash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst); > } > - hash = hash_add(hash, flow_u32[offsetof(struct flow, tp_src) / > 4]); > - > + /* Add both ports at once. */ > + hash = hash_add(hash, > + ((const uint32_t *)flow)[offsetof(struct flow, > tp_src) > + / sizeof(uint32_t)]); > hash = hash_finish(hash, 42); /* Arbitrary number. */ > } > return hash; > @@ -1348,16 +1418,16 @@ uint32_t > flow_hash_in_wildcards(const struct flow *flow, > const struct flow_wildcards *wc, uint32_t basis) > { > - const uint32_t *wc_u32 = (const uint32_t *) &wc->masks; > - const uint32_t *flow_u32 = (const uint32_t *) flow; > + const uint64_t *wc_u64 = (const uint64_t *) &wc->masks; > + const uint64_t *flow_u64 = (const uint64_t *) flow; > uint32_t hash; > size_t i; > > hash = basis; > - for (i = 0; i < FLOW_U32S; i++) { > - hash = hash_add(hash, flow_u32[i] & wc_u32[i]); > + for (i = 0; i < FLOW_U64S; i++) { > + hash = hash_add64(hash, flow_u64[i] & wc_u64[i]); > } > - return hash_finish(hash, 4 * FLOW_U32S); > + return hash_finish(hash, 8 * FLOW_U64S); > } > > /* Sets the VLAN VID that 'flow' matches to 'vid', which is interpreted > as an > @@ -1542,10 +1612,11 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 > mpls_eth_type, > > flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label)); > > - /* Clear all L3 and L4 fields. */ > - BUILD_ASSERT(FLOW_WC_SEQ == 28); > + /* Clear all L3 and L4 fields and dp_hash. */ > + BUILD_ASSERT(FLOW_WC_SEQ == 29); > memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0, > sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT); > + flow->dp_hash = 0; > } > flow->dl_type = mpls_eth_type; > } > @@ -1820,7 +1891,7 @@ miniflow_n_values(const struct miniflow *flow) > return count_1bits(flow->map); > } > > -static uint32_t * > +static uint64_t * > miniflow_alloc_values(struct miniflow *flow, int n) > { > int size = MINIFLOW_VALUES_SIZE(n); > @@ -1838,7 +1909,7 @@ miniflow_alloc_values(struct miniflow *flow, int n) > > /* Completes an initialization of 'dst' as a miniflow copy of 'src' begun > by > * the caller. The caller must have already initialized 'dst->map' > properly > - * to indicate the significant uint32_t elements of 'src'. 'n' must be > the > + * to indicate the significant uint64_t elements of 'src'. 'n' must be > the > * number of 1-bits in 'dst->map'. > * > * Normally the significant elements are the ones that are non-zero. > However, > @@ -1846,17 +1917,17 @@ miniflow_alloc_values(struct miniflow *flow, int n) > * so that the flow and mask always have the same maps. > * > * This function initializes values (either inline if possible or with > - * malloc() otherwise) and copies the uint32_t elements of 'src' > indicated by > + * malloc() otherwise) and copies the uint64_t elements of 'src' > indicated by > * 'dst->map' into it. */ > static void > miniflow_init__(struct miniflow *dst, const struct flow *src, int n) > { > - const uint32_t *src_u32 = (const uint32_t *) src; > - uint32_t *dst_u32 = miniflow_alloc_values(dst, n); > + const uint64_t *src_u64 = (const uint64_t *) src; > + uint64_t *dst_u64 = miniflow_alloc_values(dst, n); > int idx; > > MAP_FOR_EACH_INDEX(idx, dst->map) { > - *dst_u32++ = src_u32[idx]; > + *dst_u64++ = src_u64[idx]; > } > } > > @@ -1866,7 +1937,7 @@ miniflow_init__(struct miniflow *dst, const struct > flow *src, int n) > void > miniflow_init(struct miniflow *dst, const struct flow *src) > { > - const uint32_t *src_u32 = (const uint32_t *) src; > + const uint64_t *src_u64 = (const uint64_t *) src; > unsigned int i; > int n; > > @@ -1874,8 +1945,8 @@ miniflow_init(struct miniflow *dst, const struct > flow *src) > n = 0; > dst->map = 0; > > - for (i = 0; i < FLOW_U32S; i++) { > - if (src_u32[i]) { > + for (i = 0; i < FLOW_U64S; i++) { > + if (src_u64[i]) { > dst->map |= UINT64_C(1) << i; > n++; > } > @@ -1900,7 +1971,7 @@ void > miniflow_clone(struct miniflow *dst, const struct miniflow *src) > { > int size = MINIFLOW_VALUES_SIZE(miniflow_n_values(src)); > - uint32_t *values; > + uint64_t *values; > > dst->map = src->map; > if (size <= sizeof dst->inline_values) { > @@ -1971,21 +2042,12 @@ miniflow_expand(const struct miniflow *src, struct > flow *dst) > flow_union_with_miniflow(dst, src); > } > > -/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if > 'flow' > - * were expanded into a "struct flow". */ > -static uint32_t > -miniflow_get(const struct miniflow *flow, unsigned int u32_ofs) > -{ > - return flow->map & (UINT64_C(1) << u32_ofs) > - ? miniflow_get__(flow, u32_ofs) : 0; > -} > - > /* Returns true if 'a' and 'b' are the equal miniflow, false otherwise. */ > bool > miniflow_equal(const struct miniflow *a, const struct miniflow *b) > { > - const uint32_t *ap = miniflow_get_u32_values(a); > - const uint32_t *bp = miniflow_get_u32_values(b); > + const uint64_t *ap = miniflow_get_values(a); > + const uint64_t *bp = miniflow_get_values(b); > > if (OVS_LIKELY(a->map == b->map)) { > int count = miniflow_n_values(a); > @@ -2012,7 +2074,7 @@ bool > miniflow_equal_in_minimask(const struct miniflow *a, const struct > miniflow *b, > const struct minimask *mask) > { > - const uint32_t *p = miniflow_get_u32_values(&mask->masks); > + const uint64_t *p = miniflow_get_values(&mask->masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, mask->masks.map) { > @@ -2030,12 +2092,12 @@ bool > miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct > flow *b, > const struct minimask *mask) > { > - const uint32_t *b_u32 = (const uint32_t *) b; > - const uint32_t *p = miniflow_get_u32_values(&mask->masks); > + const uint64_t *b_u64 = (const uint64_t *) b; > + const uint64_t *p = miniflow_get_values(&mask->masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, mask->masks.map) { > - if ((miniflow_get(a, idx) ^ b_u32[idx]) & *p++) { > + if ((miniflow_get(a, idx) ^ b_u64[idx]) & *p++) { > return false; > } > } > @@ -2070,15 +2132,15 @@ minimask_move(struct minimask *dst, struct > minimask *src) > > /* Initializes 'dst_' as the bit-wise "and" of 'a_' and 'b_'. > * > - * The caller must provide room for FLOW_U32S "uint32_t"s in 'storage', > for use > + * The caller must provide room for FLOW_U64S "uint64_t"s in 'storage', > for use > * by 'dst_'. The caller must *not* free 'dst_' with minimask_destroy(). > */ > void > minimask_combine(struct minimask *dst_, > const struct minimask *a_, const struct minimask *b_, > - uint32_t storage[FLOW_U32S]) > + uint64_t storage[FLOW_U64S]) > { > struct miniflow *dst = &dst_->masks; > - uint32_t *dst_values = storage; > + uint64_t *dst_values = storage; > const struct miniflow *a = &a_->masks; > const struct miniflow *b = &b_->masks; > int idx; > @@ -2089,7 +2151,7 @@ minimask_combine(struct minimask *dst_, > dst->map = 0; > MAP_FOR_EACH_INDEX(idx, a->map & b->map) { > /* Both 'a' and 'b' have non-zero data at 'idx'. */ > - uint32_t mask = miniflow_get__(a, idx) & miniflow_get__(b, idx); > + uint64_t mask = miniflow_get__(a, idx) & miniflow_get__(b, idx); > > if (mask) { > dst->map |= UINT64_C(1) << idx; > @@ -2113,14 +2175,6 @@ minimask_expand(const struct minimask *mask, struct > flow_wildcards *wc) > miniflow_expand(&mask->masks, &wc->masks); > } > > -/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if > 'mask' > - * were expanded into a "struct flow_wildcards". */ > -uint32_t > -minimask_get(const struct minimask *mask, unsigned int u32_ofs) > -{ > - return miniflow_get(&mask->masks, u32_ofs); > -} > - > /* Returns true if 'a' and 'b' are the same flow mask, false otherwise. > * Minimasks may not have zero data values, so for the minimasks to be the > * same, they need to have the same map and the same data values. */ > @@ -2128,8 +2182,8 @@ bool > minimask_equal(const struct minimask *a, const struct minimask *b) > { > return a->masks.map == b->masks.map && > - !memcmp(miniflow_get_u32_values(&a->masks), > - miniflow_get_u32_values(&b->masks), > + !memcmp(miniflow_get_values(&a->masks), > + miniflow_get_values(&b->masks), > count_1bits(a->masks.map) * sizeof > *a->masks.inline_values); > } > > @@ -2138,18 +2192,18 @@ minimask_equal(const struct minimask *a, const > struct minimask *b) > bool > minimask_has_extra(const struct minimask *a, const struct minimask *b) > { > - const uint32_t *ap = miniflow_get_u32_values(&a->masks); > - const uint32_t *bp = miniflow_get_u32_values(&b->masks); > + const uint64_t *ap = miniflow_get_values(&a->masks); > + const uint64_t *bp = miniflow_get_values(&b->masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, b->masks.map) { > - uint32_t b_u32 = *bp++; > + uint64_t b_u64 = *bp++; > > - /* 'b_u32' is non-zero, check if the data in 'a' is either zero > - * or misses some of the bits in 'b_u32'. */ > + /* 'b_u64' is non-zero, check if the data in 'a' is either zero > + * or misses some of the bits in 'b_u64'. */ > if (!(a->masks.map & (UINT64_C(1) << idx)) > - || ((miniflow_values_get__(ap, a->masks.map, idx) & b_u32) > - != b_u32)) { > + || ((miniflow_values_get__(ap, a->masks.map, idx) & b_u64) > + != b_u64)) { > return true; /* 'a' wildcards some bits 'b' doesn't. */ > } > } > diff --git a/lib/flow.h b/lib/flow.h > index 8e56d05..17b9b86 100644 > --- a/lib/flow.h > +++ b/lib/flow.h > @@ -38,11 +38,12 @@ struct pkt_metadata; > /* This sequence number should be incremented whenever anything involving > flows > * or the wildcarding of flows changes. This will cause build assertion > * failures in places which likely need to be updated. */ > -#define FLOW_WC_SEQ 28 > +#define FLOW_WC_SEQ 29 > > /* Number of Open vSwitch extension 32-bit registers. */ > #define FLOW_N_REGS 8 > BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS); > +BUILD_ASSERT_DECL(FLOW_N_REGS % 2 == 0); /* Even. */ > > /* Number of OpenFlow 1.5+ 64-bit registers. > * > @@ -100,85 +101,82 @@ struct flow { > uint32_t regs[FLOW_N_REGS]; /* Registers. */ > uint32_t skb_priority; /* Packet priority for QoS. */ > uint32_t pkt_mark; /* Packet mark. */ > - uint32_t recirc_id; /* Must be exact match. */ > + uint32_t dp_hash; /* Datapath computed hash value. The exact > + * computation is opaque to the user > space. */ > union flow_in_port in_port; /* Input port.*/ > + uint32_t recirc_id; /* Must be exact match. */ > ofp_port_t actset_output; /* Output port in action set. */ > - ovs_be16 pad1; /* Pad to 32 bits. */ > + ovs_be16 pad1; /* Pad to 64 bits. */ > > - /* L2, Order the same as in the Ethernet header! */ > + /* L2, Order the same as in the Ethernet header! (64-bit aligned) */ > uint8_t dl_dst[ETH_ADDR_LEN]; /* Ethernet destination address. */ > uint8_t dl_src[ETH_ADDR_LEN]; /* Ethernet source address. */ > ovs_be16 dl_type; /* Ethernet frame type. */ > ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise > 0. */ > - ovs_be32 mpls_lse[FLOW_MAX_MPLS_LABELS]; /* MPLS label stack entry. */ > - > - /* L3 */ > + ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label > stack > + (with > padding). */ > + /* L3 (64-bit aligned) */ > + ovs_be32 nw_src; /* IPv4 source address. */ > + ovs_be32 nw_dst; /* IPv4 destination address. */ > struct in6_addr ipv6_src; /* IPv6 source address. */ > struct in6_addr ipv6_dst; /* IPv6 destination address. */ > ovs_be32 ipv6_label; /* IPv6 flow label. */ > - ovs_be32 nw_src; /* IPv4 source address. */ > - ovs_be32 nw_dst; /* IPv4 destination address. */ > uint8_t nw_frag; /* FLOW_FRAG_* flags. */ > uint8_t nw_tos; /* IP ToS (including DSCP and ECN). */ > uint8_t nw_ttl; /* IP TTL/Hop Limit. */ > uint8_t nw_proto; /* IP protocol or low 8 bits of ARP > opcode. */ > + struct in6_addr nd_target; /* IPv6 neighbor discovery (ND) target. */ > uint8_t arp_sha[ETH_ADDR_LEN]; /* ARP/ND source hardware address. */ > uint8_t arp_tha[ETH_ADDR_LEN]; /* ARP/ND target hardware address. */ > - struct in6_addr nd_target; /* IPv6 neighbor discovery (ND) target. */ > ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching > L4. */ > - ovs_be16 pad2; /* Pad to 32 bits. */ > + ovs_be16 pad2; /* Pad to 64 bits. */ > > - /* L4 */ > + /* L4 (64-bit aligned) */ > ovs_be16 tp_src; /* TCP/UDP/SCTP source port. */ > ovs_be16 tp_dst; /* TCP/UDP/SCTP destination port. */ > - ovs_be32 igmp_group_ip4; /* IGMP group IPv4 address */ > - uint32_t dp_hash; /* Datapath computed hash value. The exact > - * computation is opaque to the user > space. > + ovs_be32 igmp_group_ip4; /* IGMP group IPv4 address. > * Keep last for BUILD_ASSERT_DECL below. > */ > }; > -BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0); > +BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0); > > -#define FLOW_U32S (sizeof(struct flow) / 4) > +#define FLOW_U64S (sizeof(struct flow) / sizeof(uint64_t)) > > /* Some flow fields are mutually exclusive or only appear within the flow > * pipeline. IPv6 headers are bigger than IPv4 and MPLS, and IPv6 ND > packets > * are bigger than TCP,UDP and IGMP packets. */ > -#define FLOW_MAX_PACKET_U32S (FLOW_U32S > \ > - /* Unused in datapath */ - FLOW_U32_SIZE(regs) > \ > - - FLOW_U32_SIZE(metadata) > \ > - - FLOW_U32_SIZE(actset_output) > \ > - /* L2.5/3 */ - FLOW_U32_SIZE(nw_src) > \ > - - FLOW_U32_SIZE(nw_dst) > \ > - - FLOW_U32_SIZE(mpls_lse) > \ > - /* L4 */ - FLOW_U32_SIZE(tcp_flags) /* incl. pad. */ > \ > - - FLOW_U32_SIZE(igmp_group_ip4) > \ > +#define FLOW_MAX_PACKET_U64S (FLOW_U64S > \ > + /* Unused in datapath */ - FLOW_U64_SIZE(regs) > \ > + - FLOW_U64_SIZE(metadata) > \ > + /* L2.5/3 */ - FLOW_U64_SIZE(nw_src) /* incl. nw_dst */ > \ > + - FLOW_U64_SIZE(mpls_lse) > \ > + /* L4 */ - FLOW_U64_SIZE(tp_src) > \ > ) > > /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ > -BUILD_ASSERT_DECL(offsetof(struct flow, dp_hash) + sizeof(uint32_t) > - == sizeof(struct flow_tnl) + 180 > - && FLOW_WC_SEQ == 28); > +BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t) > + == sizeof(struct flow_tnl) + 184 > + && FLOW_WC_SEQ == 29); > > /* Incremental points at which flow classification may be performed in > * segments. > * This is located here since this is dependent on the structure of the > * struct flow defined above: > - * Each offset must be on a distinct, successive U32 boundary strictly > + * Each offset must be on a distinct, successive U64 boundary strictly > * within the struct flow. */ > enum { > FLOW_SEGMENT_1_ENDS_AT = offsetof(struct flow, dl_dst), > - FLOW_SEGMENT_2_ENDS_AT = offsetof(struct flow, ipv6_src), > + FLOW_SEGMENT_2_ENDS_AT = offsetof(struct flow, nw_src), > FLOW_SEGMENT_3_ENDS_AT = offsetof(struct flow, tp_src), > }; > -BUILD_ASSERT_DECL(FLOW_SEGMENT_1_ENDS_AT % 4 == 0); > -BUILD_ASSERT_DECL(FLOW_SEGMENT_2_ENDS_AT % 4 == 0); > -BUILD_ASSERT_DECL(FLOW_SEGMENT_3_ENDS_AT % 4 == 0); > +BUILD_ASSERT_DECL(FLOW_SEGMENT_1_ENDS_AT % sizeof(uint64_t) == 0); > +BUILD_ASSERT_DECL(FLOW_SEGMENT_2_ENDS_AT % sizeof(uint64_t) == 0); > +BUILD_ASSERT_DECL(FLOW_SEGMENT_3_ENDS_AT % sizeof(uint64_t) == 0); > BUILD_ASSERT_DECL( 0 < FLOW_SEGMENT_1_ENDS_AT); > BUILD_ASSERT_DECL(FLOW_SEGMENT_1_ENDS_AT < FLOW_SEGMENT_2_ENDS_AT); > BUILD_ASSERT_DECL(FLOW_SEGMENT_2_ENDS_AT < FLOW_SEGMENT_3_ENDS_AT); > BUILD_ASSERT_DECL(FLOW_SEGMENT_3_ENDS_AT < sizeof(struct flow)); > > -extern const uint8_t flow_segment_u32s[]; > +extern const uint8_t flow_segment_u64s[]; > > /* Represents the metadata fields of struct flow. */ > struct flow_metadata { > @@ -261,7 +259,8 @@ flow_equal(const struct flow *a, const struct flow *b) > static inline size_t > flow_hash(const struct flow *flow, uint32_t basis) > { > - return hash_words((const uint32_t *) flow, sizeof *flow / 4, basis); > + return hash_words64((const uint64_t *)flow, > + sizeof *flow / sizeof(uint64_t), basis); > } > > static inline uint16_t > @@ -373,11 +372,11 @@ bool flow_equal_except(const struct flow *a, const > struct flow *b, > > /* Compressed flow. */ > > -/* Number of 32-bit words present in struct miniflow. */ > -#define MINI_N_INLINE 8 > +/* Number of 64-bit words present in struct miniflow. */ > +#define MINI_N_INLINE 4 > > -/* Maximum number of 32-bit words supported. */ > -BUILD_ASSERT_DECL(FLOW_U32S <= 63); > +/* Maximum number of 64-bit words supported. */ > +BUILD_ASSERT_DECL(FLOW_U64S <= 63); > > /* A sparse representation of a "struct flow". > * > @@ -386,8 +385,8 @@ BUILD_ASSERT_DECL(FLOW_U32S <= 63); > * saves time when the goal is to iterate over only the nonzero parts of > the > * struct. > * > - * The 'map' member holds one bit for each uint32_t in a "struct flow". > Each > - * 0-bit indicates that the corresponding uint32_t is zero, each 1-bit > that it > + * The 'map' member holds one bit for each uint64_t in a "struct flow". > Each > + * 0-bit indicates that the corresponding uint64_t is zero, each 1-bit > that it > * *may* be nonzero (see below how this applies to minimasks). > * > * The 'values_inline' boolean member indicates that the values are at > @@ -400,7 +399,7 @@ BUILD_ASSERT_DECL(FLOW_U32S <= 63); > * MINI_N_INLINE is the default number of inline words. When a miniflow > is > * dynamically allocated the actual amount of inline storage may be > different. > * In that case 'inline_values' contains storage at least for the number > - * of words indicated by 'map' (one uint32_t for each 1-bit in the map). > + * of words indicated by 'map' (one uint64_t for each 1-bit in the map). > * > * Elements in values array are allowed to be zero. This is useful for > "struct > * minimatch", for which ensuring that the miniflow and minimask members > have > @@ -412,43 +411,33 @@ struct miniflow { > uint64_t map:63; > uint64_t values_inline:1; > union { > - uint32_t *offline_values; > - uint32_t inline_values[MINI_N_INLINE]; /* Minimum inline size. */ > + uint64_t *offline_values; > + uint64_t inline_values[MINI_N_INLINE]; /* Minimum inline size. */ > }; > }; > BUILD_ASSERT_DECL(sizeof(struct miniflow) > - == sizeof(uint64_t) + MINI_N_INLINE * sizeof(uint32_t)); > + == sizeof(uint64_t) + MINI_N_INLINE * sizeof(uint64_t)); > > -#define MINIFLOW_VALUES_SIZE(COUNT) ((COUNT) * sizeof(uint32_t)) > +#define MINIFLOW_VALUES_SIZE(COUNT) ((COUNT) * sizeof(uint64_t)) > > -static inline uint32_t *miniflow_values(struct miniflow *mf) > +static inline uint64_t *miniflow_values(struct miniflow *mf) > { > return OVS_LIKELY(mf->values_inline) > ? mf->inline_values : mf->offline_values; > } > > -static inline const uint32_t *miniflow_get_values(const struct miniflow > *mf) > +static inline const uint64_t *miniflow_get_values(const struct miniflow > *mf) > { > return OVS_LIKELY(mf->values_inline) > ? mf->inline_values : mf->offline_values; > } > > -static inline const uint32_t *miniflow_get_u32_values(const struct > miniflow *mf) > -{ > - return miniflow_get_values(mf); > -} > - > -static inline const ovs_be32 *miniflow_get_be32_values(const struct > miniflow *mf) > -{ > - return (OVS_FORCE const ovs_be32 *)miniflow_get_values(mf); > -} > - > /* This is useful for initializing a miniflow for a miniflow_extract() > call. */ > static inline void miniflow_initialize(struct miniflow *mf, > - uint32_t buf[FLOW_U32S]) > + uint64_t buf[FLOW_U64S]) > { > mf->map = 0; > - mf->values_inline = (buf == (uint32_t *)(mf + 1)); > + mf->values_inline = (buf == (uint64_t *)(mf + 1)); > if (!mf->values_inline) { > mf->offline_values = buf; > } > @@ -457,7 +446,7 @@ static inline void miniflow_initialize(struct miniflow > *mf, > struct pkt_metadata; > > /* The 'dst->values' must be initialized with a buffer with space for > - * FLOW_U32S. 'dst->map' is ignored on input and set on output to > + * FLOW_U64S. 'dst->map' is ignored on input and set on output to > * indicate which fields were extracted. */ > void miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *, > struct miniflow *dst); > @@ -472,53 +461,53 @@ void miniflow_destroy(struct miniflow *); > > void miniflow_expand(const struct miniflow *, struct flow *); > > -static inline uint32_t flow_u32_value(const struct flow *flow, size_t > index) > +static inline uint64_t flow_u64_value(const struct flow *flow, size_t > index) > { > - return ((uint32_t *)(flow))[index]; > + return ((uint64_t *)(flow))[index]; > } > > -static inline uint32_t *flow_u32_lvalue(struct flow *flow, size_t index) > +static inline uint64_t *flow_u64_lvalue(struct flow *flow, size_t index) > { > - return &((uint32_t *)(flow))[index]; > + return &((uint64_t *)(flow))[index]; > } > > static inline bool > -flow_get_next_in_map(const struct flow *flow, uint64_t map, uint32_t > *value) > +flow_get_next_in_map(const struct flow *flow, uint64_t map, uint64_t > *value) > { > if (map) { > - *value = flow_u32_value(flow, raw_ctz(map)); > + *value = flow_u64_value(flow, raw_ctz(map)); > return true; > } > return false; > } > > -/* Iterate through all flow u32 values specified by 'MAP'. */ > +/* Iterate through all flow u64 values specified by 'MAP'. */ > #define FLOW_FOR_EACH_IN_MAP(VALUE, FLOW, MAP) \ > for (uint64_t map__ = (MAP); \ > flow_get_next_in_map(FLOW, map__, &(VALUE)); \ > map__ = zero_rightmost_1bit(map__)) > > -/* Iterate through all struct flow u32 indices specified by 'MAP'. */ > -#define MAP_FOR_EACH_INDEX(U32IDX, MAP) \ > +/* Iterate through all struct flow u64 indices specified by 'MAP'. */ > +#define MAP_FOR_EACH_INDEX(U64IDX, MAP) \ > for (uint64_t map__ = (MAP); \ > - map__ && ((U32IDX) = raw_ctz(map__), true); \ > + map__ && ((U64IDX) = raw_ctz(map__), true); \ > map__ = zero_rightmost_1bit(map__)) > > -#define FLOW_U32_SIZE(FIELD) \ > - DIV_ROUND_UP(sizeof(((struct flow *)0)->FIELD), sizeof(uint32_t)) > +#define FLOW_U64_SIZE(FIELD) \ > + DIV_ROUND_UP(sizeof(((struct flow *)0)->FIELD), sizeof(uint64_t)) > > #define MINIFLOW_MAP(FIELD) \ > - (((UINT64_C(1) << FLOW_U32_SIZE(FIELD)) - 1) \ > - << (offsetof(struct flow, FIELD) / 4)) > + (((UINT64_C(1) << FLOW_U64_SIZE(FIELD)) - 1) \ > + << (offsetof(struct flow, FIELD) / sizeof(uint64_t))) > > struct mf_for_each_in_map_aux { > - const uint32_t *values; > + const uint64_t *values; > uint64_t fmap; > uint64_t map; > }; > > static inline bool > -mf_get_next_in_map(struct mf_for_each_in_map_aux *aux, uint32_t *value) > +mf_get_next_in_map(struct mf_for_each_in_map_aux *aux, uint64_t *value) > { > if (aux->map) { > uint64_t rm1bit = rightmost_1bit(aux->map); > @@ -544,50 +533,60 @@ mf_get_next_in_map(struct mf_for_each_in_map_aux > *aux, uint32_t *value) > } > } > > -/* Iterate through all miniflow u32 values specified by 'MAP'. */ > +/* Iterate through all miniflow u64 values specified by 'MAP'. */ > #define MINIFLOW_FOR_EACH_IN_MAP(VALUE, FLOW, MAP) \ > for (struct mf_for_each_in_map_aux aux__ \ > - = { miniflow_get_u32_values(FLOW), (FLOW)->map, MAP }; \ > + = { miniflow_get_values(FLOW), (FLOW)->map, MAP }; \ > mf_get_next_in_map(&aux__, &(VALUE)); \ > ) > > -/* This can be used when it is known that 'u32_idx' is set in 'map'. */ > -static inline uint32_t > -miniflow_values_get__(const uint32_t *values, uint64_t map, int u32_idx) > +/* This can be used when it is known that 'u64_idx' is set in 'map'. */ > +static inline uint64_t > +miniflow_values_get__(const uint64_t *values, uint64_t map, int u64_idx) > { > - return values[count_1bits(map & ((UINT64_C(1) << u32_idx) - 1))]; > + return values[count_1bits(map & ((UINT64_C(1) << u64_idx) - 1))]; > } > > -/* This can be used when it is known that 'u32_idx' is set in > +/* This can be used when it is known that 'u64_idx' is set in > * the map of 'mf'. */ > -static inline uint32_t > -miniflow_get__(const struct miniflow *mf, int u32_idx) > +static inline uint64_t > +miniflow_get__(const struct miniflow *mf, int u64_idx) > { > - return miniflow_values_get__(miniflow_get_u32_values(mf), mf->map, > - u32_idx); > + return miniflow_values_get__(miniflow_get_values(mf), mf->map, > u64_idx); > } > > -/* Get the value of 'FIELD' of an up to 4 byte wide integer type 'TYPE' of > +/* Get the value of 'FIELD' of an up to 8 byte wide integer type 'TYPE' of > * a miniflow. */ > #define MINIFLOW_GET_TYPE(MF, TYPE, OFS) \ > - (((MF)->map & (UINT64_C(1) << (OFS) / 4)) \ > + (((MF)->map & (UINT64_C(1) << (OFS) / sizeof(uint64_t))) \ > ? ((OVS_FORCE const TYPE *) \ > - (miniflow_get_u32_values(MF) \ > - + count_1bits((MF)->map & ((UINT64_C(1) << (OFS) / 4) - 1)))) \ > - [(OFS) % 4 / sizeof(TYPE)] \ > + (miniflow_get_values(MF) \ > + + count_1bits((MF)->map & \ > + ((UINT64_C(1) << (OFS) / sizeof(uint64_t)) - 1)))) > \ > + [(OFS) % sizeof(uint64_t) / sizeof(TYPE)] \ > : 0) \ > > -#define MINIFLOW_GET_U8(FLOW, FIELD) \ > +#define MINIFLOW_GET_U8(FLOW, FIELD) \ > MINIFLOW_GET_TYPE(FLOW, uint8_t, offsetof(struct flow, FIELD)) > -#define MINIFLOW_GET_U16(FLOW, FIELD) \ > +#define MINIFLOW_GET_U16(FLOW, FIELD) \ > MINIFLOW_GET_TYPE(FLOW, uint16_t, offsetof(struct flow, FIELD)) > -#define MINIFLOW_GET_BE16(FLOW, FIELD) > \ > +#define MINIFLOW_GET_BE16(FLOW, FIELD) \ > MINIFLOW_GET_TYPE(FLOW, ovs_be16, offsetof(struct flow, FIELD)) > -#define MINIFLOW_GET_U32(FLOW, FIELD) \ > +#define MINIFLOW_GET_U32(FLOW, FIELD) \ > MINIFLOW_GET_TYPE(FLOW, uint32_t, offsetof(struct flow, FIELD)) > -#define MINIFLOW_GET_BE32(FLOW, FIELD) > \ > +#define MINIFLOW_GET_BE32(FLOW, FIELD) \ > MINIFLOW_GET_TYPE(FLOW, ovs_be32, offsetof(struct flow, FIELD)) > - > +#define MINIFLOW_GET_U64(FLOW, FIELD) \ > + MINIFLOW_GET_TYPE(FLOW, uint64_t, offsetof(struct flow, FIELD)) > +#define MINIFLOW_GET_BE64(FLOW, FIELD) \ > + MINIFLOW_GET_TYPE(FLOW, ovs_be64, offsetof(struct flow, FIELD)) > + > +static inline uint64_t miniflow_get(const struct miniflow *, > + unsigned int u64_ofs); > +static inline uint32_t miniflow_get_u32(const struct miniflow *, > + unsigned int u32_ofs); > +static inline ovs_be32 miniflow_get_be32(const struct miniflow *, > + unsigned int be32_ofs); > static inline uint16_t miniflow_get_vid(const struct miniflow *); > static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *); > static inline ovs_be64 miniflow_get_metadata(const struct miniflow *); > @@ -619,12 +618,15 @@ void minimask_clone(struct minimask *, const struct > minimask *); > void minimask_move(struct minimask *dst, struct minimask *src); > void minimask_combine(struct minimask *dst, > const struct minimask *a, const struct minimask *b, > - uint32_t storage[FLOW_U32S]); > + uint64_t storage[FLOW_U64S]); > void minimask_destroy(struct minimask *); > > void minimask_expand(const struct minimask *, struct flow_wildcards *); > > -uint32_t minimask_get(const struct minimask *, unsigned int u32_ofs); > +static inline uint32_t minimask_get_u32(const struct minimask *, > + unsigned int u32_ofs); > +static inline ovs_be32 minimask_get_be32(const struct minimask *, > + unsigned int be32_ofs); > static inline uint16_t minimask_get_vid_mask(const struct minimask *); > static inline ovs_be64 minimask_get_metadata_mask(const struct minimask > *); > > @@ -643,6 +645,33 @@ minimask_is_catchall(const struct minimask *mask) > return mask->masks.map == 0; > } > > +/* Returns the uint64_t that would be at byte offset '8 * u64_ofs' if > 'flow' > + * were expanded into a "struct flow". */ > +static inline uint64_t miniflow_get(const struct miniflow *flow, > + unsigned int u64_ofs) > +{ > + return flow->map & (UINT64_C(1) << u64_ofs) > + ? miniflow_get__(flow, u64_ofs) : 0; > +} > + > +static inline uint32_t miniflow_get_u32(const struct miniflow *flow, > + unsigned int u32_ofs) > +{ > + uint64_t value = miniflow_get(flow, u32_ofs / 2); > + > +#if WORDS_BIGENDIAN > + return (u32_ofs & 1) ? value : value >> 32; > +#else > + return (u32_ofs & 1) ? value >> 32 : value; > +#endif > +} > + > +static inline ovs_be32 miniflow_get_be32(const struct miniflow *flow, > + unsigned int be32_ofs) > +{ > + return (OVS_FORCE ovs_be32)miniflow_get_u32(flow, be32_ofs); > +} > + > /* Returns the VID within the vlan_tci member of the "struct flow" > represented > * by 'flow'. */ > static inline uint16_t > @@ -652,6 +681,20 @@ miniflow_get_vid(const struct miniflow *flow) > return vlan_tci_to_vid(tci); > } > > +/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if > 'mask' > + * were expanded into a "struct flow_wildcards". */ > +static inline uint32_t > +minimask_get_u32(const struct minimask *mask, unsigned int u32_ofs) > +{ > + return miniflow_get_u32(&mask->masks, u32_ofs); > +} > + > +static inline ovs_be32 > +minimask_get_be32(const struct minimask *mask, unsigned int be32_ofs) > +{ > + return (OVS_FORCE ovs_be32)minimask_get_u32(mask, be32_ofs); > +} > + > /* Returns the VID mask within the vlan_tci member of the "struct > * flow_wildcards" represented by 'mask'. */ > static inline uint16_t > @@ -671,20 +714,7 @@ miniflow_get_tcp_flags(const struct miniflow *flow) > static inline ovs_be64 > miniflow_get_metadata(const struct miniflow *flow) > { > - union { > - ovs_be64 be64; > - struct { > - ovs_be32 hi; > - ovs_be32 lo; > - }; > - } value; > - > - enum { MD_OFS = offsetof(struct flow, metadata) }; > - BUILD_ASSERT_DECL(MD_OFS % sizeof(uint32_t) == 0); > - value.hi = MINIFLOW_GET_TYPE(flow, ovs_be32, MD_OFS); > - value.lo = MINIFLOW_GET_TYPE(flow, ovs_be32, MD_OFS + 4); > - > - return value.be64; > + return MINIFLOW_GET_BE64(flow, metadata); > } > > /* Returns the mask for the OpenFlow 1.1+ "metadata" field in 'mask'. > @@ -696,7 +726,7 @@ miniflow_get_metadata(const struct miniflow *flow) > static inline ovs_be64 > minimask_get_metadata_mask(const struct minimask *mask) > { > - return miniflow_get_metadata(&mask->masks); > + return MINIFLOW_GET_BE64(&mask->masks, metadata); > } > > /* Perform a bitwise OR of miniflow 'src' flow data with the equivalent > @@ -704,12 +734,12 @@ minimask_get_metadata_mask(const struct minimask > *mask) > static inline void > flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) > { > - uint32_t *dst_u32 = (uint32_t *) dst; > - const uint32_t *p = miniflow_get_u32_values(src); > + uint64_t *dst_u64 = (uint64_t *) dst; > + const uint64_t *p = miniflow_get_values(src); > int idx; > > MAP_FOR_EACH_INDEX(idx, src->map) { > - dst_u32[idx] |= *p++; > + dst_u64[idx] |= *p++; > } > } > > diff --git a/lib/match.c b/lib/match.c > index 480b972..b5bea5d 100644 > --- a/lib/match.c > +++ b/lib/match.c > @@ -870,7 +870,7 @@ match_format(const struct match *match, struct ds *s, > int priority) > > int i; > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > if (priority != OFP_DEFAULT_PRIORITY) { > ds_put_format(s, "priority=%d,", priority); > @@ -1200,13 +1200,13 @@ bool > minimatch_matches_flow(const struct minimatch *match, > const struct flow *target) > { > - const uint32_t *target_u32 = (const uint32_t *) target; > - const uint32_t *flowp = miniflow_get_u32_values(&match->flow); > - const uint32_t *maskp = miniflow_get_u32_values(&match->mask.masks); > + const uint64_t *target_u64 = (const uint64_t *) target; > + const uint64_t *flowp = miniflow_get_values(&match->flow); > + const uint64_t *maskp = miniflow_get_values(&match->mask.masks); > int idx; > > MAP_FOR_EACH_INDEX(idx, match->flow.map) { > - if ((*flowp++ ^ target_u32[idx]) & *maskp++) { > + if ((*flowp++ ^ target_u64[idx]) & *maskp++) { > return false; > } > } > diff --git a/lib/nx-match.c b/lib/nx-match.c > index 2ad3cf2..1f72a84 100644 > --- a/lib/nx-match.c > +++ b/lib/nx-match.c > @@ -817,7 +817,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, > const struct match *match, > int match_len; > int i; > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > /* Metadata. */ > if (match->wc.masks.dp_hash) { > diff --git a/lib/odp-util.h b/lib/odp-util.h > index 9c990cd..b361795 100644 > --- a/lib/odp-util.h > +++ b/lib/odp-util.h > @@ -133,7 +133,7 @@ void odp_portno_names_destroy(struct hmap > *portno_names); > * add another field and forget to adjust this value. > */ > #define ODPUTIL_FLOW_KEY_BYTES 512 > -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > /* A buffer with sufficient size and alignment to hold an > nlattr-formatted flow > * key. An array of "struct nlattr" might not, in theory, be sufficiently > diff --git a/lib/ofp-util.c b/lib/ofp-util.c > index 986659e..c4daec6 100644 > --- a/lib/ofp-util.c > +++ b/lib/ofp-util.c > @@ -186,7 +186,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) > void > ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) > { > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > > /* Initialize most of wc. */ > flow_wildcards_init_catchall(wc); > diff --git a/lib/tnl-ports.c b/lib/tnl-ports.c > index 9832ef4..7ab25eb 100644 > --- a/lib/tnl-ports.c > +++ b/lib/tnl-ports.c > @@ -188,6 +188,6 @@ tnl_port_show(struct unixctl_conn *conn, int argc > OVS_UNUSED, > void > tnl_port_map_init(void) > { > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > unixctl_command_register("tnl/ports/show", "", 0, 0, tnl_port_show, > NULL); > } > diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c > index 89de528..bc59ffb 100644 > --- a/ofproto/ofproto-dpif-upcall.c > +++ b/ofproto/ofproto-dpif-upcall.c > @@ -1551,7 +1551,7 @@ revalidate_ukey(struct udpif *udpif, struct > udpif_key *ukey, > struct dpif_flow_stats push; > struct ofpbuf xout_actions; > struct flow flow, dp_mask; > - uint32_t *dp32, *xout32; > + uint64_t *dp64, *xout64; > ofp_port_t ofp_in_port; > struct xlate_in xin; > long long int last_used; > @@ -1651,10 +1651,10 @@ revalidate_ukey(struct udpif *udpif, struct > udpif_key *ukey, > * mask in the kernel is more specific i.e. less wildcarded, than what > * we've calculated here. This guarantees we don't catch any packets > we > * shouldn't with the megaflow. */ > - dp32 = (uint32_t *) &dp_mask; > - xout32 = (uint32_t *) &xout.wc.masks; > - for (i = 0; i < FLOW_U32S; i++) { > - if ((dp32[i] | xout32[i]) != dp32[i]) { > + dp64 = (uint64_t *) &dp_mask; > + xout64 = (uint64_t *) &xout.wc.masks; > + for (i = 0; i < FLOW_U64S; i++) { > + if ((dp64[i] | xout64[i]) != dp64[i]) { > goto exit; > } > } > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index c1327a6..50ed418 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -2611,7 +2611,7 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > > /* If 'struct flow' gets additional metadata, we'll need to zero it > out > * before traversing a patch port. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); > memset(&flow_tnl, 0, sizeof flow_tnl); > > if (!xport) { > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > index 75f0b54..cbf8434 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -6682,7 +6682,7 @@ static void > oftable_init(struct oftable *table) > { > memset(table, 0, sizeof *table); > - classifier_init(&table->cls, flow_segment_u32s); > + classifier_init(&table->cls, flow_segment_u64s); > table->max_flows = UINT_MAX; > atomic_init(&table->miss_config, OFPUTIL_TABLE_MISS_DEFAULT); > > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index baa942f..064253e 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -5389,7 +5389,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 > 'in_port(1),eth(src=50:54:00:00:00: > sleep 1 > AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], > [dnl > recirc_id=0,ipv6,in_port=1,ipv6_src=2001:db8:3c4d:1:2:3:4:5,nw_frag=no, > actions: <del> > -recirc_id=0,ipv6,in_port=1,ipv6_src=2001:db8:3c4d:5:4:3:2:1/ffff:ffff:0:4::,nw_frag=no, > actions: <del> > +recirc_id=0,ipv6,in_port=1,ipv6_src=2001:db8:3c4d:5:4:3:2:1/0:0:0:4::,nw_frag=no, > actions: <del> > ]) > OVS_VSWITCHD_STOP > AT_CLEANUP > diff --git a/tests/test-classifier.c b/tests/test-classifier.c > index e4eb0f4..a15a612 100644 > --- a/tests/test-classifier.c > +++ b/tests/test-classifier.c > @@ -700,7 +700,7 @@ test_empty(int argc OVS_UNUSED, char *argv[] > OVS_UNUSED) > struct classifier cls; > struct tcls tcls; > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > assert(classifier_is_empty(&cls)); > @@ -731,7 +731,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] > OVS_UNUSED) > rule = make_rule(wc_fields, > hash_bytes(&wc_fields, sizeof wc_fields, 0), 0); > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > > @@ -769,7 +769,7 @@ test_rule_replacement(int argc OVS_UNUSED, char > *argv[] OVS_UNUSED) > rule2->aux += 5; > rule2->aux += 5; > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > tcls_insert(&tcls, rule1); > @@ -884,7 +884,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char > *argv[] OVS_UNUSED) > pri_rules[i] = -1; > } > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > > @@ -986,7 +986,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char > *argv[] OVS_UNUSED) > value_mask = ~wcf & ((1u << CLS_N_FIELDS) - 1); > } while ((1 << count_ones(value_mask)) < N_RULES); > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > > @@ -1048,7 +1048,7 @@ test_many_rules_in_n_tables(int n_tables) > } > shuffle(priorities, ARRAY_SIZE(priorities)); > > - classifier_init(&cls, flow_segment_u32s); > + classifier_init(&cls, flow_segment_u64s); > set_prefix_fields(&cls); > tcls_init(&tcls); > > @@ -1122,6 +1122,8 @@ choose(unsigned int n, unsigned int *idxp) > } > } > > +#define FLOW_U32S (FLOW_U64S * 2) > + > static bool > init_consecutive_values(int n_consecutive, struct flow *flow, > unsigned int *idxp) > @@ -1259,7 +1261,7 @@ test_miniflow(int argc OVS_UNUSED, char *argv[] > OVS_UNUSED) > > random_set_seed(0xb3faca38); > for (idx = 0; next_random_flow(&flow, idx); idx++) { > - const uint32_t *flow_u32 = (const uint32_t *) &flow; > + const uint64_t *flow_u64 = (const uint64_t *) &flow; > struct miniflow miniflow, miniflow2, miniflow3; > struct flow flow2, flow3; > struct flow_wildcards mask; > @@ -1271,9 +1273,8 @@ test_miniflow(int argc OVS_UNUSED, char *argv[] > OVS_UNUSED) > > /* Check that the flow equals its miniflow. */ > assert(miniflow_get_vid(&miniflow) == > vlan_tci_to_vid(flow.vlan_tci)); > - for (i = 0; i < FLOW_U32S; i++) { > - assert(MINIFLOW_GET_TYPE(&miniflow, uint32_t, i * 4) > - == flow_u32[i]); > + for (i = 0; i < FLOW_U64S; i++) { > + assert(miniflow_get(&miniflow, i) == flow_u64[i]); > } > > /* Check that the miniflow equals itself. */ > @@ -1372,7 +1373,7 @@ test_minimask_combine(int argc OVS_UNUSED, char > *argv[] OVS_UNUSED) > for (idx = 0; next_random_flow(&flow, idx); idx++) { > struct minimask minimask, minimask2, minicombined; > struct flow_wildcards mask, mask2, combined, combined2; > - uint32_t storage[FLOW_U32S]; > + uint64_t storage[FLOW_U64S]; > struct flow flow2; > > mask.masks = flow; > -- > 1.7.10.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev