ofproto: Add NXM_NX_TUN_GBP_ID and NXM_NX_TUN_GBP_FLAGS
[cascardo/ovs.git] / lib / flow.c
index df1996f..81b36f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 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, pad) &&
-                  offsetof(struct flow, tcp_flags) / 4
-                  == offsetof(struct flow, pad) / 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 != 27)
+#if (FLOW_WC_SEQ != 31)
 #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) % 4 == 0) {                                               \
+    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) % 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, conj_id);
+        }
     }
 
     /* 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. */
@@ -423,6 +488,7 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
     if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
         const struct ip_header *nh = data;
         int ip_len;
+        uint16_t tot_len;
 
         if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
             goto out;
@@ -432,9 +498,23 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
         if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN)) {
             goto out;
         }
+        if (OVS_UNLIKELY(size < ip_len)) {
+            goto out;
+        }
+        tot_len = ntohs(nh->ip_tot_len);
+        if (OVS_UNLIKELY(tot_len > size)) {
+            goto out;
+        }
+        if (OVS_UNLIKELY(size - tot_len > UINT8_MAX)) {
+            goto out;
+        }
+        ofpbuf_set_l2_pad_size(packet, size - tot_len);
+        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;
@@ -445,29 +525,37 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
                 nw_frag |= FLOW_NW_FRAG_LATER;
             }
         }
-        if (OVS_UNLIKELY(size < ip_len)) {
-            goto out;
-        }
         data_pull(&data, &size, ip_len);
-
     } else if (dl_type == htons(ETH_TYPE_IPV6)) {
         const struct ovs_16aligned_ip6_hdr *nh;
         ovs_be32 tc_flow;
+        uint16_t plen;
 
         if (OVS_UNLIKELY(size < sizeof *nh)) {
             goto out;
         }
         nh = data_pull(&data, &size, sizeof *nh);
 
+        plen = ntohs(nh->ip6_plen);
+        if (OVS_UNLIKELY(plen > size)) {
+            goto out;
+        }
+        /* Jumbo Payload option not supported yet. */
+        if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
+            goto out;
+        }
+        ofpbuf_set_l2_pad_size(packet, size - plen);
+        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;
@@ -548,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)));
                 }
 
@@ -562,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;
@@ -578,21 +669,28 @@ 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_push_be16(mf, tp_src, tcp->tcp_src);
+                miniflow_push_be16(mf, tp_dst, tcp->tcp_dst);
+                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_push_be16(mf, tp_src, udp->udp_src);
+                miniflow_push_be16(mf, tp_dst, udp->udp_dst);
+                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_push_be16(mf, tp_src, sctp->sctp_src);
+                miniflow_push_be16(mf, tp_dst, sctp->sctp_dst);
+                miniflow_pad_to_64(mf, igmp_group_ip4);
             }
         } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMP)) {
             if (OVS_LIKELY(size >= ICMP_HEADER_LEN)) {
@@ -600,6 +698,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)) {
@@ -619,21 +718,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;
 }
@@ -643,12 +740,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];
     }
 }
 
@@ -668,13 +765,15 @@ 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 == 27);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
 
     fmd->dp_hash = flow->dp_hash;
     fmd->recirc_id = flow->recirc_id;
     fmd->tun_id = flow->tunnel.tun_id;
     fmd->tun_src = flow->tunnel.ip_src;
     fmd->tun_dst = flow->tunnel.ip_dst;
+    fmd->gbp_id = flow->tunnel.gbp_id;
+    fmd->gbp_flags = flow->tunnel.gbp_flags;
     fmd->metadata = flow->metadata;
     memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
     fmd->pkt_mark = flow->pkt_mark;
@@ -814,6 +913,9 @@ 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 == 31);
+
     if (flow->tunnel.ip_dst) {
         if (flow->tunnel.flags & FLOW_TNL_F_KEY) {
             WC_MASK_FIELD(wc, tunnel.tun_id);
@@ -825,11 +927,13 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
         WC_MASK_FIELD(wc, tunnel.ip_ttl);
         WC_MASK_FIELD(wc, tunnel.tp_src);
         WC_MASK_FIELD(wc, tunnel.tp_dst);
+        WC_MASK_FIELD(wc, tunnel.gbp_id);
+        WC_MASK_FIELD(wc, tunnel.gbp_flags);
     } else if (flow->tunnel.tun_id) {
         WC_MASK_FIELD(wc, tunnel.tun_id);
     }
 
-    /* metadata and regs wildcarded. */
+    /* metadata, regs, and conj_id wildcarded. */
 
     WC_MASK_FIELD(wc, skb_priority);
     WC_MASK_FIELD(wc, pkt_mark);
@@ -837,6 +941,8 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
     WC_MASK_FIELD(wc, dp_hash);
     WC_MASK_FIELD(wc, in_port);
 
+    /* actset_output wildcarded. */
+
     WC_MASK_FIELD(wc, dl_dst);
     WC_MASK_FIELD(wc, dl_src);
     WC_MASK_FIELD(wc, dl_type);
@@ -898,13 +1004,73 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
     }
 }
 
+/* Return a map of possible fields for a packet of the same type as 'flow'.
+ * Including extra bits in the returned mask is not wrong, it is just less
+ * optimal.
+ *
+ * This is a less precise version of flow_wildcards_init_for_packet() above. */
+uint64_t
+flow_wc_map(const struct flow *flow)
+{
+    /* Update this function whenever struct flow changes. */
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
+
+    uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0;
+
+    /* Metadata fields that can appear on packet input. */
+    map |= MINIFLOW_MAP(skb_priority) | MINIFLOW_MAP(pkt_mark)
+        | MINIFLOW_MAP(recirc_id) | MINIFLOW_MAP(dp_hash)
+        | MINIFLOW_MAP(in_port)
+        | MINIFLOW_MAP(dl_dst) | MINIFLOW_MAP(dl_src)
+        | MINIFLOW_MAP(dl_type) | MINIFLOW_MAP(vlan_tci);
+
+    /* Ethertype-dependent fields. */
+    if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
+        map |= MINIFLOW_MAP(nw_src) | MINIFLOW_MAP(nw_dst)
+            | MINIFLOW_MAP(nw_proto) | MINIFLOW_MAP(nw_frag)
+            | MINIFLOW_MAP(nw_tos) | MINIFLOW_MAP(nw_ttl);
+        if (OVS_UNLIKELY(flow->nw_proto == IPPROTO_IGMP)) {
+            map |= MINIFLOW_MAP(igmp_group_ip4);
+        } else {
+            map |= MINIFLOW_MAP(tcp_flags)
+                | MINIFLOW_MAP(tp_src) | MINIFLOW_MAP(tp_dst);
+        }
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        map |= MINIFLOW_MAP(ipv6_src) | MINIFLOW_MAP(ipv6_dst)
+            | MINIFLOW_MAP(ipv6_label)
+            | MINIFLOW_MAP(nw_proto) | MINIFLOW_MAP(nw_frag)
+            | MINIFLOW_MAP(nw_tos) | MINIFLOW_MAP(nw_ttl);
+        if (OVS_UNLIKELY(flow->nw_proto == IPPROTO_ICMPV6)) {
+            map |= MINIFLOW_MAP(nd_target)
+                | MINIFLOW_MAP(arp_sha) | MINIFLOW_MAP(arp_tha);
+        } else {
+            map |= MINIFLOW_MAP(tcp_flags)
+                | MINIFLOW_MAP(tp_src) | MINIFLOW_MAP(tp_dst);
+        }
+    } else if (eth_type_mpls(flow->dl_type)) {
+        map |= MINIFLOW_MAP(mpls_lse);
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+               flow->dl_type == htons(ETH_TYPE_RARP)) {
+        map |= MINIFLOW_MAP(nw_src) | MINIFLOW_MAP(nw_dst)
+            | MINIFLOW_MAP(nw_proto)
+            | MINIFLOW_MAP(arp_sha) | MINIFLOW_MAP(arp_tha);
+    }
+
+    return map;
+}
+
 /* Clear the metadata and register wildcard masks. They are not packet
  * header fields. */
 void
 flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc)
 {
+    /* Update this function whenever struct flow changes. */
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
+
     memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata);
     memset(&wc->masks.regs, 0, sizeof wc->masks.regs);
+    wc->masks.actset_output = 0;
+    wc->masks.conj_id = 0;
 }
 
 /* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits or
@@ -912,11 +1078,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;
         }
     }
@@ -931,13 +1097,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];
     }
 }
 
@@ -949,13 +1115,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];
     }
 }
 
@@ -981,12 +1147,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;
         }
     }
@@ -999,13 +1165,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;
         }
     }
@@ -1043,22 +1209,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;
@@ -1078,23 +1240,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;
@@ -1263,16 +1426,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
@@ -1334,23 +1497,24 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp)
 int
 flow_count_mpls_labels(const struct flow *flow, struct flow_wildcards *wc)
 {
-    if (wc) {
-        wc->masks.dl_type = OVS_BE16_MAX;
-    }
+    /* dl_type is always masked. */
     if (eth_type_mpls(flow->dl_type)) {
         int i;
-        int len = FLOW_MAX_MPLS_LABELS;
+        int cnt;
 
-        for (i = 0; i < len; i++) {
+        cnt = 0;
+        for (i = 0; i < FLOW_MAX_MPLS_LABELS; i++) {
             if (wc) {
                 wc->masks.mpls_lse[i] |= htonl(MPLS_BOS_MASK);
             }
             if (flow->mpls_lse[i] & htonl(MPLS_BOS_MASK)) {
                 return i + 1;
             }
+            if (flow->mpls_lse[i]) {
+                cnt++;
+            }
         }
-
-        return len;
+        return cnt;
     } else {
         return 0;
     }
@@ -1405,7 +1569,7 @@ flow_count_common_mpls_labels(const struct flow *a, int an,
  *
  *     - BoS: 1.
  *
- * If the new label is the second or label MPLS label in 'flow', it is
+ * If the new label is the second or later label MPLS label in 'flow', it is
  * generated as;
  *
  *     - label: Copied from outer label.
@@ -1426,15 +1590,16 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
     ovs_assert(eth_type_mpls(mpls_eth_type));
     ovs_assert(n < FLOW_MAX_MPLS_LABELS);
 
-    memset(wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
     if (n) {
         int i;
 
+        if (wc) {
+            memset(&wc->masks.mpls_lse, 0xff, sizeof *wc->masks.mpls_lse * n);
+        }
         for (i = n; i >= 1; i--) {
             flow->mpls_lse[i] = flow->mpls_lse[i - 1];
         }
-        flow->mpls_lse[0] = (flow->mpls_lse[1]
-                             & htonl(~MPLS_BOS_MASK));
+        flow->mpls_lse[0] = (flow->mpls_lse[1] & htonl(~MPLS_BOS_MASK));
     } else {
         int label = 0;          /* IPv4 Explicit Null. */
         int tc = 0;
@@ -1446,20 +1611,23 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type,
 
         if (is_ip_any(flow)) {
             tc = (flow->nw_tos & IP_DSCP_MASK) >> 2;
-            wc->masks.nw_tos |= IP_DSCP_MASK;
+            if (wc) {
+                wc->masks.nw_tos |= IP_DSCP_MASK;
+                wc->masks.nw_ttl = 0xff;
+            }
 
             if (flow->nw_ttl) {
                 ttl = flow->nw_ttl;
             }
-            wc->masks.nw_ttl = 0xff;
         }
 
         flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));
 
-        /* Clear all L3 and L4 fields. */
-        BUILD_ASSERT(FLOW_WC_SEQ == 27);
+        /* Clear all L3 and L4 fields and dp_hash. */
+        BUILD_ASSERT(FLOW_WC_SEQ == 31);
         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;
 }
@@ -1478,13 +1646,20 @@ flow_pop_mpls(struct flow *flow, int n, ovs_be16 eth_type,
     if (n == 0) {
         /* Nothing to pop. */
         return false;
-    } else if (n == FLOW_MAX_MPLS_LABELS
-               && !(flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK))) {
-        /* Can't pop because we don't know what to fill in mpls_lse[n - 1]. */
-        return false;
+    } else if (n == FLOW_MAX_MPLS_LABELS) {
+        if (wc) {
+            wc->masks.mpls_lse[n - 1] |= htonl(MPLS_BOS_MASK);
+        }
+        if (!(flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK))) {
+            /* Can't pop because don't know what to fill in mpls_lse[n - 1]. */
+            return false;
+        }
     }
 
-    memset(wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+    if (wc) {
+        memset(&wc->masks.mpls_lse[1], 0xff,
+               sizeof *wc->masks.mpls_lse * (n - 1));
+    }
     for (i = 1; i < n; i++) {
         flow->mpls_lse[i - 1] = flow->mpls_lse[i];
     }
@@ -1727,7 +1902,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);
@@ -1745,7 +1920,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,
@@ -1753,17 +1928,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);
-    uint64_t map;
+    const uint64_t *src_u64 = (const uint64_t *) src;
+    uint64_t *dst_u64 = miniflow_alloc_values(dst, n);
+    int idx;
 
-    for (map = dst->map; map; map = zero_rightmost_1bit(map)) {
-        *dst_u32++ = src_u32[raw_ctz(map)];
+    MAP_FOR_EACH_INDEX(idx, dst->map) {
+        *dst_u64++ = src_u64[idx];
     }
 }
 
@@ -1773,7 +1948,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;
 
@@ -1781,8 +1956,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++;
         }
@@ -1807,7 +1982,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) {
@@ -1878,39 +2053,24 @@ 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_u32_values(flow) +
-            count_1bits(flow->map & ((UINT64_C(1) << u32_ofs) - 1)))
-        : 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 a_map = a->map;
-    const uint64_t b_map = b->map;
+    const uint64_t *ap = miniflow_get_values(a);
+    const uint64_t *bp = miniflow_get_values(b);
 
-    if (OVS_LIKELY(a_map == b_map)) {
+    if (OVS_LIKELY(a->map == b->map)) {
         int count = miniflow_n_values(a);
 
         return !memcmp(ap, bp, count * sizeof *ap);
     } else {
         uint64_t map;
 
-        for (map = a_map | b_map; map; map = zero_rightmost_1bit(map)) {
+        for (map = a->map | b->map; map; map = zero_rightmost_1bit(map)) {
             uint64_t bit = rightmost_1bit(map);
-            uint64_t a_value = a_map & bit ? *ap++ : 0;
-            uint64_t b_value = b_map & bit ? *bp++ : 0;
 
-            if (a_value != b_value) {
+            if ((a->map & bit ? *ap++ : 0) != (b->map & bit ? *bp++ : 0)) {
                 return false;
             }
         }
@@ -1919,19 +2079,17 @@ miniflow_equal(const struct miniflow *a, const struct miniflow *b)
     return true;
 }
 
-/* Returns true if 'a' and 'b' are equal at the places where there are 1-bits
- * in 'mask', false if they differ. */
+/* Returns false if 'a' and 'b' differ at the places where there are 1-bits
+ * in 'mask', true otherwise. */
 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);
-    uint64_t map;
-
-    for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
-        int ofs = raw_ctz(map);
+    const uint64_t *p = miniflow_get_values(&mask->masks);
+    int idx;
 
-        if ((miniflow_get(a, ofs) ^ miniflow_get(b, ofs)) & *p++) {
+    MAP_FOR_EACH_INDEX(idx, mask->masks.map) {
+        if ((miniflow_get(a, idx) ^ miniflow_get(b, idx)) & *p++) {
             return false;
         }
     }
@@ -1945,14 +2103,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);
-    uint64_t map;
-
-    for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
-        int ofs = raw_ctz(map);
+    const uint64_t *b_u64 = (const uint64_t *) b;
+    const uint64_t *p = miniflow_get_values(&mask->masks);
+    int idx;
 
-        if ((miniflow_get(a, ofs) ^ b_u32[ofs]) & *p++) {
+    MAP_FOR_EACH_INDEX(idx, mask->masks.map) {
+        if ((miniflow_get(a, idx) ^ b_u64[idx]) & *p++) {
             return false;
         }
     }
@@ -1987,31 +2143,30 @@ 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;
-    uint64_t map;
-    int n = 0;
+    int idx;
 
     dst->values_inline = false;
     dst->offline_values = storage;
 
     dst->map = 0;
-    for (map = a->map & b->map; map; map = zero_rightmost_1bit(map)) {
-        int ofs = raw_ctz(map);
-        uint32_t mask = miniflow_get(a, ofs) & miniflow_get(b, ofs);
+    MAP_FOR_EACH_INDEX(idx, a->map & b->map) {
+        /* Both 'a' and 'b' have non-zero data at 'idx'. */
+        uint64_t mask = miniflow_get__(a, idx) & miniflow_get__(b, idx);
 
         if (mask) {
-            dst->map |= rightmost_1bit(map);
-            dst_values[n++] = mask;
+            dst->map |= UINT64_C(1) << idx;
+            *dst_values++ = mask;
         }
     }
 }
@@ -2031,19 +2186,16 @@ 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.  */
+/* 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. */
 bool
 minimask_equal(const struct minimask *a, const struct minimask *b)
 {
-    return miniflow_equal(&a->masks, &b->masks);
+    return a->masks.map == b->masks.map &&
+        !memcmp(miniflow_get_values(&a->masks),
+                miniflow_get_values(&b->masks),
+                count_1bits(a->masks.map) * sizeof *a->masks.inline_values);
 }
 
 /* Returns true if at least one bit matched by 'b' is wildcarded by 'a',
@@ -2051,15 +2203,19 @@ 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 *p = miniflow_get_u32_values(&b->masks);
-    uint64_t map;
+    const uint64_t *ap = miniflow_get_values(&a->masks);
+    const uint64_t *bp = miniflow_get_values(&b->masks);
+    int idx;
 
-    for (map = b->masks.map; map; map = zero_rightmost_1bit(map)) {
-        uint32_t a_u32 = minimask_get(a, raw_ctz(map));
-        uint32_t b_u32 = *p++;
+    MAP_FOR_EACH_INDEX(idx, b->masks.map) {
+        uint64_t b_u64 = *bp++;
 
-        if ((a_u32 & b_u32) != b_u32) {
-            return true;
+        /* '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_u64)
+                != b_u64)) {
+            return true; /* 'a' wildcards some bits 'b' doesn't. */
         }
     }