flow: Support OF1.5+ (draft) actset_output field.
[cascardo/ovs.git] / lib / meta-flow.c
index c0925e8..ddf0431 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 
 #include "classifier.h"
 #include "dynamic-string.h"
+#include "nx-match.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
 #include "ovs-thread.h"
 
 VLOG_DEFINE_THIS_MODULE(meta_flow);
 
+#define FLOW_U32OFS(FIELD)                                              \
+    offsetof(struct flow, FIELD) % 4 ? -1 : offsetof(struct flow, FIELD) / 4
+
 #define MF_FIELD_SIZES(MEMBER)                  \
     sizeof ((union mf_value *)0)->MEMBER,       \
     8 * sizeof ((union mf_value *)0)->MEMBER
 
-static const struct mf_field mf_fields[MFF_N_IDS] = {
-    /* ## -------- ## */
-    /* ## metadata ## */
-    /* ## -------- ## */
-
-    {
-        MFF_TUN_ID, "tun_id", NULL,
-        MF_FIELD_SIZES(be64),
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        true,
-        NXM_NX_TUN_ID, "NXM_NX_TUN_ID",
-        OXM_OF_TUNNEL_ID, "OXM_OF_TUNNEL_ID",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_TUN_SRC, "tun_src", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_NONE,
-        true,
-        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
-        NXM_NX_TUN_IPV4_SRC, "NXM_NX_TUN_IPV4_SRC",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_TUN_DST, "tun_dst", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_NONE,
-        true,
-        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
-        NXM_NX_TUN_IPV4_DST, "NXM_NX_TUN_IPV4_DST",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_TUN_FLAGS, "tun_flags", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_NONE,
-        MFS_TNL_FLAGS,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_TUN_TTL, "tun_ttl", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_TUN_TOS, "tun_tos", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_METADATA, "metadata", NULL,
-        MF_FIELD_SIZES(be64),
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        true,
-        OXM_OF_METADATA, "OXM_OF_METADATA",
-        OXM_OF_METADATA, "OXM_OF_METADATA",
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OF11_UP,
-    }, {
-        MFF_IN_PORT, "in_port", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_NONE,
-        MFS_OFP_PORT,
-        MFP_NONE,
-        true,
-        NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
-        NXM_OF_IN_PORT, "NXM_OF_IN_PORT",
-        OFPUTIL_P_ANY,   /* OF11+ via mapping to 32 bits. */
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IN_PORT_OXM, "in_port_oxm", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_NONE,
-        MFS_OFP_PORT_OXM,
-        MFP_NONE,
-        true,
-        OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
-        OXM_OF_IN_PORT, "OXM_OF_IN_PORT",
-        OFPUTIL_P_OF11_UP,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_SKB_PRIORITY, "skb_priority", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_NONE,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_PKT_MARK, "pkt_mark", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        true,
-        NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK",
-        NXM_NX_PKT_MARK, "NXM_NX_PKT_MARK",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-#define REGISTER(IDX)                           \
-    {                                           \
-        MFF_REG##IDX, "reg" #IDX, NULL,         \
-        MF_FIELD_SIZES(be32),                   \
-        MFM_FULLY,                              \
-        MFS_HEXADECIMAL,                        \
-        MFP_NONE,                               \
-        true,                                   \
-        NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
-        NXM_NX_REG(IDX), "NXM_NX_REG" #IDX,     \
-        OFPUTIL_P_NXM_OXM_ANY,                  \
-        OFPUTIL_P_NXM_OXM_ANY,                  \
-    }
-#if FLOW_N_REGS > 0
-    REGISTER(0),
-#endif
-#if FLOW_N_REGS > 1
-    REGISTER(1),
-#endif
-#if FLOW_N_REGS > 2
-    REGISTER(2),
-#endif
-#if FLOW_N_REGS > 3
-    REGISTER(3),
-#endif
-#if FLOW_N_REGS > 4
-    REGISTER(4),
-#endif
-#if FLOW_N_REGS > 5
-    REGISTER(5),
-#endif
-#if FLOW_N_REGS > 6
-    REGISTER(6),
-#endif
-#if FLOW_N_REGS > 7
-    REGISTER(7),
-#endif
-#if FLOW_N_REGS > 8
-#error
-#endif
-
-    /* ## -- ## */
-    /* ## L2 ## */
-    /* ## -- ## */
-
-    {
-        MFF_ETH_SRC, "eth_src", "dl_src",
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_NONE,
-        true,
-        NXM_OF_ETH_SRC, "NXM_OF_ETH_SRC",
-        OXM_OF_ETH_SRC, "OXM_OF_ETH_SRC",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
-    }, {
-        MFF_ETH_DST, "eth_dst", "dl_dst",
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_NONE,
-        true,
-        NXM_OF_ETH_DST, "NXM_OF_ETH_DST",
-        OXM_OF_ETH_DST, "OXM_OF_ETH_DST",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
-    }, {
-        MFF_ETH_TYPE, "eth_type", "dl_type",
-        MF_FIELD_SIZES(be16),
-        MFM_NONE,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        false,
-        NXM_OF_ETH_TYPE, "NXM_OF_ETH_TYPE",
-        OXM_OF_ETH_TYPE, "OXM_OF_ETH_TYPE",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-    },
-
-    {
-        MFF_VLAN_TCI, "vlan_tci", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        true,
-        NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
-        NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_DL_VLAN, "dl_vlan", NULL,
-        sizeof(ovs_be16), 12,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        true,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_VLAN_VID, "vlan_vid", NULL,
-        sizeof(ovs_be16), 12,
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_NONE,
-        true,
-        OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
-        OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_DL_VLAN_PCP, "dl_vlan_pcp", NULL,
-        1, 3,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        true,
-        0, NULL,
-        0, NULL,
-        OFPUTIL_P_ANY,   /* Will be mapped to NXM and OXM. */
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_VLAN_PCP, "vlan_pcp", NULL,
-        1, 3,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_VLAN_VID,
-        true,
-        OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
-        OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
-        OFPUTIL_P_ANY,   /* Will be mapped to OF10 and NXM. */
-        OFPUTIL_P_NONE,
-    },
-
-    /* ## ---- ## */
-    /* ## L2.5 ## */
-    /* ## ---- ## */
-    {
-        MFF_MPLS_LABEL, "mpls_label", NULL,
-        4, 20,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_MPLS,
-        true,
-        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
-        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_MPLS_TC, "mpls_tc", NULL,
-        1, 3,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_MPLS,
-        true,
-        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
-        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_MPLS_BOS, "mpls_bos", NULL,
-        1, 1,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_MPLS,
-        false,
-        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
-        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-    },
-
-    /* ## -- ## */
-    /* ## L3 ## */
-    /* ## -- ## */
-
-    {
-        MFF_IPV4_SRC, "ip_src", "nw_src",
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_IPV4,
-        true,
-        NXM_OF_IP_SRC, "NXM_OF_IP_SRC",
-        OXM_OF_IPV4_SRC, "OXM_OF_IPV4_SRC",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-    }, {
-        MFF_IPV4_DST, "ip_dst", "nw_dst",
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_IPV4,
-        true,
-        NXM_OF_IP_DST, "NXM_OF_IP_DST",
-        OXM_OF_IPV4_DST, "OXM_OF_IPV4_DST",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-    },
-
-    {
-        MFF_IPV6_SRC, "ipv6_src", NULL,
-        MF_FIELD_SIZES(ipv6),
-        MFM_FULLY,
-        MFS_IPV6,
-        MFP_IPV6,
-        true,
-        NXM_NX_IPV6_SRC, "NXM_NX_IPV6_SRC",
-        OXM_OF_IPV6_SRC, "OXM_OF_IPV6_SRC",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_IPV6_DST, "ipv6_dst", NULL,
-        MF_FIELD_SIZES(ipv6),
-        MFM_FULLY,
-        MFS_IPV6,
-        MFP_IPV6,
-        true,
-        NXM_NX_IPV6_DST, "NXM_NX_IPV6_DST",
-        OXM_OF_IPV6_DST, "OXM_OF_IPV6_DST",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-    {
-        MFF_IPV6_LABEL, "ipv6_label", NULL,
-        4, 20,
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_IPV6,
-        false,
-        NXM_NX_IPV6_LABEL, "NXM_NX_IPV6_LABEL",
-        OXM_OF_IPV6_FLABEL, "OXM_OF_IPV6_FLABEL",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    {
-        MFF_IP_PROTO, "nw_proto", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        false,
-        NXM_OF_IP_PROTO, "NXM_OF_IP_PROTO",
-        OXM_OF_IP_PROTO, "OXM_OF_IP_PROTO",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IP_DSCP, "nw_tos", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        true,
-        NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
-        NXM_OF_IP_TOS, "NXM_OF_IP_TOS",
-        OFPUTIL_P_ANY,   /* Will be shifted for OXM. */
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IP_DSCP_SHIFTED, "nw_tos_shifted", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        true,
-        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
-        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
-        OFPUTIL_P_ANY,   /* Will be shifted for non-OXM. */
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IP_ECN, "nw_ecn", NULL,
-        1, 2,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        true,
-        NXM_NX_IP_ECN, "NXM_NX_IP_ECN",
-        OXM_OF_IP_ECN, "OXM_OF_IP_ECN",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IP_TTL, "nw_ttl", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        true,
-        NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
-        NXM_NX_IP_TTL, "NXM_NX_IP_TTL",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_IP_FRAG, "ip_frag", NULL,
-        1, 2,
-        MFM_FULLY,
-        MFS_FRAG,
-        MFP_IP_ANY,
-        false,
-        NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
-        NXM_NX_IP_FRAG, "NXM_NX_IP_FRAG",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    {
-        MFF_ARP_OP, "arp_op", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_ARP,
-        true,
-        NXM_OF_ARP_OP, "NXM_OF_ARP_OP",
-        OXM_OF_ARP_OP, "OXM_OF_ARP_OP",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_ARP_SPA, "arp_spa", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_ARP,
-        true,
-        NXM_OF_ARP_SPA, "NXM_OF_ARP_SPA",
-        OXM_OF_ARP_SPA, "OXM_OF_ARP_SPA",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-    }, {
-        MFF_ARP_TPA, "arp_tpa", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_IPV4,
-        MFP_ARP,
-        true,
-        NXM_OF_ARP_TPA, "NXM_OF_ARP_TPA",
-        OXM_OF_ARP_TPA, "OXM_OF_ARP_TPA",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-    }, {
-        MFF_ARP_SHA, "arp_sha", NULL,
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_ARP,
-        true,
-        NXM_NX_ARP_SHA, "NXM_NX_ARP_SHA",
-        OXM_OF_ARP_SHA, "OXM_OF_ARP_SHA",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_ARP_THA, "arp_tha", NULL,
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_ARP,
-        true,
-        NXM_NX_ARP_THA, "NXM_NX_ARP_THA",
-        OXM_OF_ARP_THA, "OXM_OF_ARP_THA",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    /* ## -- ## */
-    /* ## L4 ## */
-    /* ## -- ## */
-
-    {
-        MFF_TCP_SRC, "tcp_src", "tp_src",
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_TCP,
-        true,
-        NXM_OF_TCP_SRC, "NXM_OF_TCP_SRC",
-        OXM_OF_TCP_SRC, "OXM_OF_TCP_SRC",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_TCP_DST, "tcp_dst", "tp_dst",
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_TCP,
-        true,
-        NXM_OF_TCP_DST, "NXM_OF_TCP_DST",
-        OXM_OF_TCP_DST, "OXM_OF_TCP_DST",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_TCP_FLAGS, "tcp_flags", NULL,
-        2, 12,
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_TCP,
-        false,
-        NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
-        NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    {
-        MFF_UDP_SRC, "udp_src", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_UDP,
-        true,
-        NXM_OF_UDP_SRC, "NXM_OF_UDP_SRC",
-        OXM_OF_UDP_SRC, "OXM_OF_UDP_SRC",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_UDP_DST, "udp_dst", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_UDP,
-        true,
-        NXM_OF_UDP_DST, "NXM_OF_UDP_DST",
-        OXM_OF_UDP_DST, "OXM_OF_UDP_DST",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    {
-        MFF_SCTP_SRC, "sctp_src", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_SCTP,
-        true,
-        OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC",
-        OXM_OF_SCTP_SRC, "OXM_OF_SCTP_SRC",
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_SCTP_DST, "sctp_dst", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_FULLY,
-        MFS_DECIMAL,
-        MFP_SCTP,
-        true,
-        OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST",
-        OXM_OF_SCTP_DST, "OXM_OF_SCTP_DST",
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OXM_ANY,
-    },
-
-    {
-        MFF_ICMPV4_TYPE, "icmp_type", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_ICMPV4,
-        false,
-        NXM_OF_ICMP_TYPE, "NXM_OF_ICMP_TYPE",
-        OXM_OF_ICMPV4_TYPE, "OXM_OF_ICMPV4_TYPE",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_ICMPV4_CODE, "icmp_code", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_ICMPV4,
-        false,
-        NXM_OF_ICMP_CODE, "NXM_OF_ICMP_CODE",
-        OXM_OF_ICMPV4_CODE, "OXM_OF_ICMPV4_CODE",
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-    },
-
-    {
-        MFF_ICMPV6_TYPE, "icmpv6_type", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_ICMPV6,
-        false,
-        NXM_NX_ICMPV6_TYPE, "NXM_NX_ICMPV6_TYPE",
-        OXM_OF_ICMPV6_TYPE, "OXM_OF_ICMPV6_TYPE",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-    }, {
-        MFF_ICMPV6_CODE, "icmpv6_code", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_ICMPV6,
-        false,
-        NXM_NX_ICMPV6_CODE, "NXM_NX_ICMPV6_CODE",
-        OXM_OF_ICMPV6_CODE, "OXM_OF_ICMPV6_CODE",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-    },
-
-    /* ## ---- ## */
-    /* ## L"5" ## */
-    /* ## ---- ## */
-
-    {
-        MFF_ND_TARGET, "nd_target", NULL,
-        MF_FIELD_SIZES(ipv6),
-        MFM_FULLY,
-        MFS_IPV6,
-        MFP_ND,
-        false,
-        NXM_NX_ND_TARGET, "NXM_NX_ND_TARGET",
-        OXM_OF_IPV6_ND_TARGET, "OXM_OF_IPV6_ND_TARGET",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_ND_SLL, "nd_sll", NULL,
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_ND_SOLICIT,
-        false,
-        NXM_NX_ND_SLL, "NXM_NX_ND_SLL",
-        OXM_OF_IPV6_ND_SLL, "OXM_OF_IPV6_ND_SLL",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }, {
-        MFF_ND_TLL, "nd_tll", NULL,
-        MF_FIELD_SIZES(mac),
-        MFM_FULLY,
-        MFS_ETHERNET,
-        MFP_ND_ADVERT,
-        false,
-        NXM_NX_ND_TLL, "NXM_NX_ND_TLL",
-        OXM_OF_IPV6_ND_TLL, "OXM_OF_IPV6_ND_TLL",
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-    }
-};
+extern const struct mf_field mf_fields[MFF_N_IDS]; /* Silence a warning. */
 
-/* Maps an NXM or OXM header value to an mf_field. */
-struct nxm_field {
-    struct hmap_node hmap_node; /* In 'all_fields' hmap. */
-    uint32_t header;            /* NXM or OXM header value. */
-    const struct mf_field *mf;
+const struct mf_field mf_fields[MFF_N_IDS] = {
+#include "meta-flow.inc"
 };
 
-/* Contains 'struct nxm_field's. */
-static struct hmap all_fields;
-
 /* Maps from an mf_field's 'name' or 'extra_name' to the mf_field. */
 static struct shash mf_by_name;
 
@@ -725,17 +58,8 @@ static struct shash mf_by_name;
  * controller and so there's not much point in showing a lot of them. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
-const struct mf_field *mf_from_nxm_header__(uint32_t header);
 static void nxm_init(void);
 
-/* Returns the field with the given 'id'. */
-const struct mf_field *
-mf_from_id(enum mf_field_id id)
-{
-    ovs_assert((unsigned int) id < MFF_N_IDS);
-    return &mf_fields[id];
-}
-
 /* Returns the field with the given 'name', or a null pointer if no field has
  * that name. */
 const struct mf_field *
@@ -745,46 +69,17 @@ mf_from_name(const char *name)
     return shash_find_data(&mf_by_name, name);
 }
 
-static void
-add_nxm_field(uint32_t header, const struct mf_field *mf)
-{
-    struct nxm_field *f;
-
-    f = xmalloc(sizeof *f);
-    hmap_insert(&all_fields, &f->hmap_node, hash_int(header, 0));
-    f->header = header;
-    f->mf = mf;
-}
-
-static void
-nxm_init_add_field(const struct mf_field *mf, uint32_t header)
-{
-    if (header) {
-        ovs_assert(!mf_from_nxm_header__(header));
-        add_nxm_field(header, mf);
-        if (mf->maskable != MFM_NONE) {
-            add_nxm_field(NXM_MAKE_WILD_HEADER(header), mf);
-        }
-    }
-}
-
 static void
 nxm_do_init(void)
 {
     int i;
 
-    hmap_init(&all_fields);
     shash_init(&mf_by_name);
     for (i = 0; i < MFF_N_IDS; i++) {
         const struct mf_field *mf = &mf_fields[i];
 
         ovs_assert(mf->id == i); /* Fields must be in the enum order. */
 
-        nxm_init_add_field(mf, mf->nxm_header);
-        if (mf->oxm_header != mf->nxm_header) {
-            nxm_init_add_field(mf, mf->oxm_header);
-        }
-
         shash_add_once(&mf_by_name, mf->name, mf);
         if (mf->extra_name) {
             shash_add_once(&mf_by_name, mf->extra_name, mf);
@@ -799,27 +94,6 @@ nxm_init(void)
     pthread_once(&once, nxm_do_init);
 }
 
-const struct mf_field *
-mf_from_nxm_header(uint32_t header)
-{
-    nxm_init();
-    return mf_from_nxm_header__(header);
-}
-
-const struct mf_field *
-mf_from_nxm_header__(uint32_t header)
-{
-    const struct nxm_field *f;
-
-    HMAP_FOR_EACH_IN_BUCKET (f, hmap_node, hash_int(header, 0), &all_fields) {
-        if (f->header == header) {
-            return f->mf;
-        }
-    }
-
-    return NULL;
-}
-
 /* Returns true if 'wc' wildcards all the bits in field 'mf', false if 'wc'
  * specifies at least one bit in the field.
  *
@@ -829,6 +103,10 @@ bool
 mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+        return !wc->masks.dp_hash;
+    case MFF_RECIRC_ID:
+        return !wc->masks.recirc_id;
     case MFF_TUN_SRC:
         return !wc->masks.tunnel.ip_src;
     case MFF_TUN_DST:
@@ -849,6 +127,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
         return !wc->masks.pkt_mark;
     CASE_MFF_REGS:
         return !wc->masks.regs[mf->id - MFF_REG0];
+    CASE_MFF_XREGS:
+        return !flow_get_xreg(&wc->masks, mf->id - MFF_XREG0);
+    case MFF_ACTSET_OUTPUT:
+        return !wc->masks.actset_output;
 
     case MFF_ETH_SRC:
         return eth_addr_is_zero(wc->masks.dl_src);
@@ -876,11 +158,11 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
         return !(wc->masks.vlan_tci & htons(VLAN_PCP_MASK));
 
     case MFF_MPLS_LABEL:
-        return !(wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK));
+        return !(wc->masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK));
     case MFF_MPLS_TC:
-        return !(wc->masks.mpls_lse & htonl(MPLS_TC_MASK));
+        return !(wc->masks.mpls_lse[0] & htonl(MPLS_TC_MASK));
     case MFF_MPLS_BOS:
-        return !(wc->masks.mpls_lse & htonl(MPLS_BOS_MASK));
+        return !(wc->masks.mpls_lse[0] & htonl(MPLS_BOS_MASK));
 
     case MFF_IPV4_SRC:
         return !wc->masks.nw_src;
@@ -935,7 +217,7 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -959,28 +241,14 @@ mf_is_mask_valid(const struct mf_field *mf, const union mf_value *mask)
 {
     switch (mf->maskable) {
     case MFM_NONE:
-        return (is_all_zeros((const uint8_t *) mask, mf->n_bytes) ||
-                is_all_ones((const uint8_t *) mask, mf->n_bytes));
+        return (is_all_zeros(mask, mf->n_bytes) ||
+                is_all_ones(mask, mf->n_bytes));
 
     case MFM_FULLY:
         return true;
     }
 
-    NOT_REACHED();
-}
-
-static bool
-is_icmpv4(const struct flow *flow)
-{
-    return (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IPPROTO_ICMP);
-}
-
-static bool
-is_icmpv6(const struct flow *flow)
-{
-    return (flow->dl_type == htons(ETH_TYPE_IPV6)
-            && flow->nw_proto == IPPROTO_ICMPV6);
+    OVS_NOT_REACHED();
 }
 
 /* Returns true if 'flow' meets the prerequisites for 'mf', false otherwise. */
@@ -1031,7 +299,7 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
                 && (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)));
     }
 
-    NOT_REACHED();
+    OVS_NOT_REACHED();
 }
 
 /* Set field and it's prerequisities in the mask.
@@ -1088,6 +356,8 @@ bool
 mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+    case MFF_RECIRC_ID:
     case MFF_TUN_ID:
     case MFF_TUN_SRC:
     case MFF_TUN_DST:
@@ -1099,6 +369,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_SKB_PRIORITY:
     case MFF_PKT_MARK:
     CASE_MFF_REGS:
+    CASE_MFF_XREGS:
     case MFF_ETH_SRC:
     case MFF_ETH_DST:
     case MFF_ETH_TYPE:
@@ -1128,7 +399,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_ND_TLL:
         return true;
 
-    case MFF_IN_PORT_OXM: {
+    case MFF_IN_PORT_OXM:
+    case MFF_ACTSET_OUTPUT: {
         ofp_port_t port;
         return !ofputil_port_from_ofp11(value->be32, &port);
     }
@@ -1170,7 +442,7 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1181,6 +453,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
              union mf_value *value)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+        value->be32 = htonl(flow->dp_hash);
+        break;
+    case MFF_RECIRC_ID:
+        value->be32 = htonl(flow->recirc_id);
+        break;
     case MFF_TUN_ID:
         value->be64 = flow->tunnel.tun_id;
         break;
@@ -1210,6 +488,9 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
     case MFF_IN_PORT_OXM:
         value->be32 = ofputil_port_to_ofp11(flow->in_port.ofp_port);
         break;
+    case MFF_ACTSET_OUTPUT:
+        value->be32 = ofputil_port_to_ofp11(flow->actset_output);
+        break;
 
     case MFF_SKB_PRIORITY:
         value->be32 = htonl(flow->skb_priority);
@@ -1223,6 +504,10 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->be32 = htonl(flow->regs[mf->id - MFF_REG0]);
         break;
 
+    CASE_MFF_XREGS:
+        value->be64 = htonll(flow_get_xreg(flow, mf->id - MFF_XREG0));
+        break;
+
     case MFF_ETH_SRC:
         memcpy(value->mac, flow->dl_src, ETH_ADDR_LEN);
         break;
@@ -1252,15 +537,15 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         break;
 
     case MFF_MPLS_LABEL:
-        value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse));
+        value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse[0]));
         break;
 
     case MFF_MPLS_TC:
-        value->u8 = mpls_lse_to_tc(flow->mpls_lse);
+        value->u8 = mpls_lse_to_tc(flow->mpls_lse[0]);
         break;
 
     case MFF_MPLS_BOS:
-        value->u8 = mpls_lse_to_bos(flow->mpls_lse);
+        value->u8 = mpls_lse_to_bos(flow->mpls_lse[0]);
         break;
 
     case MFF_IPV4_SRC:
@@ -1361,7 +646,7 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1373,6 +658,12 @@ mf_set_value(const struct mf_field *mf,
              const union mf_value *value, struct match *match)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+        match_set_dp_hash(match, ntohl(value->be32));
+        break;
+    case MFF_RECIRC_ID:
+        match_set_recirc_id(match, ntohl(value->be32));
+        break;
     case MFF_TUN_ID:
         match_set_tun_id(match, value->be64);
         break;
@@ -1406,6 +697,12 @@ mf_set_value(const struct mf_field *mf,
         match_set_in_port(match, port);
         break;
     }
+    case MFF_ACTSET_OUTPUT: {
+        ofp_port_t port;
+        ofputil_port_from_ofp11(value->be32, &port);
+        match_set_actset_output(match, port);
+        break;
+    }
 
     case MFF_SKB_PRIORITY:
         match_set_skb_priority(match, ntohl(value->be32));
@@ -1419,6 +716,10 @@ mf_set_value(const struct mf_field *mf,
         match_set_reg(match, mf->id - MFF_REG0, ntohl(value->be32));
         break;
 
+    CASE_MFF_XREGS:
+        match_set_xreg(match, mf->id - MFF_XREG0, ntohll(value->be64));
+        break;
+
     case MFF_ETH_SRC:
         match_set_dl_src(match, value->mac);
         break;
@@ -1448,15 +749,15 @@ mf_set_value(const struct mf_field *mf,
         break;
 
     case MFF_MPLS_LABEL:
-        match_set_mpls_label(match, value->be32);
+        match_set_mpls_label(match, 0, value->be32);
         break;
 
     case MFF_MPLS_TC:
-        match_set_mpls_tc(match, value->u8);
+        match_set_mpls_tc(match, 0, value->u8);
         break;
 
     case MFF_MPLS_BOS:
-        match_set_mpls_bos(match, value->u8);
+        match_set_mpls_bos(match, 0, value->u8);
         break;
 
     case MFF_IPV4_SRC:
@@ -1557,7 +858,7 @@ mf_set_value(const struct mf_field *mf,
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1586,6 +887,12 @@ mf_set_flow_value(const struct mf_field *mf,
                   const union mf_value *value, struct flow *flow)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+        flow->dp_hash = ntohl(value->be32);
+        break;
+    case MFF_RECIRC_ID:
+        flow->recirc_id = ntohl(value->be32);
+        break;
     case MFF_TUN_ID:
         flow->tunnel.tun_id = value->be64;
         break;
@@ -1613,12 +920,12 @@ mf_set_flow_value(const struct mf_field *mf,
         flow->in_port.ofp_port = u16_to_ofp(ntohs(value->be16));
         break;
 
-    case MFF_IN_PORT_OXM: {
-        ofp_port_t port;
-        ofputil_port_from_ofp11(value->be32, &port);
-        flow->in_port.ofp_port = port;
+    case MFF_IN_PORT_OXM:
+        ofputil_port_from_ofp11(value->be32, &flow->in_port.ofp_port);
+        break;
+    case MFF_ACTSET_OUTPUT:
+        ofputil_port_from_ofp11(value->be32, &flow->actset_output);
         break;
-    }
 
     case MFF_SKB_PRIORITY:
         flow->skb_priority = ntohl(value->be32);
@@ -1632,6 +939,10 @@ mf_set_flow_value(const struct mf_field *mf,
         flow->regs[mf->id - MFF_REG0] = ntohl(value->be32);
         break;
 
+    CASE_MFF_XREGS:
+        flow_set_xreg(flow, mf->id - MFF_XREG0, ntohll(value->be64));
+        break;
+
     case MFF_ETH_SRC:
         memcpy(flow->dl_src, value->mac, ETH_ADDR_LEN);
         break;
@@ -1661,15 +972,15 @@ mf_set_flow_value(const struct mf_field *mf,
         break;
 
     case MFF_MPLS_LABEL:
-        flow_set_mpls_label(flow, value->be32);
+        flow_set_mpls_label(flow, 0, value->be32);
         break;
 
     case MFF_MPLS_TC:
-        flow_set_mpls_tc(flow, value->u8);
+        flow_set_mpls_tc(flow, 0, value->u8);
         break;
 
     case MFF_MPLS_BOS:
-        flow_set_mpls_bos(flow, value->u8);
+        flow_set_mpls_bos(flow, 0, value->u8);
         break;
 
     case MFF_IPV4_SRC:
@@ -1716,7 +1027,7 @@ mf_set_flow_value(const struct mf_field *mf,
         break;
 
     case MFF_IP_FRAG:
-        flow->nw_frag &= value->u8;
+        flow->nw_frag = value->u8 & FLOW_NW_FRAG_MASK;
         break;
 
     case MFF_ARP_OP:
@@ -1773,10 +1084,40 @@ mf_set_flow_value(const struct mf_field *mf,
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
+    }
+}
+
+/* Consider each of 'src', 'mask', and 'dst' as if they were arrays of 8*n
+ * bits.  Then, for each 0 <= i < 8 * n such that mask[i] == 1, sets dst[i] =
+ * src[i].  */
+static void
+apply_mask(const uint8_t *src, const uint8_t *mask, uint8_t *dst, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        dst[i] = (src[i] & mask[i]) | (dst[i] & ~mask[i]);
     }
 }
 
+/* Sets 'flow' member field described by 'field' to 'value', except that bits
+ * for which 'mask' has a 0-bit keep their existing values.  The caller is
+ * responsible for ensuring that 'flow' meets 'field''s prerequisites.*/
+void
+mf_set_flow_value_masked(const struct mf_field *field,
+                         const union mf_value *value,
+                         const union mf_value *mask,
+                         struct flow *flow)
+{
+    union mf_value tmp;
+
+    mf_get_value(field, flow, &tmp);
+    apply_mask((const uint8_t *) value, (const uint8_t *) mask,
+               (uint8_t *) &tmp, field->n_bytes);
+    mf_set_flow_value(field, &tmp, flow);
+}
+
 /* Returns true if 'mf' has a zero value in 'flow', false if it is nonzero.
  *
  * The caller is responsible for ensuring that 'flow' meets 'mf''s
@@ -1787,7 +1128,7 @@ mf_is_zero(const struct mf_field *mf, const struct flow *flow)
     union mf_value value;
 
     mf_get_value(mf, flow, &value);
-    return is_all_zeros((const uint8_t *) &value, mf->n_bytes);
+    return is_all_zeros(&value, mf->n_bytes);
 }
 
 /* Makes 'match' wildcard field 'mf'.
@@ -1798,6 +1139,14 @@ void
 mf_set_wild(const struct mf_field *mf, struct match *match)
 {
     switch (mf->id) {
+    case MFF_DP_HASH:
+        match->flow.dp_hash = 0;
+        match->wc.masks.dp_hash = 0;
+        break;
+    case MFF_RECIRC_ID:
+        match->flow.recirc_id = 0;
+        match->wc.masks.recirc_id = 0;
+        break;
     case MFF_TUN_ID:
         match_set_tun_id_masked(match, htonll(0), htonll(0));
         break;
@@ -1826,6 +1175,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         match->flow.in_port.ofp_port = 0;
         match->wc.masks.in_port.ofp_port = 0;
         break;
+    case MFF_ACTSET_OUTPUT:
+        match->flow.actset_output = 0;
+        match->wc.masks.actset_output = 0;
+        break;
 
     case MFF_SKB_PRIORITY:
         match->flow.skb_priority = 0;
@@ -1841,6 +1194,10 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         match_set_reg_masked(match, mf->id - MFF_REG0, 0, 0);
         break;
 
+    CASE_MFF_XREGS:
+        match_set_xreg_masked(match, mf->id - MFF_XREG0, 0, 0);
+        break;
+
     case MFF_ETH_SRC:
         memset(match->flow.dl_src, 0, ETH_ADDR_LEN);
         memset(match->wc.masks.dl_src, 0, ETH_ADDR_LEN);
@@ -1871,15 +1228,15 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         break;
 
     case MFF_MPLS_LABEL:
-        match_set_any_mpls_label(match);
+        match_set_any_mpls_label(match, 0);
         break;
 
     case MFF_MPLS_TC:
-        match_set_any_mpls_tc(match);
+        match_set_any_mpls_tc(match, 0);
         break;
 
     case MFF_MPLS_BOS:
-        match_set_any_mpls_bos(match);
+        match_set_any_mpls_bos(match, 0);
         break;
 
     case MFF_IPV4_SRC:
@@ -1981,7 +1338,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -2001,17 +1358,19 @@ mf_set(const struct mf_field *mf,
        const union mf_value *value, const union mf_value *mask,
        struct match *match)
 {
-    if (!mask || is_all_ones((const uint8_t *) mask, mf->n_bytes)) {
+    if (!mask || is_all_ones(mask, mf->n_bytes)) {
         mf_set_value(mf, value, match);
-        return mf->usable_protocols;
-    } else if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) {
+        return mf->usable_protocols_exact;
+    } else if (is_all_zeros(mask, mf->n_bytes)) {
         mf_set_wild(mf, match);
         return OFPUTIL_P_ANY;
     }
 
     switch (mf->id) {
+    case MFF_RECIRC_ID:
     case MFF_IN_PORT:
     case MFF_IN_PORT_OXM:
+    case MFF_ACTSET_OUTPUT:
     case MFF_SKB_PRIORITY:
     case MFF_ETH_TYPE:
     case MFF_DL_VLAN:
@@ -2032,6 +1391,9 @@ mf_set(const struct mf_field *mf,
     case MFF_ICMPV6_CODE:
         return OFPUTIL_P_NONE;
 
+    case MFF_DP_HASH:
+        match_set_dp_hash_masked(match, ntohl(value->be32), ntohl(mask->be32));
+        break;
     case MFF_TUN_ID:
         match_set_tun_id_masked(match, value->be64, mask->be64);
         break;
@@ -2060,6 +1422,11 @@ mf_set(const struct mf_field *mf,
                              ntohl(value->be32), ntohl(mask->be32));
         break;
 
+    CASE_MFF_XREGS:
+        match_set_xreg_masked(match, mf->id - MFF_XREG0,
+                              ntohll(value->be64), ntohll(mask->be64));
+        break;
+
     case MFF_PKT_MARK:
         match_set_pkt_mark_masked(match, ntohl(value->be32),
                                   ntohl(mask->be32));
@@ -2093,11 +1460,11 @@ mf_set(const struct mf_field *mf,
 
     case MFF_IPV4_SRC:
         match_set_nw_src_masked(match, value->be32, mask->be32);
-        goto cidr_check;
+        break;
 
     case MFF_IPV4_DST:
         match_set_nw_dst_masked(match, value->be32, mask->be32);
-        goto cidr_check;
+        break;
 
     case MFF_IPV6_SRC:
         match_set_ipv6_src_masked(match, &value->ipv6, &mask->ipv6);
@@ -2125,11 +1492,11 @@ mf_set(const struct mf_field *mf,
 
     case MFF_ARP_SPA:
         match_set_nw_src_masked(match, value->be32, mask->be32);
-        goto cidr_check;
+        break;
 
     case MFF_ARP_TPA:
         match_set_nw_dst_masked(match, value->be32, mask->be32);
-        goto cidr_check;
+        break;
 
     case MFF_TCP_SRC:
     case MFF_UDP_SRC:
@@ -2149,14 +1516,13 @@ mf_set(const struct mf_field *mf,
 
     case MFF_N_IDS:
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
-    return mf->usable_protocols_bitwise;
-
-cidr_check:
-    return ip_is_cidr(mask->be32) ? mf->usable_protocols :
-            mf->usable_protocols_bitwise;
+    return ((mf->usable_protocols_bitwise == mf->usable_protocols_cidr
+             || ip_is_cidr(mask->be32))
+            ? mf->usable_protocols_cidr
+            : mf->usable_protocols_bitwise);
 }
 
 static enum ofperr
@@ -2221,115 +1587,6 @@ mf_get(const struct mf_field *mf, const struct match *match,
     mf_get_mask(mf, &match->wc, mask);
 }
 
-/* Assigns a random value for field 'mf' to 'value'. */
-void
-mf_random_value(const struct mf_field *mf, union mf_value *value)
-{
-    random_bytes(value, mf->n_bytes);
-
-    switch (mf->id) {
-    case MFF_TUN_ID:
-    case MFF_TUN_SRC:
-    case MFF_TUN_DST:
-    case MFF_TUN_TOS:
-    case MFF_TUN_TTL:
-    case MFF_TUN_FLAGS:
-    case MFF_METADATA:
-    case MFF_IN_PORT:
-    case MFF_PKT_MARK:
-    case MFF_SKB_PRIORITY:
-    CASE_MFF_REGS:
-    case MFF_ETH_SRC:
-    case MFF_ETH_DST:
-    case MFF_ETH_TYPE:
-    case MFF_VLAN_TCI:
-    case MFF_IPV4_SRC:
-    case MFF_IPV4_DST:
-    case MFF_IPV6_SRC:
-    case MFF_IPV6_DST:
-    case MFF_IP_PROTO:
-    case MFF_IP_TTL:
-    case MFF_ARP_SPA:
-    case MFF_ARP_TPA:
-    case MFF_ARP_SHA:
-    case MFF_ARP_THA:
-    case MFF_TCP_SRC:
-    case MFF_TCP_DST:
-    case MFF_UDP_SRC:
-    case MFF_UDP_DST:
-    case MFF_SCTP_SRC:
-    case MFF_SCTP_DST:
-    case MFF_ICMPV4_TYPE:
-    case MFF_ICMPV4_CODE:
-    case MFF_ICMPV6_TYPE:
-    case MFF_ICMPV6_CODE:
-    case MFF_ND_TARGET:
-    case MFF_ND_SLL:
-    case MFF_ND_TLL:
-        break;
-
-    case MFF_TCP_FLAGS:
-        value->be16 &= htons(0x0fff);
-        break;
-
-    case MFF_IN_PORT_OXM:
-        value->be32 = ofputil_port_to_ofp11(u16_to_ofp(ntohs(value->be16)));
-        break;
-
-    case MFF_IPV6_LABEL:
-        value->be32 &= htonl(IPV6_LABEL_MASK);
-        break;
-
-    case MFF_IP_DSCP:
-        value->u8 &= IP_DSCP_MASK;
-        break;
-
-    case MFF_IP_DSCP_SHIFTED:
-        value->u8 &= IP_DSCP_MASK >> 2;
-        break;
-
-    case MFF_IP_ECN:
-        value->u8 &= IP_ECN_MASK;
-        break;
-
-    case MFF_IP_FRAG:
-        value->u8 &= FLOW_NW_FRAG_MASK;
-        break;
-
-    case MFF_ARP_OP:
-        value->be16 &= htons(0xff);
-        break;
-
-    case MFF_DL_VLAN:
-        value->be16 &= htons(VLAN_VID_MASK);
-        break;
-    case MFF_VLAN_VID:
-        value->be16 &= htons(VLAN_VID_MASK | VLAN_CFI);
-        break;
-
-    case MFF_DL_VLAN_PCP:
-    case MFF_VLAN_PCP:
-        value->u8 &= 0x07;
-        break;
-
-    case MFF_MPLS_LABEL:
-        value->be32 &= htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT);
-        break;
-
-    case MFF_MPLS_TC:
-        value->u8 &= MPLS_TC_MASK >> MPLS_TC_SHIFT;
-        break;
-
-    case MFF_MPLS_BOS:
-        value->u8 &= MPLS_BOS_MASK >> MPLS_BOS_SHIFT;
-        break;
-
-    case MFF_N_IDS:
-    default:
-        NOT_REACHED();
-    }
-}
-
 static char *
 mf_from_integer_string(const struct mf_field *mf, const char *s,
                        uint8_t *valuep, uint8_t *maskp)
@@ -2379,15 +1636,15 @@ mf_from_ethernet_string(const struct mf_field *mf, const char *s,
     ovs_assert(mf->n_bytes == ETH_ADDR_LEN);
 
     n = -1;
-    if (sscanf(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n) > 0
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(mac), &n)
         && n == strlen(s)) {
         memset(mask, 0xff, ETH_ADDR_LEN);
         return NULL;
     }
 
     n = -1;
-    if (sscanf(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT"%n",
-               ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask), &n) > 0
+    if (ovs_scan(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT"%n",
+                 ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask), &n)
         && n == strlen(s)) {
         return NULL;
     }
@@ -2403,11 +1660,10 @@ mf_from_ipv4_string(const struct mf_field *mf, const char *s,
 
     ovs_assert(mf->n_bytes == sizeof *ip);
 
-    if (sscanf(s, IP_SCAN_FMT"/"IP_SCAN_FMT,
-               IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask)) == IP_SCAN_COUNT * 2) {
+    if (ovs_scan(s, IP_SCAN_FMT"/"IP_SCAN_FMT,
+                 IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask))) {
         /* OK. */
-    } else if (sscanf(s, IP_SCAN_FMT"/%d",
-                      IP_SCAN_ARGS(ip), &prefix) == IP_SCAN_COUNT + 1) {
+    } else if (ovs_scan(s, IP_SCAN_FMT"/%d", IP_SCAN_ARGS(ip), &prefix)) {
         if (prefix <= 0 || prefix > 32) {
             return xasprintf("%s: network prefix bits not between 1 and "
                              "32", s);
@@ -2416,7 +1672,7 @@ mf_from_ipv4_string(const struct mf_field *mf, const char *s,
         } else {
             *mask = htonl(((1u << prefix) - 1) << (32 - prefix));
         }
-    } else if (sscanf(s, IP_SCAN_FMT, IP_SCAN_ARGS(ip)) == IP_SCAN_COUNT) {
+    } else if (ovs_scan(s, IP_SCAN_FMT, IP_SCAN_ARGS(ip))) {
         *mask = OVS_BE32_MAX;
     } else {
         return xasprintf("%s: invalid IP address", s);
@@ -2554,9 +1810,8 @@ parse_flow_tun_flags(const char *s_, const char *(*bit_to_string)(uint32_t),
         int name_len;
         unsigned long long int flags;
         uint32_t bit;
-        int n0;
 
-        if (sscanf(name, "%lli%n", &flags, &n0) > 0 && n0 > 0) {
+        if (ovs_scan(name, "%lli", &flags)) {
             result |= flags;
             continue;
         }
@@ -2600,9 +1855,84 @@ mf_from_tun_flags_string(const char *s, ovs_be16 *valuep, ovs_be16 *maskp)
     }
 
     return xasprintf("%s: unknown tunnel flags (valid flags are \"df\", "
-                     "\"csum\", \"key\"", s);
+                     "\"csum\", \"key\")", s);
+}
+
+static char *
+mf_from_tcp_flags_string(const char *s, ovs_be16 *flagsp, ovs_be16 *maskp)
+{
+    uint16_t flags = 0;
+    uint16_t mask = 0;
+    uint16_t bit;
+    int n;
+
+    if (ovs_scan(s, "%"SCNi16"/%"SCNi16"%n", &flags, &mask, &n) && !s[n]) {
+        *flagsp = htons(flags);
+        *maskp = htons(mask);
+        return NULL;
+    }
+    if (ovs_scan(s, "%"SCNi16"%n", &flags, &n) && !s[n]) {
+        *flagsp = htons(flags);
+        *maskp = OVS_BE16_MAX;
+        return NULL;
+    }
+
+    while (*s != '\0') {
+        bool set;
+        int name_len;
+
+        switch (*s) {
+        case '+':
+            set = true;
+            break;
+        case '-':
+            set = false;
+            break;
+        default:
+            return xasprintf("%s: TCP flag must be preceded by '+' (for SET) "
+                             "or '-' (NOT SET)", s);
+        }
+        s++;
+
+        name_len = strcspn(s,"+-");
+
+        for (bit = 1; bit; bit <<= 1) {
+            const char *fname = packet_tcp_flag_to_string(bit);
+            size_t len;
+
+            if (!fname) {
+                continue;
+            }
+
+            len = strlen(fname);
+            if (len != name_len) {
+                continue;
+            }
+            if (!strncmp(s, fname, len)) {
+                if (mask & bit) {
+                    return xasprintf("%s: Each TCP flag can be specified only "
+                                     "once", s);
+                }
+                if (set) {
+                    flags |= bit;
+                }
+                mask |= bit;
+                break;
+            }
+        }
+
+        if (!bit) {
+            return xasprintf("%s: unknown TCP flag(s)", s);
+        }
+        s += name_len;
+    }
+
+    *flagsp = htons(flags);
+    *maskp = htons(mask);
+    return NULL;
 }
 
+
 /* Parses 's', a string value for field 'mf', into 'value' and 'mask'.  Returns
  * NULL if successful, otherwise a malloc()'d string describing the error. */
 char *
@@ -2653,8 +1983,13 @@ mf_parse(const struct mf_field *mf, const char *s,
         error = mf_from_tun_flags_string(s, &value->be16, &mask->be16);
         break;
 
+    case MFS_TCP_FLAGS:
+        ovs_assert(mf->n_bytes == sizeof(ovs_be16));
+        error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16);
+        break;
+
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     if (!error && !mf_is_mask_valid(mf, mask)) {
@@ -2739,6 +2074,13 @@ mf_format_tnl_flags_string(const ovs_be16 *valuep, struct ds *s)
     format_flags(s, flow_tun_flag_to_string, ntohs(*valuep), '|');
 }
 
+static void
+mf_format_tcp_flags_string(ovs_be16 value, ovs_be16 mask, struct ds *s)
+{
+    format_flags_masked(s, NULL, packet_tcp_flag_to_string, ntohs(value),
+                        TCP_FLAGS(mask));
+}
+
 /* Appends to 's' a string representation of field 'mf' whose value is in
  * 'value' and 'mask'.  'mask' may be NULL to indicate an exact match. */
 void
@@ -2747,10 +2089,10 @@ mf_format(const struct mf_field *mf,
           struct ds *s)
 {
     if (mask) {
-        if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) {
+        if (is_all_zeros(mask, mf->n_bytes)) {
             ds_put_cstr(s, "ANY");
             return;
-        } else if (is_all_ones((const uint8_t *) mask, mf->n_bytes)) {
+        } else if (is_all_ones(mask, mf->n_bytes)) {
             mask = NULL;
         }
     }
@@ -2795,8 +2137,13 @@ mf_format(const struct mf_field *mf,
         mf_format_tnl_flags_string(&value->be16, s);
         break;
 
+    case MFS_TCP_FLAGS:
+        mf_format_tcp_flags_string(value->be16,
+                                   mask ? mask->be16 : OVS_BE16_MAX, s);
+        break;
+
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 \f
@@ -2860,144 +2207,6 @@ mf_get_subfield(const struct mf_subfield *sf, const struct flow *flow)
     return bitwise_get(&value, sf->field->n_bytes, sf->ofs, sf->n_bits);
 }
 
-/* Formats 'sf' into 's' in a format normally acceptable to
- * mf_parse_subfield().  (It won't be acceptable if sf->field is NULL or if
- * sf->field has no NXM name.) */
-void
-mf_format_subfield(const struct mf_subfield *sf, struct ds *s)
-{
-    if (!sf->field) {
-        ds_put_cstr(s, "<unknown>");
-    } else if (sf->field->nxm_name) {
-        ds_put_cstr(s, sf->field->nxm_name);
-    } else if (sf->field->nxm_header) {
-        uint32_t header = sf->field->nxm_header;
-        ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
-    } else {
-        ds_put_cstr(s, sf->field->name);
-    }
-
-    if (sf->field && sf->ofs == 0 && sf->n_bits == sf->field->n_bits) {
-        ds_put_cstr(s, "[]");
-    } else if (sf->n_bits == 1) {
-        ds_put_format(s, "[%d]", sf->ofs);
-    } else {
-        ds_put_format(s, "[%d..%d]", sf->ofs, sf->ofs + sf->n_bits - 1);
-    }
-}
-
-static const struct mf_field *
-mf_parse_subfield_name(const char *name, int name_len, bool *wild)
-{
-    int i;
-
-    *wild = name_len > 2 && !memcmp(&name[name_len - 2], "_W", 2);
-    if (*wild) {
-        name_len -= 2;
-    }
-
-    for (i = 0; i < MFF_N_IDS; i++) {
-        const struct mf_field *mf = mf_from_id(i);
-
-        if (mf->nxm_name
-            && !strncmp(mf->nxm_name, name, name_len)
-            && mf->nxm_name[name_len] == '\0') {
-            return mf;
-        }
-        if (mf->oxm_name
-            && !strncmp(mf->oxm_name, name, name_len)
-            && mf->oxm_name[name_len] == '\0') {
-            return mf;
-        }
-    }
-
-    return NULL;
-}
-
-/* Parses a subfield from the beginning of '*sp' into 'sf'.  If successful,
- * returns NULL and advances '*sp' to the first byte following the parsed
- * string.  On failure, returns a malloc()'d error message, does not modify
- * '*sp', and does not properly initialize 'sf'.
- *
- * The syntax parsed from '*sp' takes the form "header[start..end]" where
- * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive)
- * bit indexes.  "..end" may be omitted to indicate a single bit.  "start..end"
- * may both be omitted (the [] are still required) to indicate an entire
- * field. */
-char * WARN_UNUSED_RESULT
-mf_parse_subfield__(struct mf_subfield *sf, const char **sp)
-{
-    const struct mf_field *field;
-    const char *name;
-    int start, end;
-    const char *s;
-    int name_len;
-    bool wild;
-
-    s = *sp;
-    name = s;
-    name_len = strcspn(s, "[");
-    if (s[name_len] != '[') {
-        return xasprintf("%s: missing [ looking for field name", *sp);
-    }
-
-    field = mf_parse_subfield_name(name, name_len, &wild);
-    if (!field) {
-        return xasprintf("%s: unknown field `%.*s'", *sp, name_len, s);
-    }
-
-    s += name_len;
-    if (sscanf(s, "[%d..%d]", &start, &end) == 2) {
-        /* Nothing to do. */
-    } else if (sscanf(s, "[%d]", &start) == 1) {
-        end = start;
-    } else if (!strncmp(s, "[]", 2)) {
-        start = 0;
-        end = field->n_bits - 1;
-    } else {
-        return xasprintf("%s: syntax error expecting [] or [<bit>] or "
-                         "[<start>..<end>]", *sp);
-    }
-    s = strchr(s, ']') + 1;
-
-    if (start > end) {
-        return xasprintf("%s: starting bit %d is after ending bit %d",
-                         *sp, start, end);
-    } else if (start >= field->n_bits) {
-        return xasprintf("%s: starting bit %d is not valid because field is "
-                         "only %d bits wide", *sp, start, field->n_bits);
-    } else if (end >= field->n_bits){
-        return xasprintf("%s: ending bit %d is not valid because field is "
-                         "only %d bits wide", *sp, end, field->n_bits);
-    }
-
-    sf->field = field;
-    sf->ofs = start;
-    sf->n_bits = end - start + 1;
-
-    *sp = s;
-    return NULL;
-}
-
-/* Parses a subfield from the entirety of 's' into 'sf'.  Returns NULL if
- * successful, otherwise a malloc()'d string describing the error.  The caller
- * is responsible for freeing the returned string.
- *
- * The syntax parsed from 's' takes the form "header[start..end]" where
- * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive)
- * bit indexes.  "..end" may be omitted to indicate a single bit.  "start..end"
- * may both be omitted (the [] are still required) to indicate an entire
- * field.  */
-char * WARN_UNUSED_RESULT
-mf_parse_subfield(struct mf_subfield *sf, const char *s)
-{
-    char *error = mf_parse_subfield__(sf, &s);
-    if (!error && s[0]) {
-        error = xstrdup("unexpected input following field syntax");
-    }
-    return error;
-}
-
 void
 mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
 {