Hi Jarno,

I ran perf top before and after the miniflow patches. It looks like it is 
missing in the emc after the patches and hence the performance drops.

Before: b2623fdbb31570e7e3e39ac9c074b0978b4dd2dc ~13 mpps

  22.83%  ovs-vswitchd        [.] ixgbe_recv_pkts
  19.69%  ovs-vswitchd        [.] miniflow_extract
  16.86%  ovs-vswitchd        [.] emc_processing
  13.12%  ovs-vswitchd        [.] dp_netdev_process_rxq_port.isra.16
  11.76%  libc-2.18.so        [.] __memcmp_sse4_1
  11.32%  ovs-vswitchd        [.] ixgbe_xmit_pkts_vec
   1.52%  ovs-vswitchd        [.] netdev_dpdk_eth_send
   0.46%  libc-2.18.so        [.] __memcpy_sse2_unaligned
   0.44%  ovs-vswitchd        [.] dpdk_queue_flush__
   0.37%  ovs-vswitchd        [.] memcmp@plt
   0.19%  [vdso]              [.] __vdso_clock_gettime
   0.13%  ovs-vswitchd        [.] netdev_send
   0.13%  ovs-vswitchd        [.] netdev_dpdk_rxq_recv
   0.12%  ovs-vswitchd        [.] dp_execute_cb
   0.10%  ovs-vswitchd        [.] netdev_rxq_recv
   0.10%  ovs-vswitchd        [.] cmap_find
   0.10%  ovs-vswitchd        [.] odp_execute_actions
   0.07%  ovs-vswitchd        [.] pmd_thread_main
   0.07%  libc-2.18.so        [.] __clock_gettime
   0.05%  ovs-vswitchd        [.] dp_netdev_lookup_port
   0.05%  ovs-vswitchd        [.] dp_netdev_input
   0.05%  ovs-vswitchd        [.] nl_attr_type
   0.04%  ovs-vswitchd        [.] time_timespec__
   
After: d70e8c28f992c0d8c2918aa0733b935ce1a0caed ~4.8 mpps

 20.89%  ovs-vswitchd        [.] dpcls_lookup
  14.72%  ovs-vswitchd        [.] emc_processing
  14.45%  libc-2.18.so        [.] __memcmp_sse4_1
  11.71%  ovs-vswitchd        [.] emc_insert
   8.73%  ovs-vswitchd        [.] ixgbe_recv_pkts
   7.76%  ovs-vswitchd        [.] fast_path_processing
   7.60%  ovs-vswitchd        [.] miniflow_extract
   4.62%  ovs-vswitchd        [.] dp_netdev_process_rxq_port.isra.16
   4.27%  ovs-vswitchd        [.] ixgbe_xmit_pkts_vec
   2.89%  ovs-vswitchd        [.] cmap_find_batch
   0.52%  ovs-vswitchd        [.] memcmp@plt
   0.49%  ovs-vswitchd        [.] netdev_dpdk_eth_send
   0.18%  ovs-vswitchd        [.] dpdk_queue_flush__
   0.16%  libc-2.18.so        [.] memset
   0.11%  libc-2.18.so        [.] __memcpy_sse2_unaligned
   0.08%  [vdso]              [.] __vdso_clock_gettime
   0.06%  ovs-vswitchd        [.] netdev_dpdk_rxq_recv
   0.05%  ovs-vswitchd        [.] cmap_find
   0.04%  ovs-vswitchd        [.] netdev_send
   0.04%  ovs-vswitchd        [.] dp_netdev_input
   0.04%  ovs-vswitchd        [.] netdev_rxq_recv
   0.03%  ovs-vswitchd        [.] pmd_thread_main
   0.03%  ovs-vswitchd        [.] odp_execute_actions
   0.03%  ovs-vswitchd        [.] dp_execute_cb
   0.02%  libc-2.18.so        [.] __clock_gettime

Thanks,
Kevin.

> -----Original Message-----
> From: dev [mailto:dev-boun...@openvswitch.org] On Behalf Of Jarno Rajahalme
> Sent: Monday, January 12, 2015 6:57 PM
> To: Loftus, Ciara
> Cc: dev@openvswitch.org
> Subject: Re: [ovs-dev] [PATCH 2/2] miniflow: Use 64-bit data.
> 
> 
> On Jan 12, 2015, at 9:16 AM, Loftus, Ciara <ciara.lof...@intel.com> wrote:
> 
> > Hi,
> >
> > After running some performance tests on the latest master, it appears that 
> > this commit has caused
> netdev DPDK performance to drop significantly (by > 50 %). Has anybody else 
> seen this?
> >
> 
> I saw notified of this last week, and did some checking on the patch to find 
> out what is going on, but
> nothing came up. I’d need someone running the DPDK performance tests to send 
> me perf data taken while
> running the tests so that I have something to go with.
> 
> Thanks,
> 
>   Jarno
> 
> > Regards,
> > Ciara
> >
> > -----Original Message-----
> > From: dev [mailto:dev-boun...@openvswitch.org] On Behalf Of Jarno Rajahalme
> > Sent: Wednesday, December 17, 2014 6:31 PM
> > To: dev@openvswitch.org
> > Subject: [ovs-dev] [PATCH 2/2] miniflow: Use 64-bit data.
> >
> > 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++;                                                      \
> >     }                                                                   \
> > }
> >
> > -#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
> > --------------------------------------------------------------
> > Intel Shannon Limited
> > Registered in Ireland
> > Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
> > Registered Number: 308263
> > Business address: Dromore House, East Park, Shannon, Co. Clare
> >
> > This e-mail and any attachments may contain confidential material for the 
> > sole use of the intended
> recipient(s). Any review or distribution by others is strictly prohibited. If 
> you are not the intended
> recipient, please contact the sender and delete all copies.
> >
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to