[ovs-dev] [classifier-opt 19/28] flow: Replace flow_wildcards members by a single "struct flow".

Ethan Jackson ethan at nicira.com
Tue Jul 31 01:10:22 UTC 2012


In flow_wildcards_init_catchall() and flow_wildcards_init_exact() why
not just memset?  Perhaps the appropriate time to make that change
would have been when in_port was changed to a mask come to think of
it.  It's fine to leave it if you're going to resolve it in a future
patch of the series.

The indentation isn't quite right in flow_wildcards_combine().  It was
incorrect before this patch as well, but this may be a good time to
clean it up.

I suspect you're going to switch flow_wildcards_equal() to using
memcmp() in a future patch?

Do we still need "struct flow_wildcards" at all?  We could just use
struct flow directly.  Again, perhaps this will make more sense once
I've seen the future patches.

Looks good,
Ethan






On Fri, Jul 20, 2012 at 4:25 PM, Ben Pfaff <blp at nicira.com> wrote:
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
>  lib/classifier.c        |  206 +++++++++++++-------------
>  lib/flow.c              |  386 ++++++++++++++++++++++++-----------------------
>  lib/flow.h              |   35 +----
>  lib/meta-flow.c         |  154 ++++++++++----------
>  lib/nx-match.c          |   64 ++++----
>  lib/ofp-util.c          |  154 ++++++++++---------
>  ofproto/ofproto.c       |    4 +-
>  tests/test-classifier.c |   57 ++++---
>  utilities/ovs-ofctl.c   |   10 +-
>  9 files changed, 529 insertions(+), 541 deletions(-)
>
> diff --git a/lib/classifier.c b/lib/classifier.c
> index 47ba49a..486b3d5 100644
> --- a/lib/classifier.c
> +++ b/lib/classifier.c
> @@ -128,7 +128,7 @@ void
>  cls_rule_set_metadata_masked(struct cls_rule *rule, ovs_be64 metadata,
>                               ovs_be64 mask)
>  {
> -    rule->wc.metadata_mask = mask;
> +    rule->wc.masks.metadata = mask;
>      rule->flow.metadata = metadata & mask;
>  }
>
> @@ -142,21 +142,21 @@ void
>  cls_rule_set_tun_id_masked(struct cls_rule *rule,
>                             ovs_be64 tun_id, ovs_be64 mask)
>  {
> -    rule->wc.tun_id_mask = mask;
> +    rule->wc.masks.tun_id = mask;
>      rule->flow.tun_id = tun_id & mask;
>  }
>
>  void
>  cls_rule_set_in_port(struct cls_rule *rule, uint16_t ofp_port)
>  {
> -    rule->wc.in_port_mask = UINT16_MAX;
> +    rule->wc.masks.in_port = UINT16_MAX;
>      rule->flow.in_port = ofp_port;
>  }
>
>  void
>  cls_rule_set_dl_type(struct cls_rule *rule, ovs_be16 dl_type)
>  {
> -    rule->wc.dl_type_mask = htons(UINT16_MAX);
> +    rule->wc.masks.dl_type = htons(UINT16_MAX);
>      rule->flow.dl_type = dl_type;
>  }
>
> @@ -193,7 +193,7 @@ cls_rule_set_eth_masked(const uint8_t value_src[ETH_ADDR_LEN],
>  void
>  cls_rule_set_dl_src(struct cls_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
>  {
> -    cls_rule_set_eth(dl_src, rule->flow.dl_src, rule->wc.dl_src_mask);
> +    cls_rule_set_eth(dl_src, rule->flow.dl_src, rule->wc.masks.dl_src);
>  }
>
>  /* Modifies 'rule' so that the source Ethernet address
> @@ -205,7 +205,7 @@ cls_rule_set_dl_src_masked(struct cls_rule *rule,
>                             const uint8_t mask[ETH_ADDR_LEN])
>  {
>      cls_rule_set_eth_masked(dl_src, mask,
> -                            rule->flow.dl_src, rule->wc.dl_src_mask);
> +                            rule->flow.dl_src, rule->wc.masks.dl_src);
>  }
>
>  /* Modifies 'rule' so that the destination Ethernet address
> @@ -213,7 +213,7 @@ cls_rule_set_dl_src_masked(struct cls_rule *rule,
>  void
>  cls_rule_set_dl_dst(struct cls_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
>  {
> -    cls_rule_set_eth(dl_dst, rule->flow.dl_dst, rule->wc.dl_dst_mask);
> +    cls_rule_set_eth(dl_dst, rule->flow.dl_dst, rule->wc.masks.dl_dst);
>  }
>
>  /* Modifies 'rule' so that the destination Ethernet address
> @@ -225,7 +225,7 @@ cls_rule_set_dl_dst_masked(struct cls_rule *rule,
>                             const uint8_t mask[ETH_ADDR_LEN])
>  {
>      cls_rule_set_eth_masked(dl_dst, mask,
> -                            rule->flow.dl_dst, rule->wc.dl_dst_mask);
> +                            rule->flow.dl_dst, rule->wc.masks.dl_dst);
>  }
>
>  void
> @@ -238,7 +238,7 @@ void
>  cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
>  {
>      rule->flow.vlan_tci = tci & mask;
> -    rule->wc.vlan_tci_mask = mask;
> +    rule->wc.masks.vlan_tci = mask;
>  }
>
>  /* Modifies 'rule' so that the VLAN VID is wildcarded.  If the PCP is already
> @@ -247,8 +247,8 @@ cls_rule_set_dl_tci_masked(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
>  void
>  cls_rule_set_any_vid(struct cls_rule *rule)
>  {
> -    if (rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK)) {
> -        rule->wc.vlan_tci_mask &= ~htons(VLAN_VID_MASK);
> +    if (rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK)) {
> +        rule->wc.masks.vlan_tci &= ~htons(VLAN_VID_MASK);
>          rule->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
>      } else {
>          cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
> @@ -268,9 +268,9 @@ cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
>  {
>      flow_set_vlan_vid(&rule->flow, dl_vlan);
>      if (dl_vlan == htons(OFP10_VLAN_NONE)) {
> -        rule->wc.vlan_tci_mask = htons(UINT16_MAX);
> +        rule->wc.masks.vlan_tci = htons(UINT16_MAX);
>      } else {
> -        rule->wc.vlan_tci_mask |= htons(VLAN_VID_MASK | VLAN_CFI);
> +        rule->wc.masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
>      }
>  }
>
> @@ -280,8 +280,8 @@ cls_rule_set_dl_vlan(struct cls_rule *rule, ovs_be16 dl_vlan)
>  void
>  cls_rule_set_any_pcp(struct cls_rule *rule)
>  {
> -    if (rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK)) {
> -        rule->wc.vlan_tci_mask &= ~htons(VLAN_PCP_MASK);
> +    if (rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK)) {
> +        rule->wc.masks.vlan_tci &= ~htons(VLAN_PCP_MASK);
>          rule->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
>      } else {
>          cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
> @@ -294,7 +294,7 @@ void
>  cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, uint8_t dl_vlan_pcp)
>  {
>      flow_set_vlan_pcp(&rule->flow, dl_vlan_pcp);
> -    rule->wc.vlan_tci_mask |= htons(VLAN_CFI | VLAN_PCP_MASK);
> +    rule->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
>  }
>
>  void
> @@ -307,7 +307,7 @@ void
>  cls_rule_set_tp_src_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 mask)
>  {
>      rule->flow.tp_src = port & mask;
> -    rule->wc.tp_src_mask = mask;
> +    rule->wc.masks.tp_src = mask;
>  }
>
>  void
> @@ -320,21 +320,21 @@ void
>  cls_rule_set_tp_dst_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 mask)
>  {
>      rule->flow.tp_dst = port & mask;
> -    rule->wc.tp_dst_mask = mask;
> +    rule->wc.masks.tp_dst = mask;
>  }
>
>  void
>  cls_rule_set_nw_proto(struct cls_rule *rule, uint8_t nw_proto)
>  {
>      rule->flow.nw_proto = nw_proto;
> -    rule->wc.nw_proto_mask = UINT8_MAX;
> +    rule->wc.masks.nw_proto = UINT8_MAX;
>  }
>
>  void
>  cls_rule_set_nw_src(struct cls_rule *rule, ovs_be32 nw_src)
>  {
>      rule->flow.nw_src = nw_src;
> -    rule->wc.nw_src_mask = htonl(UINT32_MAX);
> +    rule->wc.masks.nw_src = htonl(UINT32_MAX);
>  }
>
>  void
> @@ -342,27 +342,27 @@ cls_rule_set_nw_src_masked(struct cls_rule *rule,
>                             ovs_be32 nw_src, ovs_be32 mask)
>  {
>      rule->flow.nw_src = nw_src & mask;
> -    rule->wc.nw_src_mask = mask;
> +    rule->wc.masks.nw_src = mask;
>  }
>
>  void
>  cls_rule_set_nw_dst(struct cls_rule *rule, ovs_be32 nw_dst)
>  {
>      rule->flow.nw_dst = nw_dst;
> -    rule->wc.nw_dst_mask = htonl(UINT32_MAX);
> +    rule->wc.masks.nw_dst = htonl(UINT32_MAX);
>  }
>
>  void
>  cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask)
>  {
>      rule->flow.nw_dst = ip & mask;
> -    rule->wc.nw_dst_mask = mask;
> +    rule->wc.masks.nw_dst = mask;
>  }
>
>  void
>  cls_rule_set_nw_dscp(struct cls_rule *rule, uint8_t nw_dscp)
>  {
> -    rule->wc.nw_tos_mask |= IP_DSCP_MASK;
> +    rule->wc.masks.nw_tos |= IP_DSCP_MASK;
>      rule->flow.nw_tos &= ~IP_DSCP_MASK;
>      rule->flow.nw_tos |= nw_dscp & IP_DSCP_MASK;
>  }
> @@ -370,7 +370,7 @@ cls_rule_set_nw_dscp(struct cls_rule *rule, uint8_t nw_dscp)
>  void
>  cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn)
>  {
> -    rule->wc.nw_tos_mask |= IP_ECN_MASK;
> +    rule->wc.masks.nw_tos |= IP_ECN_MASK;
>      rule->flow.nw_tos &= ~IP_ECN_MASK;
>      rule->flow.nw_tos |= nw_ecn & IP_ECN_MASK;
>  }
> @@ -378,14 +378,14 @@ cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn)
>  void
>  cls_rule_set_nw_ttl(struct cls_rule *rule, uint8_t nw_ttl)
>  {
> -    rule->wc.nw_ttl_mask = UINT8_MAX;
> +    rule->wc.masks.nw_ttl = UINT8_MAX;
>      rule->flow.nw_ttl = nw_ttl;
>  }
>
>  void
>  cls_rule_set_nw_frag(struct cls_rule *rule, uint8_t nw_frag)
>  {
> -    rule->wc.nw_frag_mask |= FLOW_NW_FRAG_MASK;
> +    rule->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
>      rule->flow.nw_frag = nw_frag;
>  }
>
> @@ -394,7 +394,7 @@ cls_rule_set_nw_frag_masked(struct cls_rule *rule,
>                              uint8_t nw_frag, uint8_t mask)
>  {
>      rule->flow.nw_frag = nw_frag & mask;
> -    rule->wc.nw_frag_mask = mask;
> +    rule->wc.masks.nw_frag = mask;
>  }
>
>  void
> @@ -412,7 +412,7 @@ cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code)
>  void
>  cls_rule_set_arp_sha(struct cls_rule *rule, const uint8_t sha[ETH_ADDR_LEN])
>  {
> -    cls_rule_set_eth(sha, rule->flow.arp_sha, rule->wc.arp_sha_mask);
> +    cls_rule_set_eth(sha, rule->flow.arp_sha, rule->wc.masks.arp_sha);
>  }
>
>  void
> @@ -421,13 +421,13 @@ cls_rule_set_arp_sha_masked(struct cls_rule *rule,
>                             const uint8_t mask[ETH_ADDR_LEN])
>  {
>      cls_rule_set_eth_masked(arp_sha, mask,
> -                            rule->flow.arp_sha, rule->wc.arp_sha_mask);
> +                            rule->flow.arp_sha, rule->wc.masks.arp_sha);
>  }
>
>  void
>  cls_rule_set_arp_tha(struct cls_rule *rule, const uint8_t tha[ETH_ADDR_LEN])
>  {
> -    cls_rule_set_eth(tha, rule->flow.arp_tha, rule->wc.arp_tha_mask);
> +    cls_rule_set_eth(tha, rule->flow.arp_tha, rule->wc.masks.arp_tha);
>  }
>
>  void
> @@ -436,14 +436,14 @@ cls_rule_set_arp_tha_masked(struct cls_rule *rule,
>                             const uint8_t mask[ETH_ADDR_LEN])
>  {
>      cls_rule_set_eth_masked(arp_tha, mask,
> -                            rule->flow.arp_tha, rule->wc.arp_tha_mask);
> +                            rule->flow.arp_tha, rule->wc.masks.arp_tha);
>  }
>
>  void
>  cls_rule_set_ipv6_src(struct cls_rule *rule, const struct in6_addr *src)
>  {
>      rule->flow.ipv6_src = *src;
> -    rule->wc.ipv6_src_mask = in6addr_exact;
> +    rule->wc.masks.ipv6_src = in6addr_exact;
>  }
>
>  void
> @@ -451,14 +451,14 @@ cls_rule_set_ipv6_src_masked(struct cls_rule *rule, const struct in6_addr *src,
>                               const struct in6_addr *mask)
>  {
>      rule->flow.ipv6_src = ipv6_addr_bitand(src, mask);
> -    rule->wc.ipv6_src_mask = *mask;
> +    rule->wc.masks.ipv6_src = *mask;
>  }
>
>  void
>  cls_rule_set_ipv6_dst(struct cls_rule *rule, const struct in6_addr *dst)
>  {
>      rule->flow.ipv6_dst = *dst;
> -    rule->wc.ipv6_dst_mask = in6addr_exact;
> +    rule->wc.masks.ipv6_dst = in6addr_exact;
>  }
>
>  void
> @@ -466,7 +466,7 @@ cls_rule_set_ipv6_dst_masked(struct cls_rule *rule, const struct in6_addr *dst,
>                               const struct in6_addr *mask)
>  {
>      rule->flow.ipv6_dst = ipv6_addr_bitand(dst, mask);
> -    rule->wc.ipv6_dst_mask = *mask;
> +    rule->wc.masks.ipv6_dst = *mask;
>  }
>
>  void
> @@ -480,14 +480,14 @@ cls_rule_set_ipv6_label_masked(struct cls_rule *rule, ovs_be32 ipv6_label,
>                                 ovs_be32 mask)
>  {
>      rule->flow.ipv6_label = ipv6_label & mask;
> -    rule->wc.ipv6_label_mask = mask;
> +    rule->wc.masks.ipv6_label = mask;
>  }
>
>  void
>  cls_rule_set_nd_target(struct cls_rule *rule, const struct in6_addr *target)
>  {
>      rule->flow.nd_target = *target;
> -    rule->wc.nd_target_mask = in6addr_exact;
> +    rule->wc.masks.nd_target = in6addr_exact;
>  }
>
>  void
> @@ -496,7 +496,7 @@ cls_rule_set_nd_target_masked(struct cls_rule *rule,
>                                const struct in6_addr *mask)
>  {
>      rule->flow.nd_target = ipv6_addr_bitand(target, mask);
> -    rule->wc.nd_target_mask = *mask;
> +    rule->wc.masks.nd_target = *mask;
>  }
>
>  /* Returns true if 'a' and 'b' have the same priority, wildcard the same
> @@ -587,10 +587,10 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          ds_put_format(s, "priority=%d,", rule->priority);
>      }
>
> -    if (wc->dl_type_mask) {
> +    if (wc->masks.dl_type) {
>          skip_type = true;
>          if (f->dl_type == htons(ETH_TYPE_IP)) {
> -            if (wc->nw_proto_mask) {
> +            if (wc->masks.nw_proto) {
>                  skip_proto = true;
>                  if (f->nw_proto == IPPROTO_ICMP) {
>                      ds_put_cstr(s, "icmp,");
> @@ -606,7 +606,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>                  ds_put_cstr(s, "ip,");
>              }
>          } else if (f->dl_type == htons(ETH_TYPE_IPV6)) {
> -            if (wc->nw_proto_mask) {
> +            if (wc->masks.nw_proto) {
>                  skip_proto = true;
>                  if (f->nw_proto == IPPROTO_ICMPV6) {
>                      ds_put_cstr(s, "icmp6,");
> @@ -628,7 +628,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          }
>      }
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        switch (wc->reg_masks[i]) {
> +        switch (wc->masks.regs[i]) {
>          case 0:
>              break;
>          case UINT32_MAX:
> @@ -636,11 +636,11 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>              break;
>          default:
>              ds_put_format(s, "reg%d=0x%"PRIx32"/0x%"PRIx32",",
> -                          i, f->regs[i], wc->reg_masks[i]);
> +                          i, f->regs[i], wc->masks.regs[i]);
>              break;
>          }
>      }
> -    switch (wc->tun_id_mask) {
> +    switch (wc->masks.tun_id) {
>      case 0:
>          break;
>      case CONSTANT_HTONLL(UINT64_MAX):
> @@ -648,10 +648,10 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          break;
>      default:
>          ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
> -                      ntohll(f->tun_id), ntohll(wc->tun_id_mask));
> +                      ntohll(f->tun_id), ntohll(wc->masks.tun_id));
>          break;
>      }
> -    switch (wc->metadata_mask) {
> +    switch (wc->masks.metadata) {
>      case 0:
>          break;
>      case CONSTANT_HTONLL(UINT64_MAX):
> @@ -659,16 +659,16 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          break;
>      default:
>          ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
> -                      ntohll(f->metadata), ntohll(wc->metadata_mask));
> +                      ntohll(f->metadata), ntohll(wc->masks.metadata));
>          break;
>      }
> -    if (wc->in_port_mask) {
> +    if (wc->masks.in_port) {
>          ds_put_format(s, "in_port=%"PRIu16",", f->in_port);
>      }
> -    if (wc->vlan_tci_mask) {
> -        ovs_be16 vid_mask = wc->vlan_tci_mask & htons(VLAN_VID_MASK);
> -        ovs_be16 pcp_mask = wc->vlan_tci_mask & htons(VLAN_PCP_MASK);
> -        ovs_be16 cfi = wc->vlan_tci_mask & htons(VLAN_CFI);
> +    if (wc->masks.vlan_tci) {
> +        ovs_be16 vid_mask = wc->masks.vlan_tci & htons(VLAN_VID_MASK);
> +        ovs_be16 pcp_mask = wc->masks.vlan_tci & htons(VLAN_PCP_MASK);
> +        ovs_be16 cfi = wc->masks.vlan_tci & htons(VLAN_CFI);
>
>          if (cfi && f->vlan_tci & htons(VLAN_CFI)
>              && (!vid_mask || vid_mask == htons(VLAN_VID_MASK))
> @@ -682,36 +682,36 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>                  ds_put_format(s, "dl_vlan_pcp=%d,",
>                                vlan_tci_to_pcp(f->vlan_tci));
>              }
> -        } else if (wc->vlan_tci_mask == htons(0xffff)) {
> +        } else if (wc->masks.vlan_tci == htons(0xffff)) {
>              ds_put_format(s, "vlan_tci=0x%04"PRIx16",", ntohs(f->vlan_tci));
>          } else {
>              ds_put_format(s, "vlan_tci=0x%04"PRIx16"/0x%04"PRIx16",",
> -                          ntohs(f->vlan_tci), ntohs(wc->vlan_tci_mask));
> +                          ntohs(f->vlan_tci), ntohs(wc->masks.vlan_tci));
>          }
>      }
> -    format_eth_masked(s, "dl_src", f->dl_src, wc->dl_src_mask);
> -    format_eth_masked(s, "dl_dst", f->dl_dst, wc->dl_dst_mask);
> -    if (!skip_type && wc->dl_type_mask) {
> +    format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src);
> +    format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst);
> +    if (!skip_type && wc->masks.dl_type) {
>          ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type));
>      }
>      if (f->dl_type == htons(ETH_TYPE_IPV6)) {
> -        format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->ipv6_src_mask);
> -        format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->ipv6_dst_mask);
> -        if (wc->ipv6_label_mask) {
> -            if (wc->ipv6_label_mask == htonl(UINT32_MAX)) {
> +        format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src);
> +        format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst);
> +        if (wc->masks.ipv6_label) {
> +            if (wc->masks.ipv6_label == htonl(UINT32_MAX)) {
>                  ds_put_format(s, "ipv6_label=0x%05"PRIx32",",
>                                ntohl(f->ipv6_label));
>              } else {
>                  ds_put_format(s, "ipv6_label=0x%05"PRIx32"/0x%05"PRIx32",",
>                                ntohl(f->ipv6_label),
> -                              ntohl(wc->ipv6_label_mask));
> +                              ntohl(wc->masks.ipv6_label));
>              }
>          }
>      } else {
> -        format_ip_netmask(s, "nw_src", f->nw_src, wc->nw_src_mask);
> -        format_ip_netmask(s, "nw_dst", f->nw_dst, wc->nw_dst_mask);
> +        format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
> +        format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
>      }
> -    if (!skip_proto && wc->nw_proto_mask) {
> +    if (!skip_proto && wc->masks.nw_proto) {
>          if (f->dl_type == htons(ETH_TYPE_ARP)) {
>              ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto);
>          } else {
> @@ -719,19 +719,19 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          }
>      }
>      if (f->dl_type == htons(ETH_TYPE_ARP)) {
> -        format_eth_masked(s, "arp_sha", f->arp_sha, wc->arp_sha_mask);
> -        format_eth_masked(s, "arp_tha", f->arp_tha, wc->arp_tha_mask);
> +        format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha);
> +        format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha);
>      }
> -    if (wc->nw_tos_mask & IP_DSCP_MASK) {
> +    if (wc->masks.nw_tos & IP_DSCP_MASK) {
>          ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos & IP_DSCP_MASK);
>      }
> -    if (wc->nw_tos_mask & IP_ECN_MASK) {
> +    if (wc->masks.nw_tos & IP_ECN_MASK) {
>          ds_put_format(s, "nw_ecn=%"PRIu8",", f->nw_tos & IP_ECN_MASK);
>      }
> -    if (wc->nw_ttl_mask) {
> +    if (wc->masks.nw_ttl) {
>          ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
>      }
> -    switch (wc->nw_frag_mask) {
> +    switch (wc->masks.nw_frag) {
>      case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
>          ds_put_format(s, "nw_frag=%s,",
>                        f->nw_frag & FLOW_NW_FRAG_ANY
> @@ -750,18 +750,18 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
>          break;
>      }
>      if (f->nw_proto == IPPROTO_ICMP) {
> -        format_be16_masked(s, "icmp_type", f->tp_src, wc->tp_src_mask);
> -        format_be16_masked(s, "icmp_code", f->tp_dst, wc->tp_dst_mask);
> +        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
> +        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
>      } else if (f->nw_proto == IPPROTO_ICMPV6) {
> -        format_be16_masked(s, "icmp_type", f->tp_src, wc->tp_src_mask);
> -        format_be16_masked(s, "icmp_code", f->tp_dst, wc->tp_dst_mask);
> +        format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
> +        format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
>          format_ipv6_netmask(s, "nd_target", &f->nd_target,
> -                            &wc->nd_target_mask);
> -        format_eth_masked(s, "nd_sll", f->arp_sha, wc->arp_sha_mask);
> -        format_eth_masked(s, "nd_tll", f->arp_tha, wc->arp_tha_mask);
> +                            &wc->masks.nd_target);
> +        format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha);
> +        format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha);
>     } else {
> -        format_be16_masked(s, "tp_src", f->tp_src, wc->tp_src_mask);
> -        format_be16_masked(s, "tp_dst", f->tp_dst, wc->tp_dst_mask);
> +        format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src);
> +        format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
>      }
>
>      if (s->length > start_len && ds_last(s) == ',') {
> @@ -1267,37 +1267,37 @@ flow_equal_except(const struct flow *a, const struct flow *b,
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
> +        if ((a->regs[i] ^ b->regs[i]) & wildcards->masks.regs[i]) {
>              return false;
>          }
>      }
>
> -    return (!((a->tun_id ^ b->tun_id) & wildcards->tun_id_mask)
> -            && !((a->metadata ^ b->metadata) & wildcards->metadata_mask)
> -            && !((a->nw_src ^ b->nw_src) & wildcards->nw_src_mask)
> -            && !((a->nw_dst ^ b->nw_dst) & wildcards->nw_dst_mask)
> -            && !((a->in_port ^ b->in_port) & wildcards->in_port_mask)
> -            && !((a->vlan_tci ^ b->vlan_tci) & wildcards->vlan_tci_mask)
> -            && !((a->dl_type ^ b->dl_type) & wildcards->dl_type_mask)
> -            && !((a->tp_src ^ b->tp_src) & wildcards->tp_src_mask)
> -            && !((a->tp_dst ^ b->tp_dst) & wildcards->tp_dst_mask)
> +    return (!((a->tun_id ^ b->tun_id) & wildcards->masks.tun_id)
> +            && !((a->metadata ^ b->metadata) & wildcards->masks.metadata)
> +            && !((a->nw_src ^ b->nw_src) & wildcards->masks.nw_src)
> +            && !((a->nw_dst ^ b->nw_dst) & wildcards->masks.nw_dst)
> +            && !((a->in_port ^ b->in_port) & wildcards->masks.in_port)
> +            && !((a->vlan_tci ^ b->vlan_tci) & wildcards->masks.vlan_tci)
> +            && !((a->dl_type ^ b->dl_type) & wildcards->masks.dl_type)
> +            && !((a->tp_src ^ b->tp_src) & wildcards->masks.tp_src)
> +            && !((a->tp_dst ^ b->tp_dst) & wildcards->masks.tp_dst)
>              && eth_addr_equal_except(a->dl_src, b->dl_src,
> -                                     wildcards->dl_src_mask)
> +                                     wildcards->masks.dl_src)
>              && eth_addr_equal_except(a->dl_dst, b->dl_dst,
> -                                     wildcards->dl_dst_mask)
> -            && !((a->nw_proto ^ b->nw_proto) & wildcards->nw_proto_mask)
> -            && !((a->nw_ttl ^ b->nw_ttl) & wildcards->nw_ttl_mask)
> -            && !((a->nw_tos ^ b->nw_tos) & wildcards->nw_tos_mask)
> -            && !((a->nw_frag ^ b->nw_frag) & wildcards->nw_frag_mask)
> +                                     wildcards->masks.dl_dst)
> +            && !((a->nw_proto ^ b->nw_proto) & wildcards->masks.nw_proto)
> +            && !((a->nw_ttl ^ b->nw_ttl) & wildcards->masks.nw_ttl)
> +            && !((a->nw_tos ^ b->nw_tos) & wildcards->masks.nw_tos)
> +            && !((a->nw_frag ^ b->nw_frag) & wildcards->masks.nw_frag)
>              && eth_addr_equal_except(a->arp_sha, b->arp_sha,
> -                                     wildcards->arp_sha_mask)
> +                                     wildcards->masks.arp_sha)
>              && eth_addr_equal_except(a->arp_tha, b->arp_tha,
> -                                     wildcards->arp_tha_mask)
> -            && !((a->ipv6_label ^ b->ipv6_label) & wildcards->ipv6_label_mask)
> +                                     wildcards->masks.arp_tha)
> +            && !((a->ipv6_label ^ b->ipv6_label) & wildcards->masks.ipv6_label)
>              && ipv6_equal_except(&a->ipv6_src, &b->ipv6_src,
> -                    &wildcards->ipv6_src_mask)
> +                    &wildcards->masks.ipv6_src)
>              && ipv6_equal_except(&a->ipv6_dst, &b->ipv6_dst,
> -                    &wildcards->ipv6_dst_mask)
> +                    &wildcards->masks.ipv6_dst)
>              && ipv6_equal_except(&a->nd_target, &b->nd_target,
> -                                 &wildcards->nd_target_mask));
> +                                 &wildcards->masks.nd_target));
>  }
> diff --git a/lib/flow.c b/lib/flow.c
> index e409e9d..2433bec 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -446,32 +446,32 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        flow->regs[i] &= wildcards->reg_masks[i];
> +        flow->regs[i] &= wildcards->masks.regs[i];
>      }
> -    flow->tun_id &= wildcards->tun_id_mask;
> -    flow->metadata &= wildcards->metadata_mask;
> -    flow->nw_src &= wildcards->nw_src_mask;
> -    flow->nw_dst &= wildcards->nw_dst_mask;
> -    flow->in_port &= wildcards->in_port_mask;
> -    flow->vlan_tci &= wildcards->vlan_tci_mask;
> -    flow->dl_type &= wildcards->dl_type_mask;
> -    flow->tp_src &= wildcards->tp_src_mask;
> -    flow->tp_dst &= wildcards->tp_dst_mask;
> -    eth_addr_bitand(flow->dl_src, wildcards->dl_src_mask, flow->dl_src);
> -    eth_addr_bitand(flow->dl_dst, wildcards->dl_dst_mask, flow->dl_dst);
> -    flow->ipv6_label &= wildcards->ipv6_label_mask;
> -    flow->nw_proto &= wildcards->nw_proto_mask;
> -    flow->nw_tos &= wildcards->nw_tos_mask;
> -    flow->nw_ttl &= wildcards->nw_ttl_mask;
> -    flow->nw_frag &= wildcards->nw_frag_mask;
> -    eth_addr_bitand(flow->arp_sha, wildcards->arp_sha_mask, flow->arp_sha);
> -    eth_addr_bitand(flow->arp_tha, wildcards->arp_tha_mask, flow->arp_tha);
> +    flow->tun_id &= wildcards->masks.tun_id;
> +    flow->metadata &= wildcards->masks.metadata;
> +    flow->nw_src &= wildcards->masks.nw_src;
> +    flow->nw_dst &= wildcards->masks.nw_dst;
> +    flow->in_port &= wildcards->masks.in_port;
> +    flow->vlan_tci &= wildcards->masks.vlan_tci;
> +    flow->dl_type &= wildcards->masks.dl_type;
> +    flow->tp_src &= wildcards->masks.tp_src;
> +    flow->tp_dst &= wildcards->masks.tp_dst;
> +    eth_addr_bitand(flow->dl_src, wildcards->masks.dl_src, flow->dl_src);
> +    eth_addr_bitand(flow->dl_dst, wildcards->masks.dl_dst, flow->dl_dst);
> +    flow->ipv6_label &= wildcards->masks.ipv6_label;
> +    flow->nw_proto &= wildcards->masks.nw_proto;
> +    flow->nw_tos &= wildcards->masks.nw_tos;
> +    flow->nw_ttl &= wildcards->masks.nw_ttl;
> +    flow->nw_frag &= wildcards->masks.nw_frag;
> +    eth_addr_bitand(flow->arp_sha, wildcards->masks.arp_sha, flow->arp_sha);
> +    eth_addr_bitand(flow->arp_tha, wildcards->masks.arp_tha, flow->arp_tha);
>      flow->ipv6_src = ipv6_addr_bitand(&flow->ipv6_src,
> -            &wildcards->ipv6_src_mask);
> +            &wildcards->masks.ipv6_src);
>      flow->ipv6_dst = ipv6_addr_bitand(&flow->ipv6_dst,
> -            &wildcards->ipv6_dst_mask);
> +            &wildcards->masks.ipv6_dst);
>      flow->nd_target = ipv6_addr_bitand(&flow->nd_target,
> -            &wildcards->nd_target_mask);
> +            &wildcards->masks.nd_target);
>      flow->skb_priority = 0;
>  }
>
> @@ -575,29 +575,29 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
>  {
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    wc->tun_id_mask = htonll(0);
> -    wc->nw_src_mask = htonl(0);
> -    wc->nw_dst_mask = htonl(0);
> -    wc->ipv6_src_mask = in6addr_any;
> -    wc->ipv6_dst_mask = in6addr_any;
> -    wc->ipv6_label_mask = htonl(0);
> -    wc->nd_target_mask = in6addr_any;
> -    memset(wc->reg_masks, 0, sizeof wc->reg_masks);
> -    wc->metadata_mask = htonll(0);
> -    wc->in_port_mask = 0;
> -    wc->vlan_tci_mask = htons(0);
> -    wc->nw_frag_mask = 0;
> -    wc->dl_type_mask = htons(0);
> -    wc->tp_src_mask = htons(0);
> -    wc->tp_dst_mask = htons(0);
> -    memset(wc->dl_src_mask, 0, ETH_ADDR_LEN);
> -    memset(wc->dl_dst_mask, 0, ETH_ADDR_LEN);
> -    memset(wc->arp_sha_mask, 0, ETH_ADDR_LEN);
> -    memset(wc->arp_tha_mask, 0, ETH_ADDR_LEN);
> -    wc->nw_proto_mask = 0;
> -    wc->nw_tos_mask = 0;
> -    wc->nw_ttl_mask = 0;
> -    memset(wc->zeros, 0, sizeof wc->zeros);
> +    wc->masks.tun_id = htonll(0);
> +    wc->masks.nw_src = htonl(0);
> +    wc->masks.nw_dst = htonl(0);
> +    wc->masks.ipv6_src = in6addr_any;
> +    wc->masks.ipv6_dst = in6addr_any;
> +    wc->masks.ipv6_label = htonl(0);
> +    wc->masks.nd_target = in6addr_any;
> +    memset(wc->masks.regs, 0, sizeof wc->masks.regs);
> +    wc->masks.metadata = htonll(0);
> +    wc->masks.in_port = 0;
> +    wc->masks.vlan_tci = htons(0);
> +    wc->masks.nw_frag = 0;
> +    wc->masks.dl_type = htons(0);
> +    wc->masks.tp_src = htons(0);
> +    wc->masks.tp_dst = htons(0);
> +    memset(wc->masks.dl_src, 0, ETH_ADDR_LEN);
> +    memset(wc->masks.dl_dst, 0, ETH_ADDR_LEN);
> +    memset(wc->masks.arp_sha, 0, ETH_ADDR_LEN);
> +    memset(wc->masks.arp_tha, 0, ETH_ADDR_LEN);
> +    wc->masks.nw_proto = 0;
> +    wc->masks.nw_tos = 0;
> +    wc->masks.nw_ttl = 0;
> +    memset(wc->masks.zeros, 0, sizeof wc->masks.zeros);
>  }
>
>  /* Initializes 'wc' as an exact-match set of wildcards; that is, 'wc' does not
> @@ -607,29 +607,29 @@ flow_wildcards_init_exact(struct flow_wildcards *wc)
>  {
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    wc->tun_id_mask = htonll(UINT64_MAX);
> -    wc->nw_src_mask = htonl(UINT32_MAX);
> -    wc->nw_dst_mask = htonl(UINT32_MAX);
> -    wc->ipv6_src_mask = in6addr_exact;
> -    wc->ipv6_dst_mask = in6addr_exact;
> -    wc->ipv6_label_mask = htonl(UINT32_MAX);
> -    wc->nd_target_mask = in6addr_exact;
> -    memset(wc->reg_masks, 0xff, sizeof wc->reg_masks);
> -    wc->metadata_mask = htonll(UINT64_MAX);
> -    wc->in_port_mask = UINT16_MAX;
> -    wc->vlan_tci_mask = htons(UINT16_MAX);
> -    wc->nw_frag_mask = UINT8_MAX;
> -    wc->dl_type_mask = htons(UINT16_MAX);
> -    wc->tp_src_mask = htons(UINT16_MAX);
> -    wc->tp_dst_mask = htons(UINT16_MAX);
> -    memset(wc->dl_src_mask, 0xff, ETH_ADDR_LEN);
> -    memset(wc->dl_dst_mask, 0xff, ETH_ADDR_LEN);
> -    memset(wc->arp_sha_mask, 0xff, ETH_ADDR_LEN);
> -    memset(wc->arp_tha_mask, 0xff, ETH_ADDR_LEN);
> -    wc->nw_proto_mask = UINT8_MAX;
> -    wc->nw_tos_mask = UINT8_MAX;
> -    wc->nw_ttl_mask = UINT8_MAX;
> -    memset(wc->zeros, 0, sizeof wc->zeros);
> +    wc->masks.tun_id = htonll(UINT64_MAX);
> +    wc->masks.nw_src = htonl(UINT32_MAX);
> +    wc->masks.nw_dst = htonl(UINT32_MAX);
> +    wc->masks.ipv6_src = in6addr_exact;
> +    wc->masks.ipv6_dst = in6addr_exact;
> +    wc->masks.ipv6_label = htonl(UINT32_MAX);
> +    wc->masks.nd_target = in6addr_exact;
> +    memset(wc->masks.regs, 0xff, sizeof wc->masks.regs);
> +    wc->masks.metadata = htonll(UINT64_MAX);
> +    wc->masks.in_port = UINT16_MAX;
> +    wc->masks.vlan_tci = htons(UINT16_MAX);
> +    wc->masks.nw_frag = UINT8_MAX;
> +    wc->masks.dl_type = htons(UINT16_MAX);
> +    wc->masks.tp_src = htons(UINT16_MAX);
> +    wc->masks.tp_dst = htons(UINT16_MAX);
> +    memset(wc->masks.dl_src, 0xff, ETH_ADDR_LEN);
> +    memset(wc->masks.dl_dst, 0xff, ETH_ADDR_LEN);
> +    memset(wc->masks.arp_sha, 0xff, ETH_ADDR_LEN);
> +    memset(wc->masks.arp_tha, 0xff, ETH_ADDR_LEN);
> +    wc->masks.nw_proto = UINT8_MAX;
> +    wc->masks.nw_tos = UINT8_MAX;
> +    wc->masks.nw_ttl = UINT8_MAX;
> +    memset(wc->masks.zeros, 0, sizeof wc->masks.zeros);
>  }
>
>  /* Returns true if 'wc' is exact-match, false if 'wc' wildcards any bits or
> @@ -641,32 +641,32 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
>
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    if (wc->tun_id_mask != htonll(UINT64_MAX)
> -        || wc->nw_src_mask != htonl(UINT32_MAX)
> -        || wc->nw_dst_mask != htonl(UINT32_MAX)
> -        || wc->tp_src_mask != htons(UINT16_MAX)
> -        || wc->tp_dst_mask != htons(UINT16_MAX)
> -        || wc->in_port_mask != UINT16_MAX
> -        || wc->vlan_tci_mask != htons(UINT16_MAX)
> -        || wc->metadata_mask != htonll(UINT64_MAX)
> -        || wc->dl_type_mask != htons(UINT16_MAX)
> -        || !eth_mask_is_exact(wc->dl_src_mask)
> -        || !eth_mask_is_exact(wc->dl_dst_mask)
> -        || !eth_mask_is_exact(wc->arp_sha_mask)
> -        || !eth_mask_is_exact(wc->arp_tha_mask)
> -        || !ipv6_mask_is_exact(&wc->ipv6_src_mask)
> -        || !ipv6_mask_is_exact(&wc->ipv6_dst_mask)
> -        || wc->ipv6_label_mask != htonl(UINT32_MAX)
> -        || !ipv6_mask_is_exact(&wc->nd_target_mask)
> -        || wc->nw_proto_mask != UINT8_MAX
> -        || wc->nw_frag_mask != UINT8_MAX
> -        || wc->nw_tos_mask != UINT8_MAX
> -        || wc->nw_ttl_mask != UINT8_MAX) {
> +    if (wc->masks.tun_id != htonll(UINT64_MAX)
> +        || wc->masks.nw_src != htonl(UINT32_MAX)
> +        || wc->masks.nw_dst != htonl(UINT32_MAX)
> +        || wc->masks.tp_src != htons(UINT16_MAX)
> +        || wc->masks.tp_dst != htons(UINT16_MAX)
> +        || wc->masks.in_port != UINT16_MAX
> +        || wc->masks.vlan_tci != htons(UINT16_MAX)
> +        || wc->masks.metadata != htonll(UINT64_MAX)
> +        || wc->masks.dl_type != htons(UINT16_MAX)
> +        || !eth_mask_is_exact(wc->masks.dl_src)
> +        || !eth_mask_is_exact(wc->masks.dl_dst)
> +        || !eth_mask_is_exact(wc->masks.arp_sha)
> +        || !eth_mask_is_exact(wc->masks.arp_tha)
> +        || !ipv6_mask_is_exact(&wc->masks.ipv6_src)
> +        || !ipv6_mask_is_exact(&wc->masks.ipv6_dst)
> +        || wc->masks.ipv6_label != htonl(UINT32_MAX)
> +        || !ipv6_mask_is_exact(&wc->masks.nd_target)
> +        || wc->masks.nw_proto != UINT8_MAX
> +        || wc->masks.nw_frag != UINT8_MAX
> +        || wc->masks.nw_tos != UINT8_MAX
> +        || wc->masks.nw_ttl != UINT8_MAX) {
>          return false;
>      }
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if (wc->reg_masks[i] != UINT32_MAX) {
> +        if (wc->masks.regs[i] != UINT32_MAX) {
>              return false;
>          }
>      }
> @@ -683,32 +683,32 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
>
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    if (wc->tun_id_mask != htonll(0)
> -        || wc->nw_src_mask != htonl(0)
> -        || wc->nw_dst_mask != htonl(0)
> -        || wc->tp_src_mask != htons(0)
> -        || wc->tp_dst_mask != htons(0)
> -        || wc->in_port_mask != 0
> -        || wc->vlan_tci_mask != htons(0)
> -        || wc->metadata_mask != htonll(0)
> -        || wc->dl_type_mask != htons(0)
> -        || !eth_addr_is_zero(wc->dl_src_mask)
> -        || !eth_addr_is_zero(wc->dl_dst_mask)
> -        || !eth_addr_is_zero(wc->arp_sha_mask)
> -        || !eth_addr_is_zero(wc->arp_tha_mask)
> -        || !ipv6_mask_is_any(&wc->ipv6_src_mask)
> -        || !ipv6_mask_is_any(&wc->ipv6_dst_mask)
> -        || wc->ipv6_label_mask != htonl(0)
> -        || !ipv6_mask_is_any(&wc->nd_target_mask)
> -        || wc->nw_proto_mask != 0
> -        || wc->nw_frag_mask != 0
> -        || wc->nw_tos_mask != 0
> -        || wc->nw_ttl_mask != 0) {
> +    if (wc->masks.tun_id != htonll(0)
> +        || wc->masks.nw_src != htonl(0)
> +        || wc->masks.nw_dst != htonl(0)
> +        || wc->masks.tp_src != htons(0)
> +        || wc->masks.tp_dst != htons(0)
> +        || wc->masks.in_port != 0
> +        || wc->masks.vlan_tci != htons(0)
> +        || wc->masks.metadata != htonll(0)
> +        || wc->masks.dl_type != htons(0)
> +        || !eth_addr_is_zero(wc->masks.dl_src)
> +        || !eth_addr_is_zero(wc->masks.dl_dst)
> +        || !eth_addr_is_zero(wc->masks.arp_sha)
> +        || !eth_addr_is_zero(wc->masks.arp_tha)
> +        || !ipv6_mask_is_any(&wc->masks.ipv6_src)
> +        || !ipv6_mask_is_any(&wc->masks.ipv6_dst)
> +        || wc->masks.ipv6_label != htonl(0)
> +        || !ipv6_mask_is_any(&wc->masks.nd_target)
> +        || wc->masks.nw_proto != 0
> +        || wc->masks.nw_frag != 0
> +        || wc->masks.nw_tos != 0
> +        || wc->masks.nw_ttl != 0) {
>          return false;
>      }
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if (wc->reg_masks[i] != 0) {
> +        if (wc->masks.regs[i] != 0) {
>              return false;
>          }
>      }
> @@ -728,33 +728,35 @@ flow_wildcards_combine(struct flow_wildcards *dst,
>
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask;
> -    dst->nw_src_mask = src1->nw_src_mask & src2->nw_src_mask;
> -    dst->nw_dst_mask = src1->nw_dst_mask & src2->nw_dst_mask;
> -    dst->ipv6_src_mask = ipv6_addr_bitand(&src1->ipv6_src_mask,
> -                                        &src2->ipv6_src_mask);
> -    dst->ipv6_dst_mask = ipv6_addr_bitand(&src1->ipv6_dst_mask,
> -                                        &src2->ipv6_dst_mask);
> -    dst->ipv6_label_mask = src1->ipv6_label_mask & src2->ipv6_label_mask;
> -    dst->nd_target_mask = ipv6_addr_bitand(&src1->nd_target_mask,
> -                                        &src2->nd_target_mask);
> +    dst->masks.tun_id = src1->masks.tun_id & src2->masks.tun_id;
> +    dst->masks.nw_src = src1->masks.nw_src & src2->masks.nw_src;
> +    dst->masks.nw_dst = src1->masks.nw_dst & src2->masks.nw_dst;
> +    dst->masks.ipv6_src = ipv6_addr_bitand(&src1->masks.ipv6_src,
> +                                        &src2->masks.ipv6_src);
> +    dst->masks.ipv6_dst = ipv6_addr_bitand(&src1->masks.ipv6_dst,
> +                                        &src2->masks.ipv6_dst);
> +    dst->masks.ipv6_label = src1->masks.ipv6_label & src2->masks.ipv6_label;
> +    dst->masks.nd_target = ipv6_addr_bitand(&src1->masks.nd_target,
> +                                        &src2->masks.nd_target);
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        dst->reg_masks[i] = src1->reg_masks[i] & src2->reg_masks[i];
> +        dst->masks.regs[i] = src1->masks.regs[i] & src2->masks.regs[i];
>      }
> -    dst->metadata_mask = src1->metadata_mask & src2->metadata_mask;
> -    dst->in_port_mask = src1->in_port_mask & src2->in_port_mask;
> -    dst->vlan_tci_mask = src1->vlan_tci_mask & src2->vlan_tci_mask;
> -    dst->dl_type_mask = src1->dl_type_mask & src2->dl_type_mask;
> -    dst->tp_src_mask = src1->tp_src_mask & src2->tp_src_mask;
> -    dst->tp_dst_mask = src1->tp_dst_mask & src2->tp_dst_mask;
> -    dst->nw_frag_mask = src1->nw_frag_mask & src2->nw_frag_mask;
> -    eth_addr_bitand(src1->dl_src_mask, src2->dl_src_mask, dst->dl_src_mask);
> -    eth_addr_bitand(src1->dl_dst_mask, src2->dl_dst_mask, dst->dl_dst_mask);
> -    eth_addr_bitand(src1->arp_sha_mask, src2->arp_sha_mask, dst->arp_sha_mask);
> -    eth_addr_bitand(src1->arp_tha_mask, src2->arp_tha_mask, dst->arp_tha_mask);
> -    dst->nw_proto_mask = src1->nw_proto_mask & src2->nw_proto_mask;
> -    dst->nw_tos_mask = src1->nw_tos_mask & src2->nw_tos_mask;
> -    dst->nw_ttl_mask = src1->nw_ttl_mask & src2->nw_ttl_mask;
> +    dst->masks.metadata = src1->masks.metadata & src2->masks.metadata;
> +    dst->masks.in_port = src1->masks.in_port & src2->masks.in_port;
> +    dst->masks.vlan_tci = src1->masks.vlan_tci & src2->masks.vlan_tci;
> +    dst->masks.dl_type = src1->masks.dl_type & src2->masks.dl_type;
> +    dst->masks.tp_src = src1->masks.tp_src & src2->masks.tp_src;
> +    dst->masks.tp_dst = src1->masks.tp_dst & src2->masks.tp_dst;
> +    dst->masks.nw_frag = src1->masks.nw_frag & src2->masks.nw_frag;
> +    eth_addr_bitand(src1->masks.dl_src, src2->masks.dl_src, dst->masks.dl_src);
> +    eth_addr_bitand(src1->masks.dl_dst, src2->masks.dl_dst, dst->masks.dl_dst);
> +    eth_addr_bitand(src1->masks.arp_sha, src2->masks.arp_sha,
> +                    dst->masks.arp_sha);
> +    eth_addr_bitand(src1->masks.arp_tha, src2->masks.arp_tha,
> +                    dst->masks.arp_tha);
> +    dst->masks.nw_proto = src1->masks.nw_proto & src2->masks.nw_proto;
> +    dst->masks.nw_tos = src1->masks.nw_tos & src2->masks.nw_tos;
> +    dst->masks.nw_ttl = src1->masks.nw_ttl & src2->masks.nw_ttl;
>  }
>
>  /* Returns a hash of the wildcards in 'wc'. */
> @@ -774,32 +776,32 @@ flow_wildcards_equal(const struct flow_wildcards *a,
>
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
> -    if (a->tun_id_mask != b->tun_id_mask
> -        || a->nw_src_mask != b->nw_src_mask
> -        || a->nw_dst_mask != b->nw_dst_mask
> -        || a->in_port_mask != b->in_port_mask
> -        || a->vlan_tci_mask != b->vlan_tci_mask
> -        || a->metadata_mask != b->metadata_mask
> -        || a->dl_type_mask != b->dl_type_mask
> -        || !ipv6_addr_equals(&a->ipv6_src_mask, &b->ipv6_src_mask)
> -        || !ipv6_addr_equals(&a->ipv6_dst_mask, &b->ipv6_dst_mask)
> -        || a->ipv6_label_mask != b->ipv6_label_mask
> -        || !ipv6_addr_equals(&a->nd_target_mask, &b->nd_target_mask)
> -        || a->tp_src_mask != b->tp_src_mask
> -        || a->tp_dst_mask != b->tp_dst_mask
> -        || a->nw_frag_mask != b->nw_frag_mask
> -        || !eth_addr_equals(a->dl_src_mask, b->dl_src_mask)
> -        || !eth_addr_equals(a->dl_dst_mask, b->dl_dst_mask)
> -        || !eth_addr_equals(a->arp_sha_mask, b->arp_sha_mask)
> -        || !eth_addr_equals(a->arp_tha_mask, b->arp_tha_mask)
> -        || a->nw_proto_mask != b->nw_proto_mask
> -        || a->nw_tos_mask != b->nw_tos_mask
> -        || a->nw_ttl_mask != b->nw_ttl_mask) {
> +    if (a->masks.tun_id != b->masks.tun_id
> +        || a->masks.nw_src != b->masks.nw_src
> +        || a->masks.nw_dst != b->masks.nw_dst
> +        || a->masks.in_port != b->masks.in_port
> +        || a->masks.vlan_tci != b->masks.vlan_tci
> +        || a->masks.metadata != b->masks.metadata
> +        || a->masks.dl_type != b->masks.dl_type
> +        || !ipv6_addr_equals(&a->masks.ipv6_src, &b->masks.ipv6_src)
> +        || !ipv6_addr_equals(&a->masks.ipv6_dst, &b->masks.ipv6_dst)
> +        || a->masks.ipv6_label != b->masks.ipv6_label
> +        || !ipv6_addr_equals(&a->masks.nd_target, &b->masks.nd_target)
> +        || a->masks.tp_src != b->masks.tp_src
> +        || a->masks.tp_dst != b->masks.tp_dst
> +        || a->masks.nw_frag != b->masks.nw_frag
> +        || !eth_addr_equals(a->masks.dl_src, b->masks.dl_src)
> +        || !eth_addr_equals(a->masks.dl_dst, b->masks.dl_dst)
> +        || !eth_addr_equals(a->masks.arp_sha, b->masks.arp_sha)
> +        || !eth_addr_equals(a->masks.arp_tha, b->masks.arp_tha)
> +        || a->masks.nw_proto != b->masks.nw_proto
> +        || a->masks.nw_tos != b->masks.nw_tos
> +        || a->masks.nw_ttl != b->masks.nw_ttl) {
>          return false;
>      }
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if (a->reg_masks[i] != b->reg_masks[i]) {
> +        if (a->masks.regs[i] != b->masks.regs[i]) {
>              return false;
>          }
>      }
> @@ -820,60 +822,62 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) {
> +        if ((a->masks.regs[i] & b->masks.regs[i]) != b->masks.regs[i]) {
>              return true;
>          }
>      }
>
> -    eth_addr_bitand(a->dl_src_mask, b->dl_src_mask, eth_masked);
> -    if (!eth_addr_equals(eth_masked, b->dl_src_mask)) {
> +    eth_addr_bitand(a->masks.dl_src, b->masks.dl_src, eth_masked);
> +    if (!eth_addr_equals(eth_masked, b->masks.dl_src)) {
>          return true;
>      }
>
> -    eth_addr_bitand(a->dl_dst_mask, b->dl_dst_mask, eth_masked);
> -    if (!eth_addr_equals(eth_masked, b->dl_dst_mask)) {
> +    eth_addr_bitand(a->masks.dl_dst, b->masks.dl_dst, eth_masked);
> +    if (!eth_addr_equals(eth_masked, b->masks.dl_dst)) {
>          return true;
>      }
>
> -    eth_addr_bitand(a->arp_sha_mask, b->arp_sha_mask, eth_masked);
> -    if (!eth_addr_equals(eth_masked, b->arp_sha_mask)) {
> +    eth_addr_bitand(a->masks.arp_sha, b->masks.arp_sha, eth_masked);
> +    if (!eth_addr_equals(eth_masked, b->masks.arp_sha)) {
>          return true;
>      }
>
> -    eth_addr_bitand(a->arp_tha_mask, b->arp_tha_mask, eth_masked);
> -    if (!eth_addr_equals(eth_masked, b->arp_tha_mask)) {
> +    eth_addr_bitand(a->masks.arp_tha, b->masks.arp_tha, eth_masked);
> +    if (!eth_addr_equals(eth_masked, b->masks.arp_tha)) {
>          return true;
>      }
>
> -    ipv6_masked = ipv6_addr_bitand(&a->ipv6_src_mask, &b->ipv6_src_mask);
> -    if (!ipv6_addr_equals(&ipv6_masked, &b->ipv6_src_mask)) {
> +    ipv6_masked = ipv6_addr_bitand(&a->masks.ipv6_src, &b->masks.ipv6_src);
> +    if (!ipv6_addr_equals(&ipv6_masked, &b->masks.ipv6_src)) {
>          return true;
>      }
>
> -    ipv6_masked = ipv6_addr_bitand(&a->ipv6_dst_mask, &b->ipv6_dst_mask);
> -    if (!ipv6_addr_equals(&ipv6_masked, &b->ipv6_dst_mask)) {
> +    ipv6_masked = ipv6_addr_bitand(&a->masks.ipv6_dst, &b->masks.ipv6_dst);
> +    if (!ipv6_addr_equals(&ipv6_masked, &b->masks.ipv6_dst)) {
>          return true;
>      }
>
> -    ipv6_masked = ipv6_addr_bitand(&a->nd_target_mask, &b->nd_target_mask);
> -    if (!ipv6_addr_equals(&ipv6_masked, &b->nd_target_mask)) {
> +    ipv6_masked = ipv6_addr_bitand(&a->masks.nd_target, &b->masks.nd_target);
> +    if (!ipv6_addr_equals(&ipv6_masked, &b->masks.nd_target)) {
>          return true;
>      }
>
> -    return ((a->tun_id_mask & b->tun_id_mask) != b->tun_id_mask
> -            || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
> -            || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask
> -            || (a->ipv6_label_mask & b->ipv6_label_mask) != b->ipv6_label_mask
> -            || (a->in_port_mask & b->in_port_mask) != b->in_port_mask
> -            || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask
> -            || (a->metadata_mask & b->metadata_mask) != b->metadata_mask
> -            || (a->dl_type_mask & b->dl_type_mask) != b->dl_type_mask
> -            || (a->tp_src_mask & b->tp_src_mask) != b->tp_src_mask
> -            || (a->tp_dst_mask & b->tp_dst_mask) != b->tp_dst_mask
> -            || (a->nw_proto_mask & b->nw_proto_mask) != b->nw_proto_mask
> -            || (a->nw_frag_mask & b->nw_frag_mask) != b->nw_frag_mask
> -            || (a->nw_tos_mask & b->nw_tos_mask) != b->nw_tos_mask
> -            || (a->nw_ttl_mask & b->nw_ttl_mask) != b->nw_ttl_mask);
> +    return ((a->masks.tun_id & b->masks.tun_id) != b->masks.tun_id
> +            || (a->masks.nw_src & b->masks.nw_src) != b->masks.nw_src
> +            || (a->masks.nw_dst & b->masks.nw_dst) != b->masks.nw_dst
> +            || ((a->masks.ipv6_label & b->masks.ipv6_label)
> +                != b->masks.ipv6_label)
> +            || (a->masks.in_port & b->masks.in_port) != b->masks.in_port
> +            || (a->masks.vlan_tci & b->masks.vlan_tci) != b->masks.vlan_tci
> +            || (a->masks.metadata & b->masks.metadata) != b->masks.metadata
> +            || (a->masks.dl_type & b->masks.dl_type) != b->masks.dl_type
> +            || (a->masks.dl_type & b->masks.dl_type) != b->masks.dl_type
> +            || (a->masks.tp_src & b->masks.tp_src) != b->masks.tp_src
> +            || (a->masks.tp_dst & b->masks.tp_dst) != b->masks.tp_dst
> +            || (a->masks.nw_proto & b->masks.nw_proto) != b->masks.nw_proto
> +            || (a->masks.nw_frag & b->masks.nw_frag) != b->masks.nw_frag
> +            || (a->masks.nw_tos & b->masks.nw_tos) != b->masks.nw_tos
> +            || (a->masks.nw_ttl & b->masks.nw_ttl) != b->masks.nw_ttl);
>  }
>
>  /* Sets the wildcard mask for register 'idx' in 'wc' to 'mask'.
> @@ -881,7 +885,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
>  void
>  flow_wildcards_set_reg_mask(struct flow_wildcards *wc, int idx, uint32_t mask)
>  {
> -    wc->reg_masks[idx] = mask;
> +    wc->masks.regs[idx] = mask;
>  }
>
>  /* Hashes 'flow' based on its L2 through L4 protocol information. */
> diff --git a/lib/flow.h b/lib/flow.h
> index 16c9bf2..9393c16 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -133,37 +133,14 @@ flow_hash(const struct flow *flow, uint32_t basis)
>      return hash_words((const uint32_t *) flow, sizeof *flow / 4, basis);
>  }
>
> -/* Information on wildcards for a flow, as a supplement to "struct flow". */
> +/* Wildcards for a flow.
> + *
> + * A 1-bit in each bit in 'masks' indicates that the corresponding bit of
> + * the flow is significant (must match).  A 0-bit indicates that the
> + * corresponding bit of the flow is wildcarded (need not match). */
>  struct flow_wildcards {
> -    ovs_be64 tun_id_mask;       /* 1-bit in each significant tun_id bit. */
> -    ovs_be64 metadata_mask;     /* 1-bit in each significant metadata bit. */
> -    uint32_t reg_masks[FLOW_N_REGS]; /* 1-bit in each significant regs bit. */
> -    ovs_be32 nw_src_mask;       /* 1-bit in each significant nw_src bit. */
> -    ovs_be32 nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
> -    struct in6_addr ipv6_src_mask; /* 1-bit in each signficant ipv6_src bit. */
> -    struct in6_addr ipv6_dst_mask; /* 1-bit in each signficant ipv6_dst bit. */
> -    struct in6_addr nd_target_mask; /* 1-bit in each significant
> -                                       nd_target bit. */
> -    ovs_be32 ipv6_label_mask;   /* 1 bit in each significant ipv6_label bit. */
> -    uint16_t in_port_mask;      /* 1-bit in each significant in_port bit. */
> -    ovs_be16 vlan_tci_mask;     /* 1-bit in each significant vlan_tci bit. */
> -    ovs_be16 dl_type_mask;      /* 1-bit in each significant dl_type bit. */
> -    ovs_be16 tp_src_mask;       /* 1-bit in each significant tp_src bit. */
> -    ovs_be16 tp_dst_mask;       /* 1-bit in each significant tp_dst bit. */
> -    uint8_t nw_proto_mask;      /* 1-bit in each significant nw_proto bit. */
> -    uint8_t nw_frag_mask;       /* 1-bit in each significant nw_frag bit. */
> -    uint8_t dl_src_mask[6];     /* 1-bit in each significant dl_src bit. */
> -    uint8_t dl_dst_mask[6];     /* 1-bit in each significant dl_dst bit. */
> -    uint8_t arp_sha_mask[6];    /* 1-bit in each significant dl_dst bit. */
> -    uint8_t arp_tha_mask[6];    /* 1-bit in each significant dl_dst bit. */
> -    uint8_t nw_tos_mask;        /* 1-bit in each significant nw_tos bit. */
> -    uint8_t nw_ttl_mask;        /* 1-bit in each significant nw_ttl bit. */
> -    uint8_t zeros[6];           /* Padding field set to zero. */
> +    struct flow masks;
>  };
> -BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) % 8 == 0);
> -
> -/* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */
> -BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 152 && FLOW_WC_SEQ == 17);
>
>  void flow_wildcards_init_catchall(struct flow_wildcards *);
>  void flow_wildcards_init_exact(struct flow_wildcards *);
> diff --git a/lib/meta-flow.c b/lib/meta-flow.c
> index 243681c..b7aae9a 100644
> --- a/lib/meta-flow.c
> +++ b/lib/meta-flow.c
> @@ -556,81 +556,81 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
>  {
>      switch (mf->id) {
>      case MFF_TUN_ID:
> -        return !wc->tun_id_mask;
> +        return !wc->masks.tun_id;
>      case MFF_METADATA:
> -        return !wc->metadata_mask;
> +        return !wc->masks.metadata;
>      case MFF_IN_PORT:
> -        return !wc->in_port_mask;
> +        return !wc->masks.in_port;
>      CASE_MFF_REGS:
> -        return !wc->reg_masks[mf->id - MFF_REG0];
> +        return !wc->masks.regs[mf->id - MFF_REG0];
>
>      case MFF_ETH_SRC:
> -        return eth_addr_is_zero(wc->dl_src_mask);
> +        return eth_addr_is_zero(wc->masks.dl_src);
>      case MFF_ETH_DST:
> -        return eth_addr_is_zero(wc->dl_dst_mask);
> +        return eth_addr_is_zero(wc->masks.dl_dst);
>      case MFF_ETH_TYPE:
> -        return !wc->dl_type_mask;
> +        return !wc->masks.dl_type;
>
>      case MFF_ARP_SHA:
>      case MFF_ND_SLL:
> -        return eth_addr_is_zero(wc->arp_sha_mask);
> +        return eth_addr_is_zero(wc->masks.arp_sha);
>
>      case MFF_ARP_THA:
>      case MFF_ND_TLL:
> -        return eth_addr_is_zero(wc->arp_tha_mask);
> +        return eth_addr_is_zero(wc->masks.arp_tha);
>
>      case MFF_VLAN_TCI:
> -        return !wc->vlan_tci_mask;
> +        return !wc->masks.vlan_tci;
>      case MFF_VLAN_VID:
> -        return !(wc->vlan_tci_mask & htons(VLAN_VID_MASK));
> +        return !(wc->masks.vlan_tci & htons(VLAN_VID_MASK));
>      case MFF_VLAN_PCP:
> -        return !(wc->vlan_tci_mask & htons(VLAN_PCP_MASK));
> +        return !(wc->masks.vlan_tci & htons(VLAN_PCP_MASK));
>
>      case MFF_IPV4_SRC:
> -        return !wc->nw_src_mask;
> +        return !wc->masks.nw_src;
>      case MFF_IPV4_DST:
> -        return !wc->nw_dst_mask;
> +        return !wc->masks.nw_dst;
>
>      case MFF_IPV6_SRC:
> -        return ipv6_mask_is_any(&wc->ipv6_src_mask);
> +        return ipv6_mask_is_any(&wc->masks.ipv6_src);
>      case MFF_IPV6_DST:
> -        return ipv6_mask_is_any(&wc->ipv6_dst_mask);
> +        return ipv6_mask_is_any(&wc->masks.ipv6_dst);
>
>      case MFF_IPV6_LABEL:
> -        return !wc->ipv6_label_mask;
> +        return !wc->masks.ipv6_label;
>
>      case MFF_IP_PROTO:
> -        return !wc->nw_proto_mask;
> +        return !wc->masks.nw_proto;
>      case MFF_IP_DSCP:
> -        return !(wc->nw_tos_mask & IP_DSCP_MASK);
> +        return !(wc->masks.nw_tos & IP_DSCP_MASK);
>      case MFF_IP_ECN:
> -        return !(wc->nw_tos_mask & IP_ECN_MASK);
> +        return !(wc->masks.nw_tos & IP_ECN_MASK);
>      case MFF_IP_TTL:
> -        return !wc->nw_ttl_mask;
> +        return !wc->masks.nw_ttl;
>
>      case MFF_ND_TARGET:
> -        return ipv6_mask_is_any(&wc->nd_target_mask);
> +        return ipv6_mask_is_any(&wc->masks.nd_target);
>
>      case MFF_IP_FRAG:
> -        return !(wc->nw_frag_mask & FLOW_NW_FRAG_MASK);
> +        return !(wc->masks.nw_frag & FLOW_NW_FRAG_MASK);
>
>      case MFF_ARP_OP:
> -        return !wc->nw_proto_mask;
> +        return !wc->masks.nw_proto;
>      case MFF_ARP_SPA:
> -        return !wc->nw_src_mask;
> +        return !wc->masks.nw_src;
>      case MFF_ARP_TPA:
> -        return !wc->nw_dst_mask;
> +        return !wc->masks.nw_dst;
>
>      case MFF_TCP_SRC:
>      case MFF_UDP_SRC:
>      case MFF_ICMPV4_TYPE:
>      case MFF_ICMPV6_TYPE:
> -        return !wc->tp_src_mask;
> +        return !wc->masks.tp_src;
>      case MFF_TCP_DST:
>      case MFF_UDP_DST:
>      case MFF_ICMPV4_CODE:
>      case MFF_ICMPV6_CODE:
> -        return !wc->tp_dst_mask;
> +        return !wc->masks.tp_dst;
>
>      case MFF_N_IDS:
>      default:
> @@ -650,110 +650,110 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
>  {
>      switch (mf->id) {
>      case MFF_TUN_ID:
> -        mask->be64 = wc->tun_id_mask;
> +        mask->be64 = wc->masks.tun_id;
>          break;
>      case MFF_METADATA:
> -        mask->be64 = wc->metadata_mask;
> +        mask->be64 = wc->masks.metadata;
>          break;
>      case MFF_IN_PORT:
> -        mask->be16 = htons(wc->in_port_mask);
> +        mask->be16 = htons(wc->masks.in_port);
>          break;
>      CASE_MFF_REGS:
> -        mask->be32 = htonl(wc->reg_masks[mf->id - MFF_REG0]);
> +        mask->be32 = htonl(wc->masks.regs[mf->id - MFF_REG0]);
>          break;
>
>      case MFF_ETH_DST:
> -        memcpy(mask->mac, wc->dl_dst_mask, ETH_ADDR_LEN);
> +        memcpy(mask->mac, wc->masks.dl_dst, ETH_ADDR_LEN);
>          break;
>      case MFF_ETH_SRC:
> -        memcpy(mask->mac, wc->dl_src_mask, ETH_ADDR_LEN);
> +        memcpy(mask->mac, wc->masks.dl_src, ETH_ADDR_LEN);
>          break;
>      case MFF_ETH_TYPE:
> -        mask->be16 = wc->dl_type_mask;
> +        mask->be16 = wc->masks.dl_type;
>          break;
>
>      case MFF_VLAN_TCI:
> -        mask->be16 = wc->vlan_tci_mask;
> +        mask->be16 = wc->masks.vlan_tci;
>          break;
>      case MFF_VLAN_VID:
> -        mask->be16 = wc->vlan_tci_mask & htons(VLAN_VID_MASK);
> +        mask->be16 = wc->masks.vlan_tci & htons(VLAN_VID_MASK);
>          break;
>      case MFF_VLAN_PCP:
> -        mask->u8 = vlan_tci_to_pcp(wc->vlan_tci_mask);
> +        mask->u8 = vlan_tci_to_pcp(wc->masks.vlan_tci);
>          break;
>
>      case MFF_IPV4_SRC:
> -        mask->be32 = wc->nw_src_mask;
> +        mask->be32 = wc->masks.nw_src;
>          break;
>      case MFF_IPV4_DST:
> -        mask->be32 = wc->nw_dst_mask;
> +        mask->be32 = wc->masks.nw_dst;
>          break;
>
>      case MFF_IPV6_SRC:
> -        mask->ipv6 = wc->ipv6_src_mask;
> +        mask->ipv6 = wc->masks.ipv6_src;
>          break;
>      case MFF_IPV6_DST:
> -        mask->ipv6 = wc->ipv6_dst_mask;
> +        mask->ipv6 = wc->masks.ipv6_dst;
>          break;
>      case MFF_IPV6_LABEL:
> -        mask->be32 = wc->ipv6_label_mask;
> +        mask->be32 = wc->masks.ipv6_label;
>          break;
>
>      case MFF_IP_PROTO:
> -        mask->u8 = wc->nw_proto_mask;
> +        mask->u8 = wc->masks.nw_proto;
>          break;
>      case MFF_IP_DSCP:
> -        mask->u8 = wc->nw_tos_mask & IP_DSCP_MASK;
> +        mask->u8 = wc->masks.nw_tos & IP_DSCP_MASK;
>          break;
>      case MFF_IP_ECN:
> -        mask->u8 = wc->nw_tos_mask & IP_ECN_MASK;
> +        mask->u8 = wc->masks.nw_tos & IP_ECN_MASK;
>          break;
>
>      case MFF_ND_TARGET:
> -        mask->ipv6 = wc->nd_target_mask;
> +        mask->ipv6 = wc->masks.nd_target;
>          break;
>
>      case MFF_IP_TTL:
> -        mask->u8 = wc->nw_ttl_mask;
> +        mask->u8 = wc->masks.nw_ttl;
>          break;
>      case MFF_IP_FRAG:
> -        mask->u8 = wc->nw_frag_mask & FLOW_NW_FRAG_MASK;
> +        mask->u8 = wc->masks.nw_frag & FLOW_NW_FRAG_MASK;
>          break;
>
>      case MFF_ARP_OP:
> -        mask->u8 = wc->nw_proto_mask;
> +        mask->u8 = wc->masks.nw_proto;
>          break;
>      case MFF_ARP_SPA:
> -        mask->be32 = wc->nw_src_mask;
> +        mask->be32 = wc->masks.nw_src;
>          break;
>      case MFF_ARP_TPA:
> -        mask->be32 = wc->nw_dst_mask;
> +        mask->be32 = wc->masks.nw_dst;
>          break;
>      case MFF_ARP_SHA:
>      case MFF_ND_SLL:
> -        memcpy(mask->mac, wc->arp_sha_mask, ETH_ADDR_LEN);
> +        memcpy(mask->mac, wc->masks.arp_sha, ETH_ADDR_LEN);
>          break;
>      case MFF_ARP_THA:
>      case MFF_ND_TLL:
> -        memcpy(mask->mac, wc->arp_tha_mask, ETH_ADDR_LEN);
> +        memcpy(mask->mac, wc->masks.arp_tha, ETH_ADDR_LEN);
>          break;
>
>      case MFF_TCP_SRC:
>      case MFF_UDP_SRC:
> -        mask->be16 = wc->tp_src_mask;
> +        mask->be16 = wc->masks.tp_src;
>          break;
>      case MFF_TCP_DST:
>      case MFF_UDP_DST:
> -        mask->be16 = wc->tp_dst_mask;
> +        mask->be16 = wc->masks.tp_dst;
>          break;
>
>      case MFF_ICMPV4_TYPE:
>      case MFF_ICMPV6_TYPE:
> -        mask->u8 = ntohs(wc->tp_src_mask);
> +        mask->u8 = ntohs(wc->masks.tp_src);
>          break;
>      case MFF_ICMPV4_CODE:
>      case MFF_ICMPV6_CODE:
> -        mask->u8 = ntohs(wc->tp_dst_mask);
> +        mask->u8 = ntohs(wc->masks.tp_dst);
>          break;
>
>      case MFF_N_IDS:
> @@ -1361,7 +1361,7 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
>
>      case MFF_IN_PORT:
>          rule->flow.in_port = 0;
> -        rule->wc.in_port_mask = 0;
> +        rule->wc.masks.in_port = 0;
>          break;
>
>      CASE_MFF_REGS:
> @@ -1370,17 +1370,17 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
>
>      case MFF_ETH_SRC:
>          memset(rule->flow.dl_src, 0, ETH_ADDR_LEN);
> -        memset(rule->wc.dl_src_mask, 0, ETH_ADDR_LEN);
> +        memset(rule->wc.masks.dl_src, 0, ETH_ADDR_LEN);
>          break;
>
>      case MFF_ETH_DST:
>          memset(rule->flow.dl_dst, 0, ETH_ADDR_LEN);
> -        memset(rule->wc.dl_dst_mask, 0, ETH_ADDR_LEN);
> +        memset(rule->wc.masks.dl_dst, 0, ETH_ADDR_LEN);
>          break;
>
>      case MFF_ETH_TYPE:
>          rule->flow.dl_type = htons(0);
> -        rule->wc.dl_type_mask = htons(0);
> +        rule->wc.masks.dl_type = htons(0);
>          break;
>
>      case MFF_VLAN_TCI:
> @@ -1406,67 +1406,67 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
>          break;
>
>      case MFF_IPV6_SRC:
> -        memset(&rule->wc.ipv6_src_mask, 0, sizeof rule->wc.ipv6_src_mask);
> +        memset(&rule->wc.masks.ipv6_src, 0, sizeof rule->wc.masks.ipv6_src);
>          memset(&rule->flow.ipv6_src, 0, sizeof rule->flow.ipv6_src);
>          break;
>
>      case MFF_IPV6_DST:
> -        memset(&rule->wc.ipv6_dst_mask, 0, sizeof rule->wc.ipv6_dst_mask);
> +        memset(&rule->wc.masks.ipv6_dst, 0, sizeof rule->wc.masks.ipv6_dst);
>          memset(&rule->flow.ipv6_dst, 0, sizeof rule->flow.ipv6_dst);
>          break;
>
>      case MFF_IPV6_LABEL:
> -        rule->wc.ipv6_label_mask = 0;
> -        rule->flow.ipv6_label = 0;
> +        rule->wc.masks.ipv6_label = htonl(0);
> +        rule->flow.ipv6_label = htonl(0);
>          break;
>
>      case MFF_IP_PROTO:
> -        rule->wc.nw_proto_mask = 0;
> +        rule->wc.masks.nw_proto = 0;
>          rule->flow.nw_proto = 0;
>          break;
>
>      case MFF_IP_DSCP:
> -        rule->wc.nw_tos_mask &= ~IP_DSCP_MASK;
> +        rule->wc.masks.nw_tos &= ~IP_DSCP_MASK;
>          rule->flow.nw_tos &= ~IP_DSCP_MASK;
>          break;
>
>      case MFF_IP_ECN:
> -        rule->wc.nw_tos_mask &= ~IP_ECN_MASK;
> +        rule->wc.masks.nw_tos &= ~IP_ECN_MASK;
>          rule->flow.nw_tos &= ~IP_ECN_MASK;
>          break;
>
>      case MFF_IP_TTL:
> -        rule->wc.nw_ttl_mask = 0;
> +        rule->wc.masks.nw_ttl = 0;
>          rule->flow.nw_ttl = 0;
>          break;
>
>      case MFF_IP_FRAG:
> -        rule->wc.nw_frag_mask |= FLOW_NW_FRAG_MASK;
> +        rule->wc.masks.nw_frag |= FLOW_NW_FRAG_MASK;
>          rule->flow.nw_frag &= ~FLOW_NW_FRAG_MASK;
>          break;
>
>      case MFF_ARP_OP:
> -        rule->wc.nw_proto_mask = 0;
> +        rule->wc.masks.nw_proto = 0;
>          rule->flow.nw_proto = 0;
>          break;
>
>      case MFF_ARP_SHA:
>      case MFF_ND_SLL:
>          memset(rule->flow.arp_sha, 0, ETH_ADDR_LEN);
> -        memset(rule->wc.arp_sha_mask, 0, ETH_ADDR_LEN);
> +        memset(rule->wc.masks.arp_sha, 0, ETH_ADDR_LEN);
>          break;
>
>      case MFF_ARP_THA:
>      case MFF_ND_TLL:
>          memset(rule->flow.arp_tha, 0, ETH_ADDR_LEN);
> -        memset(rule->wc.arp_tha_mask, 0, ETH_ADDR_LEN);
> +        memset(rule->wc.masks.arp_tha, 0, ETH_ADDR_LEN);
>          break;
>
>      case MFF_TCP_SRC:
>      case MFF_UDP_SRC:
>      case MFF_ICMPV4_TYPE:
>      case MFF_ICMPV6_TYPE:
> -        rule->wc.tp_src_mask = htons(0);
> +        rule->wc.masks.tp_src = htons(0);
>          rule->flow.tp_src = htons(0);
>          break;
>
> @@ -1474,12 +1474,12 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
>      case MFF_UDP_DST:
>      case MFF_ICMPV4_CODE:
>      case MFF_ICMPV6_CODE:
> -        rule->wc.tp_dst_mask = htons(0);
> +        rule->wc.masks.tp_dst = htons(0);
>          rule->flow.tp_dst = htons(0);
>          break;
>
>      case MFF_ND_TARGET:
> -        memset(&rule->wc.nd_target_mask, 0, sizeof rule->wc.nd_target_mask);
> +        memset(&rule->wc.masks.nd_target, 0, sizeof rule->wc.masks.nd_target);
>          memset(&rule->flow.nd_target, 0, sizeof rule->flow.nd_target);
>          break;
>
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index ba27aef..22f344f 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -406,7 +406,7 @@ static void
>  nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
>  {
>      uint8_t nw_frag = cr->flow.nw_frag;
> -    uint8_t nw_frag_mask = cr->wc.nw_frag_mask;
> +    uint8_t nw_frag_mask = cr->wc.masks.nw_frag;
>
>      switch (nw_frag_mask) {
>      case 0:
> @@ -432,38 +432,38 @@ nxm_put_ip(struct ofpbuf *b, const struct cls_rule *cr,
>
>      nxm_put_frag(b, cr);
>
> -    if (cr->wc.nw_tos_mask & IP_DSCP_MASK) {
> +    if (cr->wc.masks.nw_tos & IP_DSCP_MASK) {
>          nxm_put_8(b, oxm ? OXM_OF_IP_DSCP : NXM_OF_IP_TOS,
>                    flow->nw_tos & IP_DSCP_MASK);
>      }
>
> -    if (cr->wc.nw_tos_mask & IP_ECN_MASK) {
> +    if (cr->wc.masks.nw_tos & IP_ECN_MASK) {
>          nxm_put_8(b, oxm ? OXM_OF_IP_ECN : NXM_NX_IP_ECN,
>                    flow->nw_tos & IP_ECN_MASK);
>      }
>
> -    if (!oxm && cr->wc.nw_ttl_mask) {
> +    if (!oxm && cr->wc.masks.nw_ttl) {
>          nxm_put_8(b, NXM_NX_IP_TTL, flow->nw_ttl);
>      }
>
> -    if (cr->wc.nw_proto_mask) {
> +    if (cr->wc.masks.nw_proto) {
>          nxm_put_8(b, oxm ? OXM_OF_IP_PROTO : NXM_OF_IP_PROTO, flow->nw_proto);
>
>          if (flow->nw_proto == IPPROTO_TCP) {
>              nxm_put_16m(b, oxm ? OXM_OF_TCP_SRC : NXM_OF_TCP_SRC,
> -                        flow->tp_src, cr->wc.tp_src_mask);
> +                        flow->tp_src, cr->wc.masks.tp_src);
>              nxm_put_16m(b, oxm ? OXM_OF_TCP_DST : NXM_OF_TCP_DST,
> -                        flow->tp_dst, cr->wc.tp_dst_mask);
> +                        flow->tp_dst, cr->wc.masks.tp_dst);
>          } else if (flow->nw_proto == IPPROTO_UDP) {
>              nxm_put_16m(b, oxm ? OXM_OF_UDP_SRC : NXM_OF_UDP_SRC,
> -                        flow->tp_src, cr->wc.tp_src_mask);
> +                        flow->tp_src, cr->wc.masks.tp_src);
>              nxm_put_16m(b, oxm ? OXM_OF_UDP_DST : NXM_OF_UDP_DST,
> -                        flow->tp_dst, cr->wc.tp_dst_mask);
> +                        flow->tp_dst, cr->wc.masks.tp_dst);
>          } else if (flow->nw_proto == icmp_proto) {
> -            if (cr->wc.tp_src_mask) {
> +            if (cr->wc.masks.tp_src) {
>                  nxm_put_8(b, icmp_type, ntohs(flow->tp_src));
>              }
> -            if (cr->wc.tp_dst_mask) {
> +            if (cr->wc.masks.tp_dst) {
>                  nxm_put_8(b, icmp_code, ntohs(flow->tp_dst));
>              }
>          }
> @@ -494,7 +494,7 @@ nx_put_match(struct ofpbuf *b, bool oxm, const struct cls_rule *cr,
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
>      /* Metadata. */
> -    if (cr->wc.in_port_mask) {
> +    if (cr->wc.masks.in_port) {
>          uint16_t in_port = flow->in_port;
>          if (oxm) {
>              nxm_put_32(b, OXM_OF_IN_PORT, ofputil_port_to_ofp11(in_port));
> @@ -505,82 +505,82 @@ nx_put_match(struct ofpbuf *b, bool oxm, const struct cls_rule *cr,
>
>      /* Ethernet. */
>      nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_SRC : NXM_OF_ETH_SRC,
> -                       flow->dl_src, cr->wc.dl_src_mask);
> +                       flow->dl_src, cr->wc.masks.dl_src);
>      nxm_put_eth_masked(b, oxm ? OXM_OF_ETH_DST : NXM_OF_ETH_DST,
> -                       flow->dl_dst, cr->wc.dl_dst_mask);
> +                       flow->dl_dst, cr->wc.masks.dl_dst);
>      nxm_put_16m(b, oxm ? OXM_OF_ETH_TYPE : NXM_OF_ETH_TYPE,
>                  ofputil_dl_type_to_openflow(flow->dl_type),
> -                cr->wc.dl_type_mask);
> +                cr->wc.masks.dl_type);
>
>      /* 802.1Q.
>       *
>       * XXX missing OXM support */
> -    nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.vlan_tci_mask);
> +    nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.masks.vlan_tci);
>
>      /* L3. */
>      if (flow->dl_type == htons(ETH_TYPE_IP)) {
>          /* IP. */
>          nxm_put_32m(b, oxm ? OXM_OF_IPV4_SRC : NXM_OF_IP_SRC,
> -                    flow->nw_src, cr->wc.nw_src_mask);
> +                    flow->nw_src, cr->wc.masks.nw_src);
>          nxm_put_32m(b, oxm ? OXM_OF_IPV4_DST : NXM_OF_IP_DST,
> -                    flow->nw_dst, cr->wc.nw_dst_mask);
> +                    flow->nw_dst, cr->wc.masks.nw_dst);
>          nxm_put_ip(b, cr, IPPROTO_ICMP,
>                     oxm ? OXM_OF_ICMPV4_TYPE : NXM_OF_ICMP_TYPE,
>                     oxm ? OXM_OF_ICMPV4_CODE : NXM_OF_ICMP_CODE, oxm);
>      } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
>          /* IPv6. */
>          nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_SRC : NXM_NX_IPV6_SRC,
> -                     &flow->ipv6_src, &cr->wc.ipv6_src_mask);
> +                     &flow->ipv6_src, &cr->wc.masks.ipv6_src);
>          nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_DST : NXM_NX_IPV6_DST,
> -                     &flow->ipv6_dst, &cr->wc.ipv6_dst_mask);
> +                     &flow->ipv6_dst, &cr->wc.masks.ipv6_dst);
>          nxm_put_ip(b, cr, IPPROTO_ICMPV6,
>                     oxm ? OXM_OF_ICMPV6_TYPE : NXM_NX_ICMPV6_TYPE,
>                     oxm ? OXM_OF_ICMPV6_CODE : NXM_NX_ICMPV6_CODE, oxm);
>
>          nxm_put_32m(b, oxm ? OXM_OF_IPV6_FLABEL : NXM_NX_IPV6_LABEL,
> -                    flow->ipv6_label, cr->wc.ipv6_label_mask);
> +                    flow->ipv6_label, cr->wc.masks.ipv6_label);
>
>          if (flow->nw_proto == IPPROTO_ICMPV6
>              && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
>                  flow->tp_src == htons(ND_NEIGHBOR_ADVERT))) {
>              nxm_put_ipv6(b, oxm ? OXM_OF_IPV6_ND_TARGET : NXM_NX_ND_TARGET,
> -                         &flow->nd_target, &cr->wc.nd_target_mask);
> +                         &flow->nd_target, &cr->wc.masks.nd_target);
>              if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
>                  nxm_put_eth_masked(b, oxm ? OXM_OF_IPV6_ND_SLL : NXM_NX_ND_SLL,
> -                                   flow->arp_sha, cr->wc.arp_sha_mask);
> +                                   flow->arp_sha, cr->wc.masks.arp_sha);
>              }
>              if (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
>                  nxm_put_eth_masked(b, oxm ? OXM_OF_IPV6_ND_TLL : NXM_NX_ND_TLL,
> -                                   flow->arp_tha, cr->wc.arp_tha_mask);
> +                                   flow->arp_tha, cr->wc.masks.arp_tha);
>              }
>          }
>      } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
>          /* ARP. */
> -        if (cr->wc.nw_proto_mask) {
> +        if (cr->wc.masks.nw_proto) {
>              nxm_put_16(b, oxm ? OXM_OF_ARP_OP : NXM_OF_ARP_OP,
>                         htons(flow->nw_proto));
>          }
>          nxm_put_32m(b, oxm ? OXM_OF_ARP_SPA : NXM_OF_ARP_SPA,
> -                    flow->nw_src, cr->wc.nw_src_mask);
> +                    flow->nw_src, cr->wc.masks.nw_src);
>          nxm_put_32m(b, oxm ? OXM_OF_ARP_TPA : NXM_OF_ARP_TPA,
> -                    flow->nw_dst, cr->wc.nw_dst_mask);
> +                    flow->nw_dst, cr->wc.masks.nw_dst);
>          nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_SHA : NXM_NX_ARP_SHA,
> -                           flow->arp_sha, cr->wc.arp_sha_mask);
> +                           flow->arp_sha, cr->wc.masks.arp_sha);
>          nxm_put_eth_masked(b, oxm ? OXM_OF_ARP_THA : NXM_NX_ARP_THA,
> -                           flow->arp_tha, cr->wc.arp_tha_mask);
> +                           flow->arp_tha, cr->wc.masks.arp_tha);
>      }
>
>      /* Tunnel ID. */
> -    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.tun_id_mask);
> +    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, cr->wc.masks.tun_id);
>
>      /* Registers. */
>      for (i = 0; i < FLOW_N_REGS; i++) {
>          nxm_put_32m(b, NXM_NX_REG(i),
> -                    htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i]));
> +                    htonl(flow->regs[i]), htonl(cr->wc.masks.regs[i]));
>      }
>
>      /* OpenFlow 1.1+ Metadata. */
> -    nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, cr->wc.metadata_mask);
> +    nxm_put_64m(b, OXM_OF_METADATA, flow->metadata, cr->wc.masks.metadata);
>
>      /* Cookie. */
>      nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index d7e383b..aa3525b 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -89,42 +89,44 @@ ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
>      flow_wildcards_init_catchall(wc);
>
>      if (!(ofpfw & OFPFW10_IN_PORT)) {
> -        wc->in_port_mask = UINT16_MAX;
> +        wc->masks.in_port = UINT16_MAX;
>      }
>
>      if (!(ofpfw & OFPFW10_NW_TOS)) {
> -        wc->nw_tos_mask |= IP_DSCP_MASK;
> +        wc->masks.nw_tos |= IP_DSCP_MASK;
>      }
>
>      if (!(ofpfw & OFPFW10_NW_PROTO)) {
> -        wc->nw_proto_mask = UINT8_MAX;
> +        wc->masks.nw_proto = UINT8_MAX;
>      }
> -    wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_SRC_SHIFT);
> -    wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_DST_SHIFT);
> +    wc->masks.nw_src = ofputil_wcbits_to_netmask(ofpfw
> +                                                 >> OFPFW10_NW_SRC_SHIFT);
> +    wc->masks.nw_dst = ofputil_wcbits_to_netmask(ofpfw
> +                                                 >> OFPFW10_NW_DST_SHIFT);
>
>      if (!(ofpfw & OFPFW10_TP_SRC)) {
> -        wc->tp_src_mask = htons(UINT16_MAX);
> +        wc->masks.tp_src = htons(UINT16_MAX);
>      }
>      if (!(ofpfw & OFPFW10_TP_DST)) {
> -        wc->tp_dst_mask = htons(UINT16_MAX);
> +        wc->masks.tp_dst = htons(UINT16_MAX);
>      }
>
>      if (!(ofpfw & OFPFW10_DL_SRC)) {
> -        memset(wc->dl_src_mask, 0xff, ETH_ADDR_LEN);
> +        memset(wc->masks.dl_src, 0xff, ETH_ADDR_LEN);
>      }
>      if (!(ofpfw & OFPFW10_DL_DST)) {
> -        memset(wc->dl_dst_mask, 0xff, ETH_ADDR_LEN);
> +        memset(wc->masks.dl_dst, 0xff, ETH_ADDR_LEN);
>      }
>      if (!(ofpfw & OFPFW10_DL_TYPE)) {
> -        wc->dl_type_mask = htons(UINT16_MAX);
> +        wc->masks.dl_type = htons(UINT16_MAX);
>      }
>
>      /* VLAN TCI mask. */
>      if (!(ofpfw & OFPFW10_DL_VLAN_PCP)) {
> -        wc->vlan_tci_mask |= htons(VLAN_PCP_MASK | VLAN_CFI);
> +        wc->masks.vlan_tci |= htons(VLAN_PCP_MASK | VLAN_CFI);
>      }
>      if (!(ofpfw & OFPFW10_DL_VLAN)) {
> -        wc->vlan_tci_mask |= htons(VLAN_VID_MASK | VLAN_CFI);
> +        wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
>      }
>  }
>
> @@ -165,14 +167,14 @@ ofputil_cls_rule_from_ofp10_match(const struct ofp10_match *match,
>           * However, older versions of OVS treated this as matching packets
>           * withut an 802.1Q header, so we do here too. */
>          rule->flow.vlan_tci = htons(0);
> -        rule->wc.vlan_tci_mask = htons(0xffff);
> +        rule->wc.masks.vlan_tci = htons(0xffff);
>      } else {
>          ovs_be16 vid, pcp, tci;
>
>          vid = match->dl_vlan & htons(VLAN_VID_MASK);
>          pcp = htons((match->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
>          tci = vid | pcp | htons(VLAN_CFI);
> -        rule->flow.vlan_tci = tci & rule->wc.vlan_tci_mask;
> +        rule->flow.vlan_tci = tci & rule->wc.masks.vlan_tci;
>      }
>
>      /* Clean up. */
> @@ -189,52 +191,52 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule,
>
>      /* Figure out most OpenFlow wildcards. */
>      ofpfw = 0;
> -    if (!wc->in_port_mask) {
> +    if (!wc->masks.in_port) {
>          ofpfw |= OFPFW10_IN_PORT;
>      }
> -    if (!wc->dl_type_mask) {
> +    if (!wc->masks.dl_type) {
>          ofpfw |= OFPFW10_DL_TYPE;
>      }
> -    if (!wc->nw_proto_mask) {
> +    if (!wc->masks.nw_proto) {
>          ofpfw |= OFPFW10_NW_PROTO;
>      }
> -    ofpfw |= (ofputil_netmask_to_wcbits(wc->nw_src_mask)
> +    ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_src)
>                << OFPFW10_NW_SRC_SHIFT);
> -    ofpfw |= (ofputil_netmask_to_wcbits(wc->nw_dst_mask)
> +    ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_dst)
>                << OFPFW10_NW_DST_SHIFT);
> -    if (!(wc->nw_tos_mask & IP_DSCP_MASK)) {
> +    if (!(wc->masks.nw_tos & IP_DSCP_MASK)) {
>          ofpfw |= OFPFW10_NW_TOS;
>      }
> -    if (!wc->tp_src_mask) {
> +    if (!wc->masks.tp_src) {
>          ofpfw |= OFPFW10_TP_SRC;
>      }
> -    if (!wc->tp_dst_mask) {
> +    if (!wc->masks.tp_dst) {
>          ofpfw |= OFPFW10_TP_DST;
>      }
> -    if (eth_addr_is_zero(wc->dl_src_mask)) {
> +    if (eth_addr_is_zero(wc->masks.dl_src)) {
>          ofpfw |= OFPFW10_DL_SRC;
>      }
> -    if (eth_addr_is_zero(wc->dl_dst_mask)) {
> +    if (eth_addr_is_zero(wc->masks.dl_dst)) {
>          ofpfw |= OFPFW10_DL_DST;
>      }
>
>      /* Translate VLANs. */
>      match->dl_vlan = htons(0);
>      match->dl_vlan_pcp = 0;
> -    if (rule->wc.vlan_tci_mask == htons(0)) {
> +    if (rule->wc.masks.vlan_tci == htons(0)) {
>          ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP;
> -    } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI)
> +    } else if (rule->wc.masks.vlan_tci & htons(VLAN_CFI)
>                 && !(rule->flow.vlan_tci & htons(VLAN_CFI))) {
>          match->dl_vlan = htons(OFP10_VLAN_NONE);
>          ofpfw |= OFPFW10_DL_VLAN_PCP;
>      } else {
> -        if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) {
> +        if (!(rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
>              ofpfw |= OFPFW10_DL_VLAN;
>          } else {
>              match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci));
>          }
>
> -        if (!(rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK))) {
> +        if (!(rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
>              ofpfw |= OFPFW10_DL_VLAN_PCP;
>          } else {
>              match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci);
> @@ -297,16 +299,16 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
>          if (match->dl_vlan == htons(OFPVID11_NONE)) {
>              /* Match only packets without a VLAN tag. */
>              rule->flow.vlan_tci = htons(0);
> -            rule->wc.vlan_tci_mask = htons(UINT16_MAX);
> +            rule->wc.masks.vlan_tci = htons(UINT16_MAX);
>          } else {
>              if (match->dl_vlan == htons(OFPVID11_ANY)) {
>                  /* Match any packet with a VLAN tag regardless of VID. */
>                  rule->flow.vlan_tci = htons(VLAN_CFI);
> -                rule->wc.vlan_tci_mask = htons(VLAN_CFI);
> +                rule->wc.masks.vlan_tci = htons(VLAN_CFI);
>              } else if (ntohs(match->dl_vlan) < 4096) {
>                  /* Match only packets with the specified VLAN VID. */
>                  rule->flow.vlan_tci = htons(VLAN_CFI) | match->dl_vlan;
> -                rule->wc.vlan_tci_mask = htons(VLAN_CFI | VLAN_VID_MASK);
> +                rule->wc.masks.vlan_tci = htons(VLAN_CFI | VLAN_VID_MASK);
>              } else {
>                  /* Invalid VID. */
>                  return OFPERR_OFPBMC_BAD_VALUE;
> @@ -316,7 +318,7 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
>                  if (match->dl_vlan_pcp <= 7) {
>                      rule->flow.vlan_tci |= htons(match->dl_vlan_pcp
>                                                   << VLAN_PCP_SHIFT);
> -                    rule->wc.vlan_tci_mask |= htons(VLAN_PCP_MASK);
> +                    rule->wc.masks.vlan_tci |= htons(VLAN_PCP_MASK);
>                  } else {
>                      /* Invalid PCP. */
>                      return OFPERR_OFPBMC_BAD_VALUE;
> @@ -430,7 +432,7 @@ ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
>      match->omh.type = htons(OFPMT_STANDARD);
>      match->omh.length = htons(OFPMT11_STANDARD_LENGTH);
>
> -    if (!rule->wc.in_port_mask) {
> +    if (!rule->wc.masks.in_port) {
>          wc |= OFPFW11_IN_PORT;
>      } else {
>          match->in_port = ofputil_port_to_ofp11(rule->flow.in_port);
> @@ -438,64 +440,64 @@ ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
>
>      memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
>      for (i = 0; i < ETH_ADDR_LEN; i++) {
> -        match->dl_src_mask[i] = ~rule->wc.dl_src_mask[i];
> +        match->dl_src_mask[i] = ~rule->wc.masks.dl_src[i];
>      }
>
>      memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
>      for (i = 0; i < ETH_ADDR_LEN; i++) {
> -        match->dl_dst_mask[i] = ~rule->wc.dl_dst_mask[i];
> +        match->dl_dst_mask[i] = ~rule->wc.masks.dl_dst[i];
>      }
>
> -    if (rule->wc.vlan_tci_mask == htons(0)) {
> +    if (rule->wc.masks.vlan_tci == htons(0)) {
>          wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
> -    } else if (rule->wc.vlan_tci_mask & htons(VLAN_CFI)
> +    } else if (rule->wc.masks.vlan_tci & htons(VLAN_CFI)
>                 && !(rule->flow.vlan_tci & htons(VLAN_CFI))) {
>          match->dl_vlan = htons(OFPVID11_NONE);
>          wc |= OFPFW11_DL_VLAN_PCP;
>      } else {
> -        if (!(rule->wc.vlan_tci_mask & htons(VLAN_VID_MASK))) {
> +        if (!(rule->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
>              match->dl_vlan = htons(OFPVID11_ANY);
>          } else {
>              match->dl_vlan = htons(vlan_tci_to_vid(rule->flow.vlan_tci));
>          }
>
> -        if (!(rule->wc.vlan_tci_mask & htons(VLAN_PCP_MASK))) {
> +        if (!(rule->wc.masks.vlan_tci & htons(VLAN_PCP_MASK))) {
>              wc |= OFPFW11_DL_VLAN_PCP;
>          } else {
>              match->dl_vlan_pcp = vlan_tci_to_pcp(rule->flow.vlan_tci);
>          }
>      }
>
> -    if (!rule->wc.dl_type_mask) {
> +    if (!rule->wc.masks.dl_type) {
>          wc |= OFPFW11_DL_TYPE;
>      } else {
>          match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
>      }
>
> -    if (!(rule->wc.nw_tos_mask & IP_DSCP_MASK)) {
> +    if (!(rule->wc.masks.nw_tos & IP_DSCP_MASK)) {
>          wc |= OFPFW11_NW_TOS;
>      } else {
>          match->nw_tos = rule->flow.nw_tos & IP_DSCP_MASK;
>      }
>
> -    if (!rule->wc.nw_proto_mask) {
> +    if (!rule->wc.masks.nw_proto) {
>          wc |= OFPFW11_NW_PROTO;
>      } else {
>          match->nw_proto = rule->flow.nw_proto;
>      }
>
>      match->nw_src = rule->flow.nw_src;
> -    match->nw_src_mask = ~rule->wc.nw_src_mask;
> +    match->nw_src_mask = ~rule->wc.masks.nw_src;
>      match->nw_dst = rule->flow.nw_dst;
> -    match->nw_dst_mask = ~rule->wc.nw_dst_mask;
> +    match->nw_dst_mask = ~rule->wc.masks.nw_dst;
>
> -    if (!rule->wc.tp_src_mask) {
> +    if (!rule->wc.masks.tp_src) {
>          wc |= OFPFW11_TP_SRC;
>      } else {
>          match->tp_src = rule->flow.tp_src;
>      }
>
> -    if (!rule->wc.tp_dst_mask) {
> +    if (!rule->wc.masks.tp_dst) {
>          wc |= OFPFW11_TP_DST;
>      } else {
>          match->tp_dst = rule->flow.tp_dst;
> @@ -506,7 +508,7 @@ ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
>      wc |= OFPFW11_MPLS_TC;
>
>      match->metadata = rule->flow.metadata;
> -    match->metadata_mask = ~rule->wc.metadata_mask;
> +    match->metadata_mask = ~rule->wc.masks.metadata;
>
>      match->wildcards = htonl(wc);
>  }
> @@ -1439,7 +1441,7 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
>      int i;
>
>      for (i = 0; i < FLOW_N_REGS; i++) {
> -        if (wc->reg_masks[i] != 0) {
> +        if (wc->masks.regs[i] != 0) {
>              return false;
>          }
>      }
> @@ -1458,23 +1460,23 @@ ofputil_usable_protocols(const struct cls_rule *rule)
>      BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
>
>      /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
> -    if (!eth_mask_is_exact(wc->dl_src_mask)
> -        && !eth_addr_is_zero(wc->dl_src_mask)) {
> +    if (!eth_mask_is_exact(wc->masks.dl_src)
> +        && !eth_addr_is_zero(wc->masks.dl_src)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
> -    if (!eth_mask_is_exact(wc->dl_dst_mask)
> -        && !eth_addr_is_zero(wc->dl_dst_mask)) {
> +    if (!eth_mask_is_exact(wc->masks.dl_dst)
> +        && !eth_addr_is_zero(wc->masks.dl_dst)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* NXM and OF1.1+ support matching metadata. */
> -    if (wc->metadata_mask != htonll(0)) {
> +    if (wc->masks.metadata != htonll(0)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports matching ARP hardware addresses. */
> -    if (!eth_addr_is_zero(wc->arp_sha_mask) ||
> -        !eth_addr_is_zero(wc->arp_tha_mask)) {
> +    if (!eth_addr_is_zero(wc->masks.arp_sha) ||
> +        !eth_addr_is_zero(wc->masks.arp_tha)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
> @@ -1489,38 +1491,38 @@ ofputil_usable_protocols(const struct cls_rule *rule)
>      }
>
>      /* Only NXM supports matching tun_id. */
> -    if (wc->tun_id_mask != htonll(0)) {
> +    if (wc->masks.tun_id != htonll(0)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports matching fragments. */
> -    if (wc->nw_frag_mask) {
> +    if (wc->masks.nw_frag) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports matching IPv6 flow label. */
> -    if (wc->ipv6_label_mask) {
> +    if (wc->masks.ipv6_label) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports matching IP ECN bits. */
> -    if (wc->nw_tos_mask & IP_ECN_MASK) {
> +    if (wc->masks.nw_tos & IP_ECN_MASK) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports matching IP TTL/hop limit. */
> -    if (wc->nw_ttl_mask) {
> +    if (wc->masks.nw_ttl) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports non-CIDR IPv4 address masks. */
> -    if (!ip_is_cidr(wc->nw_src_mask) || !ip_is_cidr(wc->nw_dst_mask)) {
> +    if (!ip_is_cidr(wc->masks.nw_src) || !ip_is_cidr(wc->masks.nw_dst)) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
>      /* Only NXM supports bitwise matching on transport port. */
> -    if ((wc->tp_src_mask && wc->tp_src_mask != htons(UINT16_MAX)) ||
> -        (wc->tp_dst_mask && wc->tp_dst_mask != htons(UINT16_MAX))) {
> +    if ((wc->masks.tp_src && wc->masks.tp_src != htons(UINT16_MAX)) ||
> +        (wc->masks.tp_dst && wc->masks.tp_dst != htons(UINT16_MAX))) {
>          return OFPUTIL_P_NXM_ANY;
>      }
>
> @@ -2405,13 +2407,13 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
>          pin->fmd.in_port = rule.flow.in_port;
>
>          pin->fmd.tun_id = rule.flow.tun_id;
> -        pin->fmd.tun_id_mask = rule.wc.tun_id_mask;
> +        pin->fmd.tun_id_mask = rule.wc.masks.tun_id;
>
>          pin->fmd.metadata = rule.flow.metadata;
> -        pin->fmd.metadata_mask = rule.wc.metadata_mask;
> +        pin->fmd.metadata_mask = rule.wc.masks.metadata;
>
>          memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs);
> -        memcpy(pin->fmd.reg_masks, rule.wc.reg_masks,
> +        memcpy(pin->fmd.reg_masks, rule.wc.masks.regs,
>                 sizeof pin->fmd.reg_masks);
>
>          pin->buffer_id = ntohl(npi->buffer_id);
> @@ -4087,30 +4089,30 @@ ofputil_normalize_rule(struct cls_rule *rule)
>      /* Clear the fields that may not be matched. */
>      wc = rule->wc;
>      if (!(may_match & MAY_NW_ADDR)) {
> -        wc.nw_src_mask = wc.nw_dst_mask = htonl(0);
> +        wc.masks.nw_src = wc.masks.nw_dst = htonl(0);
>      }
>      if (!(may_match & MAY_TP_ADDR)) {
> -        wc.tp_src_mask = wc.tp_dst_mask = htons(0);
> +        wc.masks.tp_src = wc.masks.tp_dst = htons(0);
>      }
>      if (!(may_match & MAY_NW_PROTO)) {
> -        wc.nw_proto_mask = 0;
> +        wc.masks.nw_proto = 0;
>      }
>      if (!(may_match & MAY_IPVx)) {
> -        wc.nw_tos_mask = 0;
> -        wc.nw_ttl_mask = 0;
> +        wc.masks.nw_tos = 0;
> +        wc.masks.nw_ttl = 0;
>      }
>      if (!(may_match & MAY_ARP_SHA)) {
> -        memset(wc.arp_sha_mask, 0, ETH_ADDR_LEN);
> +        memset(wc.masks.arp_sha, 0, ETH_ADDR_LEN);
>      }
>      if (!(may_match & MAY_ARP_THA)) {
> -        memset(wc.arp_tha_mask, 0, ETH_ADDR_LEN);
> +        memset(wc.masks.arp_tha, 0, ETH_ADDR_LEN);
>      }
>      if (!(may_match & MAY_IPV6)) {
> -        wc.ipv6_src_mask = wc.ipv6_dst_mask = in6addr_any;
> -        wc.ipv6_label_mask = htonl(0);
> +        wc.masks.ipv6_src = wc.masks.ipv6_dst = in6addr_any;
> +        wc.masks.ipv6_label = htonl(0);
>      }
>      if (!(may_match & MAY_ND_TARGET)) {
> -        wc.nd_target_mask = in6addr_any;
> +        wc.masks.nd_target = in6addr_any;
>      }
>
>      /* Log any changes. */
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 17131ca..73b2efb 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -3989,7 +3989,7 @@ ofopgroup_complete(struct ofopgroup *group)
>          case OFOPERATION_ADD:
>              if (!op->error) {
>                  ofproto_rule_destroy__(op->victim);
> -                if ((rule->cr.wc.vlan_tci_mask & htons(VLAN_VID_MASK))
> +                if ((rule->cr.wc.masks.vlan_tci & htons(VLAN_VID_MASK))
>                      == htons(VLAN_VID_MASK)) {
>                      if (ofproto->vlan_bitmap) {
>                          uint16_t vid = vlan_tci_to_vid(rule->cr.flow.vlan_tci);
> @@ -4643,7 +4643,7 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
>          const struct cls_table *table;
>
>          HMAP_FOR_EACH (table, hmap_node, &oftable->cls.tables) {
> -            if ((table->wc.vlan_tci_mask & htons(VLAN_VID_MASK))
> +            if ((table->wc.masks.vlan_tci & htons(VLAN_VID_MASK))
>                  == htons(VLAN_VID_MASK)) {
>                  const struct cls_rule *rule;
>
> diff --git a/tests/test-classifier.c b/tests/test-classifier.c
> index da72d91..ae1d81f 100644
> --- a/tests/test-classifier.c
> +++ b/tests/test-classifier.c
> @@ -188,39 +188,44 @@ match(const struct cls_rule *wild, const struct flow *fixed)
>          bool eq;
>
>          if (f_idx == CLS_F_IDX_NW_SRC) {
> -            eq = !((fixed->nw_src ^ wild->flow.nw_src) & wild->wc.nw_src_mask);
> +            eq = !((fixed->nw_src ^ wild->flow.nw_src)
> +                   & wild->wc.masks.nw_src);
>          } else if (f_idx == CLS_F_IDX_NW_DST) {
> -            eq = !((fixed->nw_dst ^ wild->flow.nw_dst) & wild->wc.nw_dst_mask);
> +            eq = !((fixed->nw_dst ^ wild->flow.nw_dst)
> +                   & wild->wc.masks.nw_dst);
>          } else if (f_idx == CLS_F_IDX_TP_SRC) {
> -            eq = !((fixed->tp_src ^ wild->flow.tp_src) & wild->wc.tp_src_mask);
> +            eq = !((fixed->tp_src ^ wild->flow.tp_src)
> +                   & wild->wc.masks.tp_src);
>          } else if (f_idx == CLS_F_IDX_TP_DST) {
> -            eq = !((fixed->tp_dst ^ wild->flow.tp_dst) & wild->wc.tp_dst_mask);
> +            eq = !((fixed->tp_dst ^ wild->flow.tp_dst)
> +                   & wild->wc.masks.tp_dst);
>          } else if (f_idx == CLS_F_IDX_DL_SRC) {
>              eq = eth_addr_equal_except(fixed->dl_src, wild->flow.dl_src,
> -                                       wild->wc.dl_src_mask);
> +                                       wild->wc.masks.dl_src);
>          } else if (f_idx == CLS_F_IDX_DL_DST) {
>              eq = eth_addr_equal_except(fixed->dl_dst, wild->flow.dl_dst,
> -                                       wild->wc.dl_dst_mask);
> +                                       wild->wc.masks.dl_dst);
>          } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
>              eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci)
> -                   & wild->wc.vlan_tci_mask);
> +                   & wild->wc.masks.vlan_tci);
>          } else if (f_idx == CLS_F_IDX_TUN_ID) {
> -            eq = !((fixed->tun_id ^ wild->flow.tun_id) & wild->wc.tun_id_mask);
> +            eq = !((fixed->tun_id ^ wild->flow.tun_id)
> +                   & wild->wc.masks.tun_id);
>          } else if (f_idx == CLS_F_IDX_METADATA) {
>              eq = !((fixed->metadata ^ wild->flow.metadata)
> -                   & wild->wc.metadata_mask);
> +                   & wild->wc.masks.metadata);
>          } else if (f_idx == CLS_F_IDX_NW_DSCP) {
>              eq = !((fixed->nw_tos ^ wild->flow.nw_tos) &
> -                   (wild->wc.nw_tos_mask & IP_DSCP_MASK));
> +                   (wild->wc.masks.nw_tos & IP_DSCP_MASK));
>          } else if (f_idx == CLS_F_IDX_NW_PROTO) {
>              eq = !((fixed->nw_proto ^ wild->flow.nw_proto)
> -                   & wild->wc.nw_proto_mask);
> +                   & wild->wc.masks.nw_proto);
>          } else if (f_idx == CLS_F_IDX_DL_TYPE) {
>              eq = !((fixed->dl_type ^ wild->flow.dl_type)
> -                   & wild->wc.dl_type_mask);
> +                   & wild->wc.masks.dl_type);
>          } else if (f_idx == CLS_F_IDX_IN_PORT) {
>              eq = !((fixed->in_port ^ wild->flow.in_port)
> -                   & wild->wc.in_port_mask);
> +                   & wild->wc.masks.in_port);
>          } else {
>              NOT_REACHED();
>          }
> @@ -483,31 +488,31 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
>                 values[f_idx][value_idx], f->len);
>
>          if (f_idx == CLS_F_IDX_NW_SRC) {
> -            rule->cls_rule.wc.nw_src_mask = htonl(UINT32_MAX);
> +            rule->cls_rule.wc.masks.nw_src = htonl(UINT32_MAX);
>          } else if (f_idx == CLS_F_IDX_NW_DST) {
> -            rule->cls_rule.wc.nw_dst_mask = htonl(UINT32_MAX);
> +            rule->cls_rule.wc.masks.nw_dst = htonl(UINT32_MAX);
>          } else if (f_idx == CLS_F_IDX_TP_SRC) {
> -            rule->cls_rule.wc.tp_src_mask = htons(UINT16_MAX);
> +            rule->cls_rule.wc.masks.tp_src = htons(UINT16_MAX);
>          } else if (f_idx == CLS_F_IDX_TP_DST) {
> -            rule->cls_rule.wc.tp_dst_mask = htons(UINT16_MAX);
> +            rule->cls_rule.wc.masks.tp_dst = htons(UINT16_MAX);
>          } else if (f_idx == CLS_F_IDX_DL_SRC) {
> -            memset(rule->cls_rule.wc.dl_src_mask, 0xff, ETH_ADDR_LEN);
> +            memset(rule->cls_rule.wc.masks.dl_src, 0xff, ETH_ADDR_LEN);
>          } else if (f_idx == CLS_F_IDX_DL_DST) {
> -            memset(rule->cls_rule.wc.dl_dst_mask, 0xff, ETH_ADDR_LEN);
> +            memset(rule->cls_rule.wc.masks.dl_dst, 0xff, ETH_ADDR_LEN);
>          } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
> -            rule->cls_rule.wc.vlan_tci_mask = htons(UINT16_MAX);
> +            rule->cls_rule.wc.masks.vlan_tci = htons(UINT16_MAX);
>          } else if (f_idx == CLS_F_IDX_TUN_ID) {
> -            rule->cls_rule.wc.tun_id_mask = htonll(UINT64_MAX);
> +            rule->cls_rule.wc.masks.tun_id = htonll(UINT64_MAX);
>          } else if (f_idx == CLS_F_IDX_METADATA) {
> -            rule->cls_rule.wc.metadata_mask = htonll(UINT64_MAX);
> +            rule->cls_rule.wc.masks.metadata = htonll(UINT64_MAX);
>          } else if (f_idx == CLS_F_IDX_NW_DSCP) {
> -            rule->cls_rule.wc.nw_tos_mask |= IP_DSCP_MASK;
> +            rule->cls_rule.wc.masks.nw_tos |= IP_DSCP_MASK;
>          } else if (f_idx == CLS_F_IDX_NW_PROTO) {
> -            rule->cls_rule.wc.nw_proto_mask = UINT8_MAX;
> +            rule->cls_rule.wc.masks.nw_proto = UINT8_MAX;
>          } else if (f_idx == CLS_F_IDX_DL_TYPE) {
> -            rule->cls_rule.wc.dl_type_mask = htons(UINT16_MAX);
> +            rule->cls_rule.wc.masks.dl_type = htons(UINT16_MAX);
>          } else if (f_idx == CLS_F_IDX_IN_PORT) {
> -            rule->cls_rule.wc.in_port_mask = UINT16_MAX;
> +            rule->cls_rule.wc.masks.in_port = UINT16_MAX;
>          } else {
>              NOT_REACHED();
>          }
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index e5c5255..afaef13 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -2553,7 +2553,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
>
>      cls_rule_init_catchall(&rule, OFP_DEFAULT_PRIORITY);
>      rule.flow.vlan_tci = htons(strtoul(argv[1], NULL, 16));
> -    rule.wc.vlan_tci_mask = htons(strtoul(argv[2], NULL, 16));
> +    rule.wc.masks.vlan_tci = htons(strtoul(argv[2], NULL, 16));
>
>      /* Convert to and from string. */
>      string_s = cls_rule_to_string(&rule);
> @@ -2562,7 +2562,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
>      parse_ofp_str(&fm, -1, string_s, false);
>      printf("%04"PRIx16"/%04"PRIx16"\n",
>             ntohs(fm.cr.flow.vlan_tci),
> -           ntohs(fm.cr.wc.vlan_tci_mask));
> +           ntohs(fm.cr.wc.masks.vlan_tci));
>
>      /* Convert to and from NXM. */
>      ofpbuf_init(&nxm, 0);
> @@ -2575,7 +2575,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
>      } else {
>          printf("%04"PRIx16"/%04"PRIx16"\n",
>                 ntohs(nxm_rule.flow.vlan_tci),
> -               ntohs(nxm_rule.wc.vlan_tci_mask));
> +               ntohs(nxm_rule.wc.masks.vlan_tci));
>      }
>      free(nxm_s);
>      ofpbuf_uninit(&nxm);
> @@ -2589,7 +2589,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
>             of10_match.dl_vlan_pcp,
>             (of10_match.wildcards & htonl(OFPFW10_DL_VLAN_PCP)) != 0,
>             ntohs(of10_rule.flow.vlan_tci),
> -           ntohs(of10_rule.wc.vlan_tci_mask));
> +           ntohs(of10_rule.wc.masks.vlan_tci));
>
>      /* Convert to and from OpenFlow 1.1. */
>      ofputil_cls_rule_to_ofp11_match(&rule, &of11_match);
> @@ -2600,7 +2600,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
>             of11_match.dl_vlan_pcp,
>             (of11_match.wildcards & htonl(OFPFW11_DL_VLAN_PCP)) != 0,
>             ntohs(of11_rule.flow.vlan_tci),
> -           ntohs(of11_rule.wc.vlan_tci_mask));
> +           ntohs(of11_rule.wc.masks.vlan_tci));
>  }
>
>  /* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
> --
> 1.7.2.5
>



More information about the dev mailing list