[ovs-dev] [PATCH 06/17] meta-flow: Autogenerate mf_field data structures.

Ben Pfaff blp at nicira.com
Wed Sep 17 05:56:59 UTC 2014


This is a first step toward improving the abstraction of OXM and NXM in the
tree.  As an immediate improvement, this commit removes all of the
definitions of the OXM and NXM constants from the top-level header files,
because they are no longer used anywhere.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 build-aux/extract-ofp-fields    |  458 +++++++++++++
 include/openflow/nicira-ext.h   |  464 +------------
 include/openflow/openflow-1.2.h |  123 ----
 lib/automake.mk                 |    8 +-
 lib/meta-flow.c                 |  769 +--------------------
 lib/meta-flow.h                 | 1398 ++++++++++++++++++++++++++++++++++++---
 lib/ofp-actions.c               |    2 +-
 7 files changed, 1773 insertions(+), 1449 deletions(-)
 create mode 100755 build-aux/extract-ofp-fields

diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
new file mode 100755
index 0000000..b895cf8
--- /dev/null
+++ b/build-aux/extract-ofp-fields
@@ -0,0 +1,458 @@
+#! /usr/bin/python
+
+import sys
+import os.path
+import re
+
+line = ""
+
+# Maps from user-friendly version number to its protocol encoding.
+VERSION = {"1.0": 0x01,
+           "1.1": 0x02,
+           "1.2": 0x03,
+           "1.3": 0x04,
+           "1.4": 0x05,
+           "1.5": 0x06}
+
+TYPES = {"u8": 1,
+         "be16": 2,
+         "be32": 4,
+         "MAC": 6,
+         "be64": 8,
+         "IPv6": 16}
+
+FORMATTING = {"decimal":            ("MFS_DECIMAL",      1, 8),
+              "hexadecimal":        ("MFS_HEXADECIMAL",  1, 8),
+              "Ethernet":           ("MFS_ETHERNET",     6, 6),
+              "IPv4":               ("MFS_IPV4",         4, 4),
+              "IPv6":               ("MFS_IPV6",        16,16),
+              "OpenFlow 1.0 port":  ("MFS_OFP_PORT",     2, 2),
+              "OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4, 4),
+              "frag":               ("MFS_FRAG",         1, 1),
+              "tunnel flags":       ("MFS_TNL_FLAGS",    2, 2),
+              "TCP flags":          ("MFS_TCP_FLAGS",    2, 2)}
+
+PREREQS = {"none": "MFP_NONE",
+          "ARP": "MFP_ARP",
+          "VLAN VID": "MFP_VLAN_VID",
+          "IPv4": "MFP_IPV4",
+          "IPv6": "MFP_IPV6",
+          "IPv4/IPv6": "MFP_IP_ANY",
+          "MPLS": "MFP_MPLS",
+          "TCP": "MFP_TCP",
+          "UDP": "MFP_UDP",
+          "SCTP": "MFP_SCTP",
+          "ICMPv4": "MFP_ICMPV4",
+          "ICMPv6": "MFP_ICMPV6",
+          "ND": "MFP_ND",
+          "ND solicit": "MFP_ND_SOLICIT",
+          "ND advert": "MFP_ND_ADVERT"}
+
+# Maps a name prefix to an oxm_class.
+# If a name matches more than one prefix, the longest one is used.
+OXM_CLASSES = {"NXM_OF_": 0x0000,
+               "NXM_NX_": 0x0001,
+               "OXM_OF_": 0x8000,
+               "OXM_OF_PKT_REG": 0x8001}
+def oxm_name_to_class(name):
+    prefix = ''
+    class_ = None
+    for p, c in OXM_CLASSES.iteritems():
+        if name.startswith(p) and len(p) > len(prefix):
+            prefix = p
+            class_ = c
+    return class_
+
+def decode_version_range(range):
+    if range in VERSION:
+        return (VERSION[range], VERSION[range])
+    elif range.endswith('+'):
+        return (VERSION[range[:-1]], max(VERSION.values()))
+    else:
+        a, b = re.match(r'^([^-]+)-([^-]+)$', range).groups()
+        return (VERSION[a], VERSION[b])
+
+def get_line():
+    global line
+    global line_number
+    line = input_file.readline()
+    line_number += 1
+    if line == "":
+        fatal("unexpected end of input")
+
+n_errors = 0
+def error(msg):
+    global n_errors
+    sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
+    n_errors += 1
+
+def fatal(msg):
+    error(msg)
+    sys.exit(1)
+
+def usage():
+    argv0 = os.path.basename(sys.argv[0])
+    print '''\
+%(argv0)s, for extracting OpenFlow field properties from meta-flow.h
+usage: %(argv0)s INPUT
+  where INPUT points to lib/meta-flow.h in the source directory.
+The output written to stdout is intended to be saved as lib/meta-flow.inc,
+which lib/meta-flow.c \"#include\"s.\
+''' % {"argv0": argv0}
+    sys.exit(0)
+
+def make_sizeof(s):
+    m = re.match(r'(.*) up to (.*)', s)
+    if m:
+        struct, member = m.groups()
+        return "offsetof(%s, %s)" % (struct, member)
+    else:
+        return "sizeof(%s)" % s
+
+def parse_oxm(s, prefix, n_bytes):
+    if s == 'none':
+        return None
+
+    m = re.match('([A-Z0-9_]+)\(([0-9]+)\) since(?: OF(1\.[0-9]+) and)? v([12]\.[0-9]+)$', s)
+    if not m:
+        fatal("%s: syntax error parsing %s" % (s, prefix))
+        
+    name, code, of_version, ovs_version = m.groups()
+
+    class_ = oxm_name_to_class(name)
+    if class_ is None:
+        fatal("unknown OXM class for %s" % name)
+    header = ("NXM_HEADER(0x%04x, %s, %d)" % (class_, code, n_bytes))
+
+    if of_version:
+        if of_version not in VERSION:
+            fatal("%s: unknown OpenFlow version %s" % (name, of_version))
+        of_version_nr = VERSION[of_version]
+        if of_version_nr < VERSION['1.2']:
+            fatal("%s: claimed version %s predates OXM" % (name, of_version))
+    else:
+        of_version_nr = 0
+
+    return (header, name, of_version_nr, ovs_version)
+
+def parse_field(mff, comment):
+    f = {'mff': mff}
+
+    # First line of comment is the field name.
+    m = re.match(r'"([^"]+)"(?:\s+\(aka "([^"]+)"\))?(?:\s+\(.*\))?\.', comment[0])
+    if not m:
+        fatal("%s lacks field name" % mff)
+    f['name'], f['extra_name'] = m.groups()
+
+    # Find the last blank line the comment.  The field definitions
+    # start after that.
+    blank = None
+    for i in range(len(comment)):
+        if not comment[i]:
+            blank = i
+    if not blank:
+        fatal("%s: missing blank line in comment" % mff)
+
+    d = {}
+    for key in ("Type", "Maskable", "Formatting", "Prerequisites",
+                "Access", "Prefix lookup member",
+                "OXM", "NXM", "OF1.0", "OF1.1"):
+        d[key] = None
+    for line in comment[blank + 1:]:
+        m = re.match(r'([^:]+):\s+(.*)\.$', line)
+        if not m:
+            fatal("%s: syntax error parsing key-value pair as part of %s"
+                  % (line, mff))
+        key, value = m.groups()
+        if key not in d:
+            fatal("%s: unknown key" % key)
+        elif key == 'Code point':
+            d[key] += [value]
+        elif d[key] is not None:
+            fatal("%s: duplicate key" % key)
+        d[key] = value
+    for key, value in d.iteritems():
+        if not value and key not in ("OF1.0", "OF1.1",
+                                     "Prefix lookup member", "Notes"):
+            fatal("%s: missing %s" % (mff, key))
+
+    m = re.match(r'([a-zA-Z0-9]+)(?: \(low ([0-9]+) bits\))?$', d['Type'])
+    if not m:
+        fatal("%s: syntax error in type" % mff)
+    type_ = m.group(1)
+    if type_ not in TYPES:
+        fatal("%s: unknown type %s" % (mff, d['Type']))
+    f['n_bytes'] = TYPES[type_]
+    if m.group(2):
+        f['n_bits'] = int(m.group(2))
+        if f['n_bits'] > f['n_bytes'] * 8:
+            fatal("%s: more bits (%d) than field size (%d)"
+                  % (mff, f['n_bits'], 8 * f['n_bytes']))
+    else:
+        f['n_bits'] = 8 * f['n_bytes']
+
+    if d['Maskable'] == 'no':
+        f['mask'] = 'MFM_NONE'
+    elif d['Maskable'] == 'bitwise':
+        f['mask'] = 'MFM_FULLY'
+    else:
+        fatal("%s: unknown maskable %s" % (mff, d['Maskable']))
+
+    fmt = FORMATTING.get(d['Formatting'])
+    if not fmt:
+        fatal("%s: unknown format %s" % (mff, d['Formatting']))
+    if f['n_bytes'] < fmt[1] or f['n_bytes'] > fmt[2]:
+        fatal("%s: %d-byte field can't be formatted as %s"
+              % (mff, f['n_bytes'], d['Formatting']))
+    f['string'] = fmt[0]
+
+    f['prereqs'] = PREREQS.get(d['Prerequisites'])
+    if not f['prereqs']:
+        fatal("%s: unknown prerequisites %s" % (mff, d['Prerequisites']))
+
+    if d['Access'] == 'read-only':
+        f['writable'] = False
+    elif d['Access'] == 'read/write':
+        f['writable'] = True
+    else:
+        fatal("%s: unknown access %s" % (mff, d['Access']))
+
+    f['OF1.0'] = d['OF1.0']
+    if not d['OF1.0'] in (None, 'exact match', 'CIDR mask'):
+        fatal("%s: unknown OF1.0 match type %s" % (mff, d['OF1.0']))
+        
+    f['OF1.1'] = d['OF1.1']
+    if not d['OF1.1'] in (None, 'exact match', 'bitwise mask'):
+        fatal("%s: unknown OF1.1 match type %s" % (mff, d['OF1.1']))
+
+    f['OXM'] = parse_oxm(d['OXM'], 'OXM', f['n_bytes'])
+    f['NXM'] = parse_oxm(d['NXM'], 'NXM', f['n_bytes'])
+
+    f['prefix'] = d["Prefix lookup member"]
+
+    return f
+
+def protocols_to_c(protocols):
+    if protocols == set(['of10', 'of11', 'oxm']):
+        return 'OFPUTIL_P_ANY'
+    elif protocols == set(['of11', 'oxm']):
+        return 'OFPUTIL_P_NXM_OF11_UP'
+    elif protocols == set(['oxm']):
+        return 'OFPUTIL_P_NXM_OXM_ANY'
+    elif protocols == set([]):
+        return 'OFPUTIL_P_NONE'
+    else:
+        assert False        
+
+def extract_ofp_fields():
+    global line
+
+    fields = []
+
+    while True:
+        get_line()
+        if re.match('enum.*mf_field_id', line):
+            break
+
+    while True:
+        get_line()
+        first_line_number = line_number
+        here = '%s:%d' % (file_name, line_number)
+        if (line.startswith('/*')
+            or line.startswith(' *')
+            or line.startswith('#')
+            or not line
+            or line.isspace()):
+            continue
+        elif re.match('}', line) or re.match('\s+MFF_N_IDS', line):
+            break
+
+        # Parse the comment preceding an MFF_ constant into 'comment',
+        # one line to an array element.
+        line = line.strip()
+        if not line.startswith('/*'):
+            fatal("unexpected syntax between fields")
+        line = line[1:]
+        comment = []
+        end = False
+        while not end:
+            line = line.strip()
+            if line.startswith('*/'):
+                get_line()
+                break
+            if not line.startswith('*'):
+                fatal("unexpected syntax within field")
+
+            line = line[1:]
+            if line.startswith(' '):
+                line = line[1:]
+            if line.startswith(' ') and comment:
+                continuation = True
+                line = line.lstrip()
+            else:
+                continuation = False
+
+            if line.endswith('*/'):
+                line = line[:-2].rstrip()
+                end = True
+            else:
+                end = False
+
+            if continuation:
+                comment[-1] += " " + line
+            else:
+                comment += [line]
+            get_line()
+
+        # Drop blank lines at each end of comment.
+        while comment and not comment[0]:
+            comment = comment[1:]
+        while comment and not comment[-1]:
+            comment = comment[:-1]
+
+        # Parse the MFF_ constant(s).
+        mffs = []
+        while True:
+            m = re.match('\s+(MFF_[A-Z0-9_]+),?\s?$', line)
+            if not m:
+                break
+            mffs += [m.group(1)]
+            get_line()
+        if not mffs:
+            fatal("unexpected syntax looking for MFF_ constants")
+
+        if len(mffs) > 1 or '<N>' in comment[0]:
+            for mff in mffs:
+                # Extract trailing integer.
+                m = re.match('.*[^0-9]([0-9]+)$', mff)
+                if not m:
+                    fatal("%s lacks numeric suffix in register group" % mff)
+                n = m.group(1)
+
+                # Search-and-replace <N> within the comment,
+                # and drop lines that have <x> for x != n.
+                instance = []
+                for x in comment:
+                    y = x.replace('<N>', n)
+                    if re.search('<[0-9]+>', y):
+                        if ('<%s>' % n) not in y:
+                            continue
+                        y = re.sub('<[0-9]+>', '', y)
+                    instance += [y.strip()]
+                fields += [parse_field(mff, instance)]
+        else:
+            fields += [parse_field(mffs[0], comment)]
+        continue
+
+    input_file.close()
+
+    if n_errors:
+        sys.exit(1)
+
+    output = []
+    output += ["/* Generated automatically; do not modify!     "
+               "-*- buffer-read-only: t -*- */"]
+    output += [""]
+
+    for f in fields:
+        output += ["{"]
+        output += ["    %s," % f['mff']]
+        if f['extra_name']:
+            output += ["    \"%s\", \"%s\"," % (f['name'], f['extra_name'])]
+        else:
+            output += ["    \"%s\", NULL," % f['name']]
+        output += ["    %d, %d," % (f['n_bytes'], f['n_bits'])]
+
+        if f['writable']:
+            rw = 'true'
+        else:
+            rw = 'false'
+        output += ["    %s, %s, %s, %s,"
+                   % (f['mask'], f['string'], f['prereqs'], rw)]
+
+        nxm = f['NXM']
+        oxm = f['OXM']
+        if not nxm:
+            nxm = oxm
+        elif not oxm:
+            oxm = nxm
+        if nxm:
+            output += ["    %s, \"%s\"," % (nxm[0], nxm[1])]
+            output += ["    %s, \"%s\", %s," % (oxm[0], oxm[1], oxm[2])]
+        else:
+            output += ["    0, NULL, 0, NULL, 0, /* no NXM or OXM */"]
+
+        of10 = f['OF1.0']
+        of11 = f['OF1.1']
+        if f['mff'] in ('MFF_DL_VLAN', 'MFF_DL_VLAN_PCP'):
+            # MFF_DL_VLAN and MFF_DL_VLAN_PCP don't exactly correspond to
+            # OF1.1, nor do they have NXM or OXM assignments, but their
+            # meanings can be expressed in every protocol, which is the goal of
+            # this member.
+            protocols = set(["of10", "of11", "oxm"])
+        else:
+            protocols = set([])
+            if of10:
+                protocols |= set(["of10"])
+            if of11:
+                protocols |= set(["of11"])
+            if nxm or oxm:
+                protocols |= set(["oxm"])
+
+        if f['mask'] == 'MFM_FULLY':
+            cidr_protocols = protocols.copy()
+            bitwise_protocols = protocols.copy()
+
+            if of10 == 'exact match':
+                bitwise_protocols -= set(['of10'])
+                cidr_protocols -= set(['of10'])
+            elif of10 == 'CIDR mask':
+                bitwise_protocols -= set(['of10'])
+            else:
+                assert of10 is None
+
+            if of11 == 'exact match':
+                bitwise_protocols -= set(['of11'])
+                cidr_protocols -= set(['of11'])
+            else:
+                assert of11 in (None, 'bitwise mask')
+        else:
+            assert f['mask'] == 'MFM_NONE'
+            cidr_protocols = set([])
+            bitwise_protocols = set([])
+
+        output += ["    %s," % protocols_to_c(protocols)]
+        output += ["    %s," % protocols_to_c(cidr_protocols)]
+        output += ["    %s," % protocols_to_c(bitwise_protocols)]
+        
+        if f['prefix']:
+            output += ["    FLOW_U32OFS(%s)," % f['prefix']]
+        else:
+            output += ["    -1, /* not usable for prefix lookup */"]
+
+        output += ["},"]
+
+    if n_errors:
+        sys.exit(1)
+
+    return output
+
+
+if __name__ == '__main__':
+    if '--help' in sys.argv:
+        usage()
+    elif len(sys.argv) != 2:
+        sys.stderr.write("exactly one non-option argument required; "
+                         "use --help for help\n")
+        sys.exit(1)
+    else:
+        global file_name
+        global input_file
+        global line_number
+        file_name = sys.argv[1]
+        input_file = open(file_name)
+        line_number = 0
+
+        for line in extract_ofp_fields():
+            print line
+        
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index bbf3388..b1885b2 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -482,406 +482,13 @@ OFP_ASSERT(sizeof(struct nx_async_config) == 24);
 #define NXM_MAKE_WILD_HEADER(HEADER) \
         NXM_HEADER_W(NXM_VENDOR(HEADER), NXM_FIELD(HEADER), NXM_LENGTH(HEADER))
 
-/* ## ------------------------------- ## */
-/* ## OpenFlow 1.0-compatible fields. ## */
-/* ## ------------------------------- ## */
-
-/* Physical or virtual port on which the packet was received.
- *
- * Prereqs: None.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Not maskable. */
-#define NXM_OF_IN_PORT    NXM_HEADER  (0x0000,  0, 2)
-
-/* Source or destination address in Ethernet header.
- *
- * Prereqs: None.
- *
- * Format: 48-bit Ethernet MAC address.
- *
- * Masking: Fully maskable, in versions 1.8 and later. Earlier versions only
- *   supported the following masks for NXM_OF_ETH_DST_W: 00:00:00:00:00:00,
- *   fe:ff:ff:ff:ff:ff, 01:00:00:00:00:00, ff:ff:ff:ff:ff:ff. */
-#define NXM_OF_ETH_DST    NXM_HEADER  (0x0000,  1, 6)
-#define NXM_OF_ETH_DST_W  NXM_HEADER_W(0x0000,  1, 6)
-#define NXM_OF_ETH_SRC    NXM_HEADER  (0x0000,  2, 6)
-#define NXM_OF_ETH_SRC_W  NXM_HEADER_W(0x0000,  2, 6)
-
-/* Packet's Ethernet type.
- *
- * For an Ethernet II packet this is taken from the Ethernet header.  For an
- * 802.2 LLC+SNAP header with OUI 00-00-00 this is taken from the SNAP header.
- * A packet that has neither format has value 0x05ff
- * (OFP_DL_TYPE_NOT_ETH_TYPE).
- *
- * For a packet with an 802.1Q header, this is the type of the encapsulated
- * frame.
- *
- * Prereqs: None.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Not maskable. */
-#define NXM_OF_ETH_TYPE   NXM_HEADER  (0x0000,  3, 2)
-
-/* 802.1Q TCI.
- *
- * For a packet with an 802.1Q header, this is the Tag Control Information
- * (TCI) field, with the CFI bit forced to 1.  For a packet with no 802.1Q
- * header, this has value 0.
- *
- * Prereqs: None.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Arbitrary masks.
- *
- * This field can be used in various ways:
- *
- *   - If it is not constrained at all, the nx_match matches packets without
- *     an 802.1Q header or with an 802.1Q header that has any TCI value.
- *
- *   - Testing for an exact match with 0 matches only packets without an
- *     802.1Q header.
- *
- *   - Testing for an exact match with a TCI value with CFI=1 matches packets
- *     that have an 802.1Q header with a specified VID and PCP.
- *
- *   - Testing for an exact match with a nonzero TCI value with CFI=0 does
- *     not make sense.  The switch may reject this combination.
- *
- *   - Testing with a specific VID and CFI=1, with nxm_mask=0x1fff, matches
- *     packets that have an 802.1Q header with that VID (and any PCP).
- *
- *   - Testing with a specific PCP and CFI=1, with nxm_mask=0xf000, matches
- *     packets that have an 802.1Q header with that PCP (and any VID).
- *
- *   - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q
- *     header or with an 802.1Q header with a VID of 0.
- *
- *   - Testing with nxm_value=0, nxm_mask=0xe000 matches packets with no 802.1Q
- *     header or with an 802.1Q header with a PCP of 0.
- *
- *   - Testing with nxm_value=0, nxm_mask=0xefff matches packets with no 802.1Q
- *     header or with an 802.1Q header with both VID and PCP of 0.
- */
-#define NXM_OF_VLAN_TCI   NXM_HEADER  (0x0000,  4, 2)
-#define NXM_OF_VLAN_TCI_W NXM_HEADER_W(0x0000,  4, 2)
-
-/* The "type of service" byte of the IP header, with the ECN bits forced to 0.
- *
- * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *
- * Format: 8-bit integer with 2 least-significant bits forced to 0.
- *
- * Masking: Not maskable. */
-#define NXM_OF_IP_TOS     NXM_HEADER  (0x0000,  5, 1)
-
-/* The "protocol" byte in the IP header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *
- * Format: 8-bit integer.
- *
- * Masking: Not maskable. */
-#define NXM_OF_IP_PROTO   NXM_HEADER  (0x0000,  6, 1)
-
-/* The source or destination address in the IP header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match 0x0800 exactly.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: Fully maskable, in Open vSwitch 1.8 and later.  In earlier
- *   versions, only CIDR masks are allowed, that is, masks that consist of N
- *   high-order bits set to 1 and the other 32-N bits set to 0. */
-#define NXM_OF_IP_SRC     NXM_HEADER  (0x0000,  7, 4)
-#define NXM_OF_IP_SRC_W   NXM_HEADER_W(0x0000,  7, 4)
-#define NXM_OF_IP_DST     NXM_HEADER  (0x0000,  8, 4)
-#define NXM_OF_IP_DST_W   NXM_HEADER_W(0x0000,  8, 4)
-
-/* The source or destination port in the TCP header.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *   NXM_OF_IP_PROTO must match 6 exactly.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Fully maskable, in Open vSwitch 1.6 and later.  Not maskable, in
- *   earlier versions. */
-#define NXM_OF_TCP_SRC    NXM_HEADER  (0x0000,  9, 2)
-#define NXM_OF_TCP_SRC_W  NXM_HEADER_W(0x0000,  9, 2)
-#define NXM_OF_TCP_DST    NXM_HEADER  (0x0000, 10, 2)
-#define NXM_OF_TCP_DST_W  NXM_HEADER_W(0x0000, 10, 2)
-
-/* The source or destination port in the UDP header.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd.
- *   NXM_OF_IP_PROTO must match 17 exactly.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Fully maskable, in Open vSwitch 1.6 and later.  Not maskable, in
- *   earlier versions. */
-#define NXM_OF_UDP_SRC    NXM_HEADER  (0x0000, 11, 2)
-#define NXM_OF_UDP_SRC_W  NXM_HEADER_W(0x0000, 11, 2)
-#define NXM_OF_UDP_DST    NXM_HEADER  (0x0000, 12, 2)
-#define NXM_OF_UDP_DST_W  NXM_HEADER_W(0x0000, 12, 2)
-
-/* The type or code in the ICMP header.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match 0x0800 exactly.
- *   NXM_OF_IP_PROTO must match 1 exactly.
- *
- * Format: 8-bit integer.
- *
- * Masking: Not maskable. */
-#define NXM_OF_ICMP_TYPE  NXM_HEADER  (0x0000, 13, 1)
-#define NXM_OF_ICMP_CODE  NXM_HEADER  (0x0000, 14, 1)
-
-/* ARP opcode.
- *
- * For an Ethernet+IP ARP packet, the opcode in the ARP header.  Always 0
- * otherwise.  Only ARP opcodes between 1 and 255 should be specified for
- * matching.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match either 0x0806 or 0x8035.
- *
- * Format: 16-bit integer in network byte order.
- *
- * Masking: Not maskable. */
-#define NXM_OF_ARP_OP     NXM_HEADER  (0x0000, 15, 2)
-
-/* For an Ethernet+IP ARP packet, the source or target protocol address
- * in the ARP header.  Always 0 otherwise.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match either 0x0806 or 0x8035.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: Fully maskable, in Open vSwitch 1.8 and later.  In earlier
- *   versions, only CIDR masks are allowed, that is, masks that consist of N
- *   high-order bits set to 1 and the other 32-N bits set to 0. */
-#define NXM_OF_ARP_SPA    NXM_HEADER  (0x0000, 16, 4)
-#define NXM_OF_ARP_SPA_W  NXM_HEADER_W(0x0000, 16, 4)
-#define NXM_OF_ARP_TPA    NXM_HEADER  (0x0000, 17, 4)
-#define NXM_OF_ARP_TPA_W  NXM_HEADER_W(0x0000, 17, 4)
-
-/* ## ------------------------ ## */
-/* ## Nicira match extensions. ## */
-/* ## ------------------------ ## */
-
-/* Metadata registers.
- *
- * Registers initially have value 0.  Actions allow register values to be
- * manipulated.
- *
- * Prereqs: None.
- *
- * Format: Array of 32-bit integer registers.  Space is reserved for up to
- *   NXM_NX_MAX_REGS registers, but switches may implement fewer.
- *
- * Masking: Arbitrary masks. */
+/* Number of registers allocated NXM field IDs. */
 #define NXM_NX_MAX_REGS 16
-#define NXM_NX_REG(IDX)   NXM_HEADER  (0x0001, IDX, 4)
-#define NXM_NX_REG_W(IDX) NXM_HEADER_W(0x0001, IDX, 4)
-#define NXM_NX_REG_IDX(HEADER) NXM_FIELD(HEADER)
-#define NXM_IS_NX_REG(HEADER) (!((((HEADER) ^ NXM_NX_REG0)) & 0xffffe1ff))
-#define NXM_IS_NX_REG_W(HEADER) (!((((HEADER) ^ NXM_NX_REG0_W)) & 0xffffe1ff))
-#define NXM_NX_REG0       NXM_HEADER  (0x0001, 0, 4)
-#define NXM_NX_REG0_W     NXM_HEADER_W(0x0001, 0, 4)
-#define NXM_NX_REG1       NXM_HEADER  (0x0001, 1, 4)
-#define NXM_NX_REG1_W     NXM_HEADER_W(0x0001, 1, 4)
-#define NXM_NX_REG2       NXM_HEADER  (0x0001, 2, 4)
-#define NXM_NX_REG2_W     NXM_HEADER_W(0x0001, 2, 4)
-#define NXM_NX_REG3       NXM_HEADER  (0x0001, 3, 4)
-#define NXM_NX_REG3_W     NXM_HEADER_W(0x0001, 3, 4)
-#define NXM_NX_REG4       NXM_HEADER  (0x0001, 4, 4)
-#define NXM_NX_REG4_W     NXM_HEADER_W(0x0001, 4, 4)
-#define NXM_NX_REG5       NXM_HEADER  (0x0001, 5, 4)
-#define NXM_NX_REG5_W     NXM_HEADER_W(0x0001, 5, 4)
-#define NXM_NX_REG6       NXM_HEADER  (0x0001, 6, 4)
-#define NXM_NX_REG6_W     NXM_HEADER_W(0x0001, 6, 4)
-#define NXM_NX_REG7       NXM_HEADER  (0x0001, 7, 4)
-#define NXM_NX_REG7_W     NXM_HEADER_W(0x0001, 7, 4)
-
-/* Tunnel ID.
- *
- * For a packet received via a Geneve, GRE, VXLAN or LISP tunnel including a
- * key less than 64 bits, the key is stored in the low bits and the high bits
- * are zeroed.  For other packets, the value is 0.
- *
- * All zero bits, for packets not received via a keyed tunnel.
- *
- * Prereqs: None.
- *
- * Format: 64-bit integer in network byte order.
- *
- * Masking: Arbitrary masks. */
-#define NXM_NX_TUN_ID     NXM_HEADER  (0x0001, 16, 8)
-#define NXM_NX_TUN_ID_W   NXM_HEADER_W(0x0001, 16, 8)
-
-/* For an Ethernet+IP ARP packet, the source or target hardware address
- * in the ARP header.  Always 0 otherwise.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match either 0x0806 or 0x8035.
- *
- * Format: 48-bit Ethernet MAC address.
- *
- * Masking: Not maskable. */
-#define NXM_NX_ARP_SHA    NXM_HEADER  (0x0001, 17, 6)
-#define NXM_NX_ARP_THA    NXM_HEADER  (0x0001, 18, 6)
-
-/* The source or destination address in the IPv6 header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *
- * Format: 128-bit IPv6 address.
- *
- * Masking: Fully maskable, in Open vSwitch 1.8 and later.  In previous
- *   versions, only CIDR masks are allowed, that is, masks that consist of N
- *   high-order bits set to 1 and the other 128-N bits set to 0. */
-#define NXM_NX_IPV6_SRC    NXM_HEADER  (0x0001, 19, 16)
-#define NXM_NX_IPV6_SRC_W  NXM_HEADER_W(0x0001, 19, 16)
-#define NXM_NX_IPV6_DST    NXM_HEADER  (0x0001, 20, 16)
-#define NXM_NX_IPV6_DST_W  NXM_HEADER_W(0x0001, 20, 16)
-
-/* The type or code in the ICMPv6 header.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *   NXM_OF_IP_PROTO must match 58 exactly.
- *
- * Format: 8-bit integer.
- *
- * Masking: Not maskable. */
-#define NXM_NX_ICMPV6_TYPE NXM_HEADER  (0x0001, 21, 1)
-#define NXM_NX_ICMPV6_CODE NXM_HEADER  (0x0001, 22, 1)
-
-/* The target address in an IPv6 Neighbor Discovery message.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *   NXM_OF_IP_PROTO must match 58 exactly.
- *   NXM_OF_ICMPV6_TYPE must be either 135 or 136.
- *
- * Format: 128-bit IPv6 address.
- *
- * Masking: Fully maskable, in Open vSwitch 1.8 and later.  In previous
- *   versions, only CIDR masks are allowed, that is, masks that consist of N
- *   high-order bits set to 1 and the other 128-N bits set to 0. */
-#define NXM_NX_ND_TARGET     NXM_HEADER    (0x0001, 23, 16)
-#define NXM_NX_ND_TARGET_W   NXM_HEADER_W  (0x0001, 23, 16)
-
-/* The source link-layer address option in an IPv6 Neighbor Discovery
- * message.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *   NXM_OF_IP_PROTO must match 58 exactly.
- *   NXM_OF_ICMPV6_TYPE must be exactly 135.
- *
- * Format: 48-bit Ethernet MAC address.
- *
- * Masking: Not maskable. */
-#define NXM_NX_ND_SLL      NXM_HEADER  (0x0001, 24, 6)
-
-/* The target link-layer address option in an IPv6 Neighbor Discovery
- * message.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *   NXM_OF_IP_PROTO must match 58 exactly.
- *   NXM_OF_ICMPV6_TYPE must be exactly 136.
- *
- * Format: 48-bit Ethernet MAC address.
- *
- * Masking: Not maskable. */
-#define NXM_NX_ND_TLL      NXM_HEADER  (0x0001, 25, 6)
-
-/* IP fragment information.
- *
- * Prereqs:
- *   NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *
- * Format: 8-bit value with one of the values 0, 1, or 3, as described below.
- *
- * Masking: Fully maskable.
- *
- * This field has three possible values:
- *
- *   - A packet that is not an IP fragment has value 0.
- *
- *   - A packet that is an IP fragment with offset 0 (the first fragment) has
- *     bit 0 set and thus value 1.
- *
- *   - A packet that is an IP fragment with nonzero offset has bits 0 and 1 set
- *     and thus value 3.
- *
- * NX_IP_FRAG_ANY and NX_IP_FRAG_LATER are declared to symbolically represent
- * the meanings of bits 0 and 1.
- *
- * The switch may reject matches against values that can never appear.
- *
- * It is important to understand how this field interacts with the OpenFlow IP
- * fragment handling mode:
- *
- *   - In OFPC_FRAG_DROP mode, the OpenFlow switch drops all IP fragments
- *     before they reach the flow table, so every packet that is available for
- *     matching will have value 0 in this field.
- *
- *   - Open vSwitch does not implement OFPC_FRAG_REASM mode, but if it did then
- *     IP fragments would be reassembled before they reached the flow table and
- *     again every packet available for matching would always have value 0.
- *
- *   - In OFPC_FRAG_NORMAL mode, all three values are possible, but OpenFlow
- *     1.0 says that fragments' transport ports are always 0, even for the
- *     first fragment, so this does not provide much extra information.
- *
- *   - In OFPC_FRAG_NX_MATCH mode, all three values are possible.  For
- *     fragments with offset 0, Open vSwitch makes L4 header information
- *     available.
- */
-#define NXM_NX_IP_FRAG     NXM_HEADER  (0x0001, 26, 1)
-#define NXM_NX_IP_FRAG_W   NXM_HEADER_W(0x0001, 26, 1)
 
 /* Bits in the value of NXM_NX_IP_FRAG. */
 #define NX_IP_FRAG_ANY   (1 << 0) /* Is this a fragment? */
 #define NX_IP_FRAG_LATER (1 << 1) /* Is this a fragment with nonzero offset? */
 
-/* The flow label in the IPv6 header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must match 0x86dd exactly.
- *
- * Format: 20-bit IPv6 flow label in least-significant bits.
- *
- * Masking: Fully maskable. */
-#define NXM_NX_IPV6_LABEL   NXM_HEADER  (0x0001, 27, 4)
-#define NXM_NX_IPV6_LABEL_W NXM_HEADER_W(0x0001, 27, 4)
-
-/* The ECN of the IP header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *
- * Format: ECN in the low-order 2 bits.
- *
- * Masking: Not maskable. */
-#define NXM_NX_IP_ECN      NXM_HEADER  (0x0001, 28, 1)
-
-/* The time-to-live/hop limit of the IP header.
- *
- * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
- *
- * Format: 8-bit integer.
- *
- * Masking: Not maskable. */
-#define NXM_NX_IP_TTL      NXM_HEADER  (0x0001, 29, 1)
-
 /* Flow cookie.
  *
  * This may be used to gain the OpenFlow 1.1-like ability to restrict
@@ -898,75 +505,6 @@ OFP_ASSERT(sizeof(struct nx_async_config) == 24);
 #define NXM_NX_COOKIE     NXM_HEADER  (0x0001, 30, 8)
 #define NXM_NX_COOKIE_W   NXM_HEADER_W(0x0001, 30, 8)
 
-/* The source or destination address in the outer IP header of a tunneled
- * packet.
- *
- * For non-tunneled packets, the value is 0.
- *
- * Prereqs: None.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: Fully maskable. */
-#define NXM_NX_TUN_IPV4_SRC   NXM_HEADER  (0x0001, 31, 4)
-#define NXM_NX_TUN_IPV4_SRC_W NXM_HEADER_W(0x0001, 31, 4)
-#define NXM_NX_TUN_IPV4_DST   NXM_HEADER  (0x0001, 32, 4)
-#define NXM_NX_TUN_IPV4_DST_W NXM_HEADER_W(0x0001, 32, 4)
-
-/* Metadata marked onto the packet in a system-dependent manner.
- *
- * The packet mark may be used to carry contextual information
- * to other parts of the system outside of Open vSwitch. As a
- * result, the semantics depend on system in use.
- *
- * Prereqs: None.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: Fully maskable. */
-#define NXM_NX_PKT_MARK   NXM_HEADER  (0x0001, 33, 4)
-#define NXM_NX_PKT_MARK_W NXM_HEADER_W(0x0001, 33, 4)
-
-/* The flags in the TCP header.
-*
-* Prereqs:
-*   NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd.
-*   NXM_OF_IP_PROTO must match 6 exactly.
-*
-* Format: 16-bit integer with 4 most-significant bits forced to 0.
-*
-* Masking: Bits 0-11 fully maskable. */
-#define NXM_NX_TCP_FLAGS   NXM_HEADER  (0x0001, 34, 2)
-#define NXM_NX_TCP_FLAGS_W NXM_HEADER_W(0x0001, 34, 2)
-
-/* Metadata dp_hash.
- *
- * Internal use only, not programable from controller.
- *
- * The dp_hash is used to carry the flow hash computed in the
- * datapath.
- *
- * Prereqs: None.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: Fully maskable. */
-#define NXM_NX_DP_HASH   NXM_HEADER  (0x0001, 35, 4)
-#define NXM_NX_DP_HASH_W NXM_HEADER_W(0x0001, 35, 4)
-
-/* Metadata recirc_id.
- *
- * Internal use only, not programable from controller.
- *
- * The recirc_id used for recirculation. 0 is reserved
- * for initially received packet.
- *
- * Prereqs: None.
- *
- * Format: 32-bit integer in network byte order.
- *
- * Masking: not maskable. */
-#define NXM_NX_RECIRC_ID   NXM_HEADER  (0x0001, 36, 4)
 
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h
index 58be0b5..ef1d340 100644
--- a/include/openflow/openflow-1.2.h
+++ b/include/openflow/openflow-1.2.h
@@ -72,131 +72,8 @@ enum ofp12_oxm_class {
     OFPXMC12_EXPERIMENTER   = 0xffff, /* Experimenter class */
 };
 
-/* OXM Flow match field types for OpenFlow basic class. */
-enum oxm12_ofb_match_fields {
-    OFPXMT12_OFB_IN_PORT,        /* Switch input port. */
-    OFPXMT12_OFB_IN_PHY_PORT,    /* Switch physical input port. */
-    OFPXMT12_OFB_METADATA,       /* Metadata passed between tables. */
-    OFPXMT12_OFB_ETH_DST,        /* Ethernet destination address. */
-    OFPXMT12_OFB_ETH_SRC,        /* Ethernet source address. */
-    OFPXMT12_OFB_ETH_TYPE,       /* Ethernet frame type. */
-    OFPXMT12_OFB_VLAN_VID,       /* VLAN id. */
-    OFPXMT12_OFB_VLAN_PCP,       /* VLAN priority. */
-    OFPXMT12_OFB_IP_DSCP,        /* IP DSCP (6 bits in ToS field). */
-    OFPXMT12_OFB_IP_ECN,         /* IP ECN (2 bits in ToS field). */
-    OFPXMT12_OFB_IP_PROTO,       /* IP protocol. */
-    OFPXMT12_OFB_IPV4_SRC,       /* IPv4 source address. */
-    OFPXMT12_OFB_IPV4_DST,       /* IPv4 destination address. */
-    OFPXMT12_OFB_TCP_SRC,        /* TCP source port. */
-    OFPXMT12_OFB_TCP_DST,        /* TCP destination port. */
-    OFPXMT12_OFB_UDP_SRC,        /* UDP source port. */
-    OFPXMT12_OFB_UDP_DST,        /* UDP destination port. */
-    OFPXMT12_OFB_SCTP_SRC,       /* SCTP source port. */
-    OFPXMT12_OFB_SCTP_DST,       /* SCTP destination port. */
-    OFPXMT12_OFB_ICMPV4_TYPE,    /* ICMP type. */
-    OFPXMT12_OFB_ICMPV4_CODE,    /* ICMP code. */
-    OFPXMT12_OFB_ARP_OP,         /* ARP opcode. */
-    OFPXMT12_OFB_ARP_SPA,        /* ARP source IPv4 address. */
-    OFPXMT12_OFB_ARP_TPA,        /* ARP target IPv4 address. */
-    OFPXMT12_OFB_ARP_SHA,        /* ARP source hardware address. */
-    OFPXMT12_OFB_ARP_THA,        /* ARP target hardware address. */
-    OFPXMT12_OFB_IPV6_SRC,       /* IPv6 source address. */
-    OFPXMT12_OFB_IPV6_DST,       /* IPv6 destination address. */
-    OFPXMT12_OFB_IPV6_FLABEL,    /* IPv6 Flow Label */
-    OFPXMT12_OFB_ICMPV6_TYPE,    /* ICMPv6 type. */
-    OFPXMT12_OFB_ICMPV6_CODE,    /* ICMPv6 code. */
-    OFPXMT12_OFB_IPV6_ND_TARGET, /* Target address for ND. */
-    OFPXMT12_OFB_IPV6_ND_SLL,    /* Source link-layer for ND. */
-    OFPXMT12_OFB_IPV6_ND_TLL,    /* Target link-layer for ND. */
-    OFPXMT12_OFB_MPLS_LABEL,     /* MPLS label. */
-    OFPXMT12_OFB_MPLS_TC,        /* MPLS TC. */
-
-    /* Following added in OpenFlow 1.3 */
-    OFPXMT13_OFB_MPLS_BOS,       /* MPLS BoS bit. */
-    OFPXMT13_OFB_PBB_ISID,       /* PBB I-SID. */
-    OFPXMT13_OFB_TUNNEL_ID,      /* Logical Port Metadata */
-    OFPXMT13_OFB_IPV6_EXTHDR,    /* IPv6 Extension Header pseudo-field */
-
-    /* Following added in OpenFlow 1.4. */
-    OFPXMT14_OFB_PBB_UCA = 41,  /* PBB UCA header field. */
-
-    /* Following added in OpenFlow 1.5. */
-    OFPXMT15_OFB_TCP_FLAGS = 42,  /* TCP flags. */
- };
-
-/* OXM implementation makes use of NXM as they are the same format
- * with different field definitions
- */
-
-#define OXM_HEADER(FIELD, LENGTH) \
-    NXM_HEADER(OFPXMC12_OPENFLOW_BASIC, FIELD, LENGTH)
-#define OXM_HEADER_W(FIELD, LENGTH) \
-    NXM_HEADER_W(OFPXMC12_OPENFLOW_BASIC, FIELD, LENGTH)
-
 #define IS_OXM_HEADER(header) (NXM_VENDOR(header) == OFPXMC12_OPENFLOW_BASIC)
 
-#define OXM_OF_IN_PORT        OXM_HEADER   (OFPXMT12_OFB_IN_PORT, 4)
-#define OXM_OF_IN_PHY_PORT    OXM_HEADER   (OFPXMT12_OFB_IN_PHY_PORT, 4)
-#define OXM_OF_METADATA       OXM_HEADER   (OFPXMT12_OFB_METADATA, 8)
-#define OXM_OF_ETH_DST        OXM_HEADER   (OFPXMT12_OFB_ETH_DST, 6)
-#define OXM_OF_ETH_DST_W      OXM_HEADER_W (OFPXMT12_OFB_ETH_DST, 6)
-#define OXM_OF_ETH_SRC        OXM_HEADER   (OFPXMT12_OFB_ETH_SRC, 6)
-#define OXM_OF_ETH_SRC_W      OXM_HEADER_W (OFPXMT12_OFB_ETH_SRC, 6)
-#define OXM_OF_ETH_TYPE       OXM_HEADER   (OFPXMT12_OFB_ETH_TYPE, 2)
-#define OXM_OF_VLAN_VID       OXM_HEADER   (OFPXMT12_OFB_VLAN_VID, 2)
-#define OXM_OF_VLAN_VID_W     OXM_HEADER_W (OFPXMT12_OFB_VLAN_VID, 2)
-#define OXM_OF_VLAN_PCP       OXM_HEADER   (OFPXMT12_OFB_VLAN_PCP, 1)
-#define OXM_OF_IP_DSCP        OXM_HEADER   (OFPXMT12_OFB_IP_DSCP, 1)
-#define OXM_OF_IP_ECN         OXM_HEADER   (OFPXMT12_OFB_IP_ECN, 1)
-#define OXM_OF_IP_PROTO       OXM_HEADER   (OFPXMT12_OFB_IP_PROTO, 1)
-#define OXM_OF_IPV4_SRC       OXM_HEADER   (OFPXMT12_OFB_IPV4_SRC, 4)
-#define OXM_OF_IPV4_SRC_W     OXM_HEADER_W (OFPXMT12_OFB_IPV4_SRC, 4)
-#define OXM_OF_IPV4_DST       OXM_HEADER   (OFPXMT12_OFB_IPV4_DST, 4)
-#define OXM_OF_IPV4_DST_W     OXM_HEADER_W (OFPXMT12_OFB_IPV4_DST, 4)
-#define OXM_OF_TCP_SRC        OXM_HEADER   (OFPXMT12_OFB_TCP_SRC, 2)
-#define OXM_OF_TCP_DST        OXM_HEADER   (OFPXMT12_OFB_TCP_DST, 2)
-#define OXM_OF_UDP_SRC        OXM_HEADER   (OFPXMT12_OFB_UDP_SRC, 2)
-#define OXM_OF_UDP_DST        OXM_HEADER   (OFPXMT12_OFB_UDP_DST, 2)
-#define OXM_OF_SCTP_SRC       OXM_HEADER   (OFPXMT12_OFB_SCTP_SRC, 2)
-#define OXM_OF_SCTP_DST       OXM_HEADER   (OFPXMT12_OFB_SCTP_DST, 2)
-#define OXM_OF_ICMPV4_TYPE    OXM_HEADER   (OFPXMT12_OFB_ICMPV4_TYPE, 1)
-#define OXM_OF_ICMPV4_CODE    OXM_HEADER   (OFPXMT12_OFB_ICMPV4_CODE, 1)
-#define OXM_OF_ARP_OP         OXM_HEADER   (OFPXMT12_OFB_ARP_OP, 2)
-#define OXM_OF_ARP_SPA        OXM_HEADER   (OFPXMT12_OFB_ARP_SPA, 4)
-#define OXM_OF_ARP_SPA_W      OXM_HEADER_W (OFPXMT12_OFB_ARP_SPA, 4)
-#define OXM_OF_ARP_TPA        OXM_HEADER   (OFPXMT12_OFB_ARP_TPA, 4)
-#define OXM_OF_ARP_TPA_W      OXM_HEADER_W (OFPXMT12_OFB_ARP_TPA, 4)
-#define OXM_OF_ARP_SHA        OXM_HEADER   (OFPXMT12_OFB_ARP_SHA, 6)
-#define OXM_OF_ARP_SHA_W      OXM_HEADER_W (OFPXMT12_OFB_ARP_SHA, 6)
-#define OXM_OF_ARP_THA        OXM_HEADER   (OFPXMT12_OFB_ARP_THA, 6)
-#define OXM_OF_ARP_THA_W      OXM_HEADER_W (OFPXMT12_OFB_ARP_THA, 6)
-#define OXM_OF_IPV6_SRC       OXM_HEADER   (OFPXMT12_OFB_IPV6_SRC, 16)
-#define OXM_OF_IPV6_SRC_W     OXM_HEADER_W (OFPXMT12_OFB_IPV6_SRC, 16)
-#define OXM_OF_IPV6_DST       OXM_HEADER   (OFPXMT12_OFB_IPV6_DST, 16)
-#define OXM_OF_IPV6_DST_W     OXM_HEADER_W (OFPXMT12_OFB_IPV6_DST, 16)
-#define OXM_OF_IPV6_FLABEL    OXM_HEADER   (OFPXMT12_OFB_IPV6_FLABEL, 4)
-#define OXM_OF_IPV6_FLABEL_W  OXM_HEADER_W (OFPXMT12_OFB_IPV6_FLABEL, 4)
-#define OXM_OF_ICMPV6_TYPE    OXM_HEADER   (OFPXMT12_OFB_ICMPV6_TYPE, 1)
-#define OXM_OF_ICMPV6_CODE    OXM_HEADER   (OFPXMT12_OFB_ICMPV6_CODE, 1)
-#define OXM_OF_IPV6_ND_TARGET OXM_HEADER   (OFPXMT12_OFB_IPV6_ND_TARGET, 16)
-#define OXM_OF_IPV6_ND_SLL    OXM_HEADER   (OFPXMT12_OFB_IPV6_ND_SLL, 6)
-#define OXM_OF_IPV6_ND_TLL    OXM_HEADER   (OFPXMT12_OFB_IPV6_ND_TLL, 6)
-#define OXM_OF_MPLS_LABEL     OXM_HEADER   (OFPXMT12_OFB_MPLS_LABEL, 4)
-#define OXM_OF_MPLS_TC        OXM_HEADER   (OFPXMT12_OFB_MPLS_TC, 1)
-#define OXM_OF_MPLS_BOS       OXM_HEADER   (OFPXMT13_OFB_MPLS_BOS, 1)
-#define OXM_OF_PBB_ISID       OXM_HEADER   (OFPXMT12_OFB_PBB_ISID, 3)
-#define OXM_OF_PBB_ISID_W     OXM_HEADER_W (OFPXMT12_OFB_PBB_ISID, 3)
-#define OXM_OF_TUNNEL_ID      OXM_HEADER   (OFPXMT13_OFB_TUNNEL_ID, 8)
-#define OXM_OF_TUNNEL_ID_W    OXM_HEADER_W (OFPXMT13_OFB_TUNNEL_ID, 8)
-#define OXM_OF_IPV6_EXTHDR    OXM_HEADER   (OFPXMT13_OFB_IPV6_EXTHDR, 2)
-#define OXM_OF_IPV6_EXTHDR_W  OXM_HEADER_W (OFPXMT13_OFB_IPV6_EXTHDR, 2)
-#define OXM_OF_PBB_UCA        OXM_HEADER   (OFPXMT14_OFB_PBB_UCA, 1)
-#define OXM_OF_TCP_FLAGS      OXM_HEADER   (OFPXMT15_OFB_TCP_FLAGS, 2)
-#define OXM_OF_TCP_FLAGS_W    OXM_HEADER_W (OFPXMT15_OFB_TCP_FLAGS, 2)
-
-#define OXM_OF_PKT_REG(N)    (NXM_HEADER  (OFPXMC15_PACKET_REGS, N, 8))
-#define OXM_OF_PKT_REG_W(N)  (NXM_HEADER_W(OFPXMC15_PACKET_REGS, N, 8))
-
 /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
  * special conditions.
  */
diff --git a/lib/automake.mk b/lib/automake.mk
index b14a510..06bef2a 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -441,13 +441,19 @@ lib/dirs.c: lib/dirs.c.in Makefile
 	     > lib/dirs.c.tmp
 	mv lib/dirs.c.tmp lib/dirs.c
 
+lib/meta-flow.inc: $(srcdir)/build-aux/extract-ofp-fields lib/meta-flow.h
+	$(AM_V_GEN)$(run_python) $^ > $@.tmp && mv $@.tmp $@
+lib/meta-flow.lo: lib/meta-flow.inc
+CLEANFILES += lib/meta-flow.inc
+EXTRA_DIST += build-aux/extract-ofp-fields
+
 lib/ofp-actions.inc1: $(srcdir)/build-aux/extract-ofp-actions lib/ofp-actions.c
 	$(run_python) $^ --prototypes > $@.tmp && mv $@.tmp $@
 lib/ofp-actions.inc2: $(srcdir)/build-aux/extract-ofp-actions lib/ofp-actions.c
 	$(run_python) $^ --definitions > $@.tmp && mv $@.tmp $@
 lib/ofp-actions.lo: lib/ofp-actions.inc1 lib/ofp-actions.inc2
 CLEANFILES += lib/ofp-actions.inc1 lib/ofp-actions.inc2
-EXTRA_DIST += build-aux/extract-ofp-actions lib/ofp-errors.inc
+EXTRA_DIST += build-aux/extract-ofp-actions
 
 $(srcdir)/lib/ofp-errors.inc: \
 	lib/ofp-errors.h include/openflow/openflow-common.h \
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 3b82e62..1dc6d7e 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -47,755 +47,7 @@ VLOG_DEFINE_THIS_MODULE(meta_flow);
 extern const struct mf_field mf_fields[MFF_N_IDS]; /* Silence a warning. */
 
 const struct mf_field mf_fields[MFF_N_IDS] = {
-    /* ## -------- ## */
-    /* ## metadata ## */
-    /* ## -------- ## */
-
-    {
-        MFF_DP_HASH, "dp_hash", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_FULLY,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        false,
-        NXM_NX_DP_HASH, "NXM_NX_DP_HASH",
-        NXM_NX_DP_HASH, "NXM_NX_DP_HASH", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        MFF_RECIRC_ID, "recirc_id", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        false,
-        NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID",
-        NXM_NX_RECIRC_ID, "NXM_NX_RECIRC_ID", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        MFF_TUN_ID, "tun_id", "tunnel_id",
-        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", OFP13_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        FLOW_U32OFS(tunnel.tun_id),
-    }, {
-        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", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        FLOW_U32OFS(tunnel.ip_src),
-    }, {
-        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", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        FLOW_U32OFS(tunnel.ip_dst),
-    }, {
-        MFF_TUN_FLAGS, "tun_flags", NULL,
-        MF_FIELD_SIZES(be16),
-        MFM_NONE,
-        MFS_TNL_FLAGS,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        MFF_TUN_TTL, "tun_ttl", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        MFF_TUN_TOS, "tun_tos", NULL,
-        MF_FIELD_SIZES(u8),
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OF11_UP,
-        -1,
-    }, {
-        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", 0,
-        OFPUTIL_P_ANY,   /* OF11+ via mapping to 32 bits. */
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_OF11_UP,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        MFF_SKB_PRIORITY, "skb_priority", NULL,
-        MF_FIELD_SIZES(be32),
-        MFM_NONE,
-        MFS_HEXADECIMAL,
-        MFP_NONE,
-        false,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_NONE,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-#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, 0,  \
-        OFPUTIL_P_NXM_OXM_ANY,                  \
-        OFPUTIL_P_NXM_OXM_ANY,                  \
-        -1,                                     \
-    }
-#if FLOW_N_REGS == 8
-    REGISTER(0),
-    REGISTER(1),
-    REGISTER(2),
-    REGISTER(3),
-    REGISTER(4),
-    REGISTER(5),
-    REGISTER(6),
-    REGISTER(7),
-#else
-#error "Need to update mf_fields[] to match FLOW_N_REGS"
-#endif
-
-#define XREGISTER(IDX)                                              \
-    {                                                               \
-        MFF_XREG##IDX, "xreg" #IDX, NULL,                           \
-        MF_FIELD_SIZES(be64),                                       \
-        MFM_FULLY,                                                  \
-        MFS_HEXADECIMAL,                                            \
-        MFP_NONE,                                                   \
-        true,                                                       \
-        OXM_OF_PKT_REG(IDX), "OXM_OF_PKT_REG" #IDX,                 \
-        OXM_OF_PKT_REG(IDX), "OXM_OF_PKT_REG" #IDX, OFP15_VERSION,  \
-        OFPUTIL_P_NXM_OXM_ANY,                                      \
-        OFPUTIL_P_NXM_OXM_ANY,                                      \
-        -1,                                                         \
-    }
-#if FLOW_N_XREGS == 4
-    XREGISTER(0),
-    XREGISTER(1),
-    XREGISTER(2),
-    XREGISTER(3),
-#else
-#error "Need to update mf_fields[] to match FLOW_N_XREGS"
-#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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,   /* Bitwise masking only with NXM and OF11+! */
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    },
-
-    {
-        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", 0,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        MFF_DL_VLAN, "dl_vlan", NULL,
-        sizeof(ovs_be16), 12,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        true,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        MFF_DL_VLAN_PCP, "dl_vlan_pcp", NULL,
-        1, 3,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_NONE,
-        true,
-        0, NULL,
-        0, NULL, 0,
-        OFPUTIL_P_ANY,   /* Will be mapped to NXM and OXM. */
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,   /* Will be mapped to OF10 and NXM. */
-        OFPUTIL_P_NONE,
-        -1,
-    },
-
-    /* ## ---- ## */
-    /* ## 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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP13_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    },
-
-    /* ## -- ## */
-    /* ## 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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-        FLOW_U32OFS(nw_src),
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-        FLOW_U32OFS(nw_dst),
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        FLOW_U32OFS(ipv6_src),
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        FLOW_U32OFS(ipv6_dst),
-    },
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    {
-        MFF_IP_PROTO, "nw_proto", "ip_proto",
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", 0,
-        OFPUTIL_P_ANY,   /* Will be shifted for OXM. */
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        MFF_IP_DSCP_SHIFTED, "ip_dscp", NULL,
-        1, 6,
-        MFM_NONE,
-        MFS_DECIMAL,
-        MFP_IP_ANY,
-        true,
-        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP",
-        OXM_OF_IP_DSCP, "OXM_OF_IP_DSCP", OFP12_VERSION,
-        OFPUTIL_P_ANY,   /* Will be shifted for non-OXM. */
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        MFF_IP_ECN, "nw_ecn", "ip_ecn",
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", 0,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OF11_UP,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    /* ## -- ## */
-    /* ## 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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        MFF_TCP_FLAGS, "tcp_flags", NULL,
-        2, 12,
-        MFM_FULLY,
-        MFS_TCP_FLAGS,
-        MFP_TCP,
-        false,
-        NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
-        OXM_OF_TCP_FLAGS, "OXM_OF_TCP_FLAGS", OFP15_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OF11_UP,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    },
-
-    {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NONE,
-        -1,
-    },
-
-    /* ## ---- ## */
-    /* ## 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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }, {
-        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", OFP12_VERSION,
-        OFPUTIL_P_NXM_OXM_ANY,
-        OFPUTIL_P_NXM_OXM_ANY,
-        -1,
-    }
+#include "meta-flow.inc"
 };
 
 /* Maps an NXM or OXM header value to an mf_field. */
@@ -2132,7 +1384,7 @@ mf_set(const struct mf_field *mf,
 {
     if (!mask || is_all_ones(mask, mf->n_bytes)) {
         mf_set_value(mf, value, match);
-        return mf->usable_protocols;
+        return mf->usable_protocols_exact;
     } else if (is_all_zeros(mask, mf->n_bytes)) {
         mf_set_wild(mf, match);
         return OFPUTIL_P_ANY;
@@ -2231,11 +1483,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);
@@ -2263,11 +1515,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:
@@ -2290,11 +1542,10 @@ mf_set(const struct mf_field *mf,
         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
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index c11f7ab..c443c9c 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -29,116 +29,1309 @@
 struct ds;
 struct match;
 
-/* The comment on each of these indicates the member in "union mf_value" used
- * to represent its value. */
+/* Open vSwitch fields
+ * ===================
+ *
+ * A "field" is a property of a packet.  Most familiarly, "data fields" are
+ * fields that can be extracted from a packet.
+ *
+ * Some data fields are always present as a consequence of the basic networking
+ * technology in use.  Ethernet is the assumed base technology for current
+ * versions of OpenFlow and Open vSwitch, so Ethernet header fields are always
+ * available.
+ *
+ * Other data fields are not always present.  A packet contains ARP fields, for
+ * example, only when its Ethernet header indicates the Ethertype for ARP,
+ * 0x0806.  We say that a field is "applicable" when it is it present in a
+ * packet, and "inapplicable" when it is not, and refer to the conditions that
+ * determine whether a field is applicable as "prerequisites".  Some
+ * VLAN-related fields are a special case: these fields are always applicable,
+ * but have a designated value or bit that indicates whether a VLAN header is
+ * present, with the remaining values or bits indicating the VLAN header's
+ * content (if it is present).  See MFF_VLAN_TCI for an example.
+ *
+ * Conceptually, an inapplicable field does not have a value, not even a
+ * nominal ``value'' such as all-zero-bits.  In many circumstances, OpenFlow
+ * and Open vSwitch allow references only to applicable fields.  For example,
+ * one may match a given field only if the match includes the field's
+ * prerequisite, e.g. matching an ARP field is only allowed if one also matches
+ * on Ethertype 0x0806.
+ *
+ * (Practically, however, OVS represents a field's value as some fixed member
+ * in its "struct flow", so accessing that member will obtain some value.  Some
+ * members are used for more than one purpose, e.g. the "tp_src" member
+ * represents the TCP, UDP, and SCTP source port, so the value read may not
+ * even make sense.  For this reason, it is important to know whether a field's
+ * prerequisites are satisfied before attempting to read it.)
+ *
+ * Sometimes a packet may contain multiple instances of a header.  For example,
+ * a packet may contain multiple VLAN or MPLS headers, and tunnels can cause
+ * any data field to recur.  OpenFlow and Open vSwitch do not address these
+ * cases uniformly.  For VLAN and MPLS headers, only the outermost header is
+ * accessible, so that inner headers may be accessed only by ``popping''
+ * (removing) the outer header.  (Open vSwitch supports only a single VLAN
+ * header in any case.)  For tunnels, e.g. GRE or VXLAN, the outer header and
+ * inner headers are treated as different data fields.
+ *
+ * OpenFlow and Open vSwitch support some fields other than data fields.
+ * "Metadata fields" relate to the origin or treatment of a packet, but they
+ * are not extracted from the packet data itself.  One example is the physical
+ * port on which a packet arrived at the switch.  "Register fields" act like
+ * variables: they give an OpenFlow switch space for temporary storage while
+ * processing a packet.  Existing metadata and register fields have no
+ * prerequisites.
+ *
+ * A field's value consists of an integral number of bytes.  Most data fields
+ * are copied directly from protocol headers, e.g. at layer 2, MFF_ETH_SRC is
+ * copied from the Ethernet source address and MFF_ETH_DST from the destination
+ * address.  Other data fields are copied from a packet with padding, usually
+ * with zeros and in the most significant positions (see e.g. MFF_MPLS_LABEL)
+ * but not always (see e.g. MFF_IP_DSCP).  A final category of data fields is
+ * transformed in other ways as they are copied from the packets, to make them
+ * more useful for matching, e.g. MFF_IP_FRAG describes whether a packet is a
+ * fragment but it is not copied directly from the IP header.
+ *
+ *
+ * Field specifications
+ * ====================
+ *
+ * Each of the enumeration values below represents a field.  The comments
+ * preceding each enum must be in a stylized form that is parsed at compile
+ * time by the extract-ofp-fields program.  The comment itself consists of a
+ * series of paragraphs separate by blank lines.  The paragraphs consist of:
+ *
+ *     - The first paragraph gives the user-visible name of the field as a
+ *       quoted string.  This is the name used for parsing and formatting the
+ *       field.
+ *
+ *       For historical reasons, some fields have an additional name that is
+ *       accepted as an alternative in parsing.  This name, when there is one,
+ *       is given as a quoted string in parentheses along with "aka".  For
+ *       example:
+ *
+ *           "tun_id" (aka "tunnel_id").
+ *
+ *       New fields should have only one name.
+ *
+ *     - Any number of paragraphs of free text that describe the field.  This
+ *       is meant for human readers, so extract-ofp-fields ignores it.
+ *
+ *     - A final paragraph that consists of a series of key-value pairs, one
+ *       per line, in the form "key: value." where the period at the end of the
+ *       line is a mandatory part of the syntax.
+ *
+ * Every field must specify:the following key-value pairs:
+ *
+ *   Type:
+ *
+ *     The format and size of the field's value.  Some possible values are
+ *     generic:
+ *
+ *         u8: A one-byte field.
+ *         be16: A two-byte field.
+ *         be32: A four-byte field.
+ *         be64: An eight-byte field.
+ *
+ *     The remaining values imply more about the value's semantics, though OVS
+ *     does not currently take advantage of this additional information:
+ *
+ *         MAC: A six-byte field whose value is an Ethernet address.
+ *         IPv6: A 16-byte field whose value is an IPv6 address.
+ *
+ *   Maskable:
+ *
+ *     Either "bitwise", if OVS supports matching any subset of bits in the
+ *     field, or "no", if OVS only supports matching or wildcarding the entire
+ *     field.
+ *
+ *   Formatting:
+ *
+ *     Explains how a field's value is formatted and parsed for human
+ *     consumption.  Some of the options are fairly generally useful:
+ *
+ *       decimal: Formats the value as a decimal number.  On parsing, accepts
+ *         decimal (with no prefix), hexadecimal with 0x prefix, or octal
+ *         with 0 prefix.
+ *
+ *       hexadecimal: Same as decimal except nonzero values are formatted in
+ *         hex with 0x prefix.  The default for parsing is *not* hexadecimal:
+ *         only with a 0x prefix is the input in hexadecimal.
+ *
+ *       Ethernet: Formats and accepts the common format xx:xx:xx:xx:xx:xx.
+ *         6-byte fields only.
+ *
+ *       IPv4: Formats and accepts the common format w.x.y.z.  4-byte fields
+ *         only.
+ *
+ *       IPv6: Formats and accepts the common IPv6 formats.  16-byte fields
+ *         only.
+ *
+ *       OpenFlow 1.0 port: Accepts an OpenFlow well-known port name
+ *         (e.g. "IN_PORT") in uppercase or lowercase, or a 16-bit port
+ *         number in decimal.  Formats ports using their well-known names in
+ *         uppercase, or in decimal otherwise.  2-byte fields only.
+ *
+ *       OpenFlow 1.1+ port: Same syntax as for OpenFlow 1.0 ports but for
+ *         4-byte OpenFlow 1.1+ port number fields.
+ *
+ *     Others are very specific to particular fields:
+ *
+ *       frag: One of the strings "no", "first", "later", "yes", "not_later"
+ *         describing which IPv4/v6 fragments are matched.
+ *
+ *       tunnel flags: Any number of the strings "df", "csum", "key", or
+ *         "oam" separated by "|".
+ *
+ *       TCP flags: See the description of tcp_flags in ovs-ofctl(8).
+ *
+ *   Prerequisites:
+ *
+ *     The field's prerequisites.  The values should be straightfoward.
+ *
+ *   Access:
+ *
+ *     Either "read-only", for a field that cannot be changed via OpenFlow, or
+ *     "read/write" for a modifiable field.
+ *
+ *   NXM:
+ *
+ *     If the field has an NXM field assignment, then this specifies the NXM
+ *     name of the field (e.g. "NXM_OF_ETH_SRC"), followed by its nxm_type in
+ *     parentheses, followed by "since v<x>.<y>" specifying the version of Open
+ *     vSwitch that first supported this field in NXM (e.g. "since v1.1" if it
+ *     was introduced in Open vSwitch 1.1).
+ *
+ *     The NXM name must begin with NXM_OF_ or NXM_NX_.  This allows OVS to
+ *     determine the correct NXM class.
+ *
+ *     If the field does not have an NXM field assignment, specify "none".
+ *
+ *   OXM:
+ *
+ *     If the field has an OXM field assignment, then this specifies the OXM
+ *     name of the field (e.g. "OXM_OF_ETH_SRC"), followed by its nxm_type in
+ *     parentheses, followed by "since OF<a>.<b> v<x>.<y>" specifying the
+ *     versions of OpenFlow and Open vSwitch that first supported this field in
+ *     OXM (e.g. "since OF1.3 and v1.10" if it was introduced in OpenFlow 1.3
+ *     and first supported by Open vSwitch in version 1.10).
+ *
+ *     OVS uses the start of the OXM field name to determine the correct OXM
+ *     class.  To support a new OXM class, edit the mapping table in
+ *     build-aux/extract-ofp-fields.
+ *
+ *     If the field does not have an OXM field assignment, specify "none".
+ *
+ * The following key-value pairs are optional.  Open vSwitch already supports
+ * all the fields to which they apply, so new fields should probably not
+ * include these pairs:
+ *
+ *   OF1.0:
+ *
+ *     Specify this as "exact match" if OpenFlow 1.0 can match or wildcard the
+ *     entire field, or as "CIDR mask" if OpenFlow 1.0 can match any CIDR
+ *     prefix of the field.  (OpenFlow 1.0 did not support bitwise matching.)
+ *     Omit, if OpenFlow 1.0 did not support this field.
+ *
+ *   OF1.1:
+ *
+ *     Specify this as "exact match" if OpenFlow 1.1 can match or wildcard the
+ *     entire field, or as "bitwise" if OpenFlow 1.1 can match any subset of
+ *     bits in the field.  Omit, if OpenFlow 1.1 did not support this field.
+ *
+ * The following key-value pair is optional:
+ *
+ *   Prefix lookup member:
+ *
+ *     If this field makes sense for use with classifier_set_prefix_fields(),
+ *     specify the name of the "struct flow" member that corresponds to the
+ *     field.
+ *
+ * Finally, a few "register" fields have very similar names and purposes,
+ * e.g. MFF_REG0 through MFF_REG7.  For these, the comments may be merged
+ * together using <N> as a metasyntactic variable for the numeric suffix.
+ * Lines in the comment that are specific to one of the particular fields by
+ * writing, e.g. <1>, to consider that line only for e.g. MFF_REG1.
+ */
+
 enum OVS_PACKED_ENUM mf_field_id {
-    /* Metadata. */
-    MFF_DP_HASH,                /* be32 */
-    MFF_RECIRC_ID,              /* be32 */
-    MFF_TUN_ID,                 /* be64 */
-    MFF_TUN_SRC,                /* be32 */
-    MFF_TUN_DST,                /* be32 */
-    MFF_TUN_FLAGS,              /* be16 */
-    MFF_TUN_TTL,                /* u8 */
-    MFF_TUN_TOS,                /* u8 */
-    MFF_METADATA,               /* be64 */
-    MFF_IN_PORT,                /* be16 */
-    MFF_IN_PORT_OXM,            /* be32 */
-    MFF_SKB_PRIORITY,           /* be32 */
-    MFF_PKT_MARK,               /* be32 */
+/* ## -------- ## */
+/* ## Metadata ## */
+/* ## -------- ## */
+
+    /* "dp_hash".
+     *
+     * Flow hash computed in the datapath.  Internal use only, not programmable
+     * from controller.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: NXM_NX_DP_HASH(35) since v2.2.
+     * OXM: none.
+     */
+    MFF_DP_HASH,
+
+    /* "recirc_id".
+     *
+     * ID for recirculation.  The value 0 is reserved for initially received
+     * packets.  Internal use only, not programmable from controller.
+     *
+     * Type: be32.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: NXM_NX_RECIRC_ID(36) since v2.2.
+     * OXM: none.
+     */
+    MFF_RECIRC_ID,
+
+    /* "tun_id" (aka "tunnel_id").
+     *
+     * The "key" or "tunnel ID" or "VNI" in a packet received via a keyed
+     * tunnel.  For protocols in which the key is shorter than 64 bits, the key
+     * is stored in the low bits and the high bits are zeroed.  For non-keyed
+     * tunnels and packets not received via a tunnel, the value is 0.
+     *
+     * Type: be64.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_NX_TUN_ID(16) since v1.1.
+     * OXM: OXM_OF_TUNNEL_ID(38) since OF1.3 and v1.10.
+     * Prefix lookup member: tunnel.tun_id.
+     */
+    MFF_TUN_ID,
+
+    /* "tun_src".
+     *
+     * The IPv4 source address in the outer IP header of a tunneled packet.
+     *
+     * For non-tunneled packets, the value is 0.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_NX_TUN_IPV4_SRC(31) since v2.0.
+     * OXM: none.
+     * Prefix lookup member: tunnel.ip_src.
+     */
+    MFF_TUN_SRC,
+
+    /* "tun_dst".
+     *
+     * The IPv4 destination address in the outer IP header of a tunneled
+     * packet.
+     *
+     * For non-tunneled packets, the value is 0.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_NX_TUN_IPV4_DST(32) since v2.0.
+     * OXM: none.
+     * Prefix lookup member: tunnel.ip_dst.
+     */
+    MFF_TUN_DST,
+
+    /* "tun_flags".
+     *
+     * Combination of FLOW_TNL_F_* bitmapped flags that indicate properties of
+     * a tunneled packet.  Internal use only, not programmable from controller.
+     *
+     * For non-tunneled packets, the value is 0.
+     *
+     * Type: be16.
+     * Maskable: no.
+     * Formatting: tunnel flags.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: none.
+     */
+    MFF_TUN_FLAGS,
+
+    /* "tun_ttl".
+     *
+     * The TTL in the outer IP header of a tunneled packet.  Internal use only,
+     * not programmable from controller.
+     *
+     * For non-tunneled packets, the value is 0.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: none.
+     */
+    MFF_TUN_TTL,
+
+    /* "tun_tos".
+     *
+     * The ToS value in the outer IP header of a tunneled packet.  Internal use
+     * only, not programmable from controller.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: none.
+     */
+    MFF_TUN_TOS,
+
+    /* "metadata".
+     *
+     * A scratch pad value standardized in OpenFlow 1.1+.
+     *
+     * Type: be64.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_METADATA(2) since OF1.2 and v1.8.
+     * OF1.1: bitwise mask.
+     */
+    MFF_METADATA,
+
+    /* "in_port".
+     *
+     * 16-bit (OpenFlow 1.0) view of the physical or virtual port on which the
+     * packet was received.
+     *
+     * Type: be16.
+     * Maskable: no.
+     * Formatting: OpenFlow 1.0 port.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_OF_IN_PORT(0) since v1.1.
+     * OXM: none.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_IN_PORT,
+
+    /* "in_port_oxm".
+     *
+     * 32-bit (OpenFlow 1.1+) view of the physical or virtual port on which the
+     * packet was received.
+     *
+     * Type: be32.
+     * Maskable: no.
+     * Formatting: OpenFlow 1.1+ port.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_IN_PORT(0) since OF1.2 and v1.7.
+     * OF1.1: exact match.
+     */
+    MFF_IN_PORT_OXM,
+
+    /* "skb_priority".
+     *
+     * Designates the queue to which output will be directed.  The value in
+     * this field is not necessarily the OpenFlow queue number; with the Linux
+     * kernel switch, it instead has a pair of subfields designating the
+     * "major" and "minor" numbers of a Linux kernel qdisc handle.
+     *
+     * This field is "semi-internal" in that it can be set with the "set_queue"
+     * action but not matched or read or written other ways.
+     *
+     * Type: be32.
+     * Maskable: no.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: none.
+     */
+    MFF_SKB_PRIORITY,
+
+    /* "pkt_mark".
+     *
+     * Packet metadata mark.  The mark may be passed into other system
+     * components in order to facilitate interaction between subsystems.  On
+     * Linux this corresponds to struct sk_buff's "skb_mark" member but the
+     * exact implementation is platform-dependent.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_NX_PKT_MARK(33) since v2.0.
+     * OXM: none.
+     */
+    MFF_PKT_MARK,
 
 #if FLOW_N_REGS == 8
-    MFF_REG0,                   /* be32 */
-    MFF_REG1,                   /* be32 */
-    MFF_REG2,                   /* be32 */
-    MFF_REG3,                   /* be32 */
-    MFF_REG4,                   /* be32 */
-    MFF_REG5,                   /* be32 */
-    MFF_REG6,                   /* be32 */
-    MFF_REG7,                   /* be32 */
+    /* "reg<N>".
+     *
+     * Nicira extension scratch pad register with initial value 0.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_NX_REG0(0) since v1.1.        <0>
+     * NXM: NXM_NX_REG1(1) since v1.1.        <1>
+     * NXM: NXM_NX_REG2(2) since v1.1.        <2>
+     * NXM: NXM_NX_REG3(3) since v1.1.        <3>
+     * NXM: NXM_NX_REG4(4) since v1.3.        <4>
+     * NXM: NXM_NX_REG5(5) since v1.7.        <5>
+     * NXM: NXM_NX_REG6(6) since v1.7.        <6>
+     * NXM: NXM_NX_REG7(7) since v1.7.        <7>
+     * OXM: none.
+     */
+    MFF_REG0,
+    MFF_REG1,
+    MFF_REG2,
+    MFF_REG3,
+    MFF_REG4,
+    MFF_REG5,
+    MFF_REG6,
+    MFF_REG7,
 #else
 #error "Need to update MFF_REG* to match FLOW_N_REGS"
 #endif
 
 #if FLOW_N_XREGS == 4
-    MFF_XREG0,                  /* be64 */
-    MFF_XREG1,                  /* be64 */
-    MFF_XREG2,                  /* be64 */
-    MFF_XREG3,                  /* be64 */
+    /* "xreg<N>".
+     *
+     * OpenFlow 1.5 (draft) ``extended register".  Each extended register
+     * overlays two of the Nicira extension 32-bit registers: xreg0 overlays
+     * reg0 and reg1, with reg0 supplying the most-significant bits of xreg0
+     * and reg1 the least-significant.  xreg1 similarly overlays reg2 and reg3,
+     * and so on.
+     *
+     * Type: be64.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_PKT_REG<N>(<N>) since OF1.5 and v2.4.
+     */
+    MFF_XREG0,
+    MFF_XREG1,
+    MFF_XREG2,
+    MFF_XREG3,
 #else
 #error "Need to update MFF_REG* to match FLOW_N_XREGS"
 #endif
 
-    /* L2. */
-    MFF_ETH_SRC,                /* mac */
-    MFF_ETH_DST,                /* mac */
-    MFF_ETH_TYPE,               /* be16 */
-
-    MFF_VLAN_TCI,               /* be16 */
-    MFF_DL_VLAN,                /* be16 (OpenFlow 1.0 compatibility) */
-    MFF_VLAN_VID,               /* be16 (OpenFlow 1.2 compatibility) */
-    MFF_DL_VLAN_PCP,            /* u8 (OpenFlow 1.0 compatibility) */
-    MFF_VLAN_PCP,               /* be16 (OpenFlow 1.2 compatibility) */
-
-    /* L2.5 */
-    MFF_MPLS_LABEL,             /* be32 */
-    MFF_MPLS_TC,                /* u8 */
-    MFF_MPLS_BOS,               /* u8 */
-
-    /* L3. */
-    /* Update mf_is_l3_or_higher() if MFF_IPV4_SRC is
-     * no longer the first element for a field of layer 3 or higher */
-    MFF_IPV4_SRC,               /* be32 */
-    MFF_IPV4_DST,               /* be32 */
-
-    MFF_IPV6_SRC,               /* ipv6 */
-    MFF_IPV6_DST,               /* ipv6 */
-    MFF_IPV6_LABEL,             /* be32 */
-
-    /* The IPv4/IPv6 DSCP field has two different views:
-     *
-     *   - MFF_IP_DSCP has the DSCP in bits 2-7, their bit positions in the
-     *     IPv4 and IPv6 "traffic class" field, as used in OpenFlow 1.0 and 1.1
-     *     flow format and in NXM's NXM_OF_IP_TOS
-     *
-     *   - MFF_IP_DSCP has the DSCP in bits 0-5, shifted right two bits from
-     *     their positions in the IPv4 and IPv6 "traffic class" field, as used
-     *     in OpenFlow 1.2+ OXM's OXM_OF_IP_DSCP. */
-    MFF_IP_PROTO,               /* u8 (used for IPv4 or IPv6) */
-    MFF_IP_DSCP,                /* u8 (used for IPv4 or IPv6) */
-    MFF_IP_DSCP_SHIFTED,        /* u8 (used for IPv4 or IPv6) (OF1.2 compat) */
-    MFF_IP_ECN,                 /* u8 (used for IPv4 or IPv6) */
-    MFF_IP_TTL,                 /* u8 (used for IPv4 or IPv6) */
-    MFF_IP_FRAG,                /* u8 (used for IPv4 or IPv6) */
-
-    MFF_ARP_OP,                 /* be16 */
-    MFF_ARP_SPA,                /* be32 */
-    MFF_ARP_TPA,                /* be32 */
-    MFF_ARP_SHA,                /* mac */
-    MFF_ARP_THA,                /* mac */
-
-    /* L4. */
-    MFF_TCP_SRC,                /* be16 (used for IPv4 or IPv6) */
-    MFF_TCP_DST,                /* be16 (used for IPv4 or IPv6) */
-    MFF_TCP_FLAGS,              /* be16, 12 bits (4 MSB zeroed,
-                                 * used for IPv4 or IPv6) */
-
-    MFF_UDP_SRC,                /* be16 (used for IPv4 or IPv6) */
-    MFF_UDP_DST,                /* be16 (used for IPv4 or IPv6) */
-
-    MFF_SCTP_SRC,               /* be16 (used for IPv4 or IPv6) */
-    MFF_SCTP_DST,               /* be16 (used for IPv4 or IPv6) */
-
-    MFF_ICMPV4_TYPE,            /* u8 */
-    MFF_ICMPV4_CODE,            /* u8 */
-
-    MFF_ICMPV6_TYPE,            /* u8 */
-    MFF_ICMPV6_CODE,            /* u8 */
-
-    /* ICMPv6 Neighbor Discovery. */
-    MFF_ND_TARGET,              /* ipv6 */
-    MFF_ND_SLL,                 /* mac */
-    MFF_ND_TLL,                 /* mac */
+/* ## -------- ## */
+/* ## Ethernet ## */
+/* ## -------- ## */
+
+    /* "eth_src" (aka "dl_src").
+     *
+     * Source address in Ethernet header.
+     *
+     * This field was not maskable before Open vSwitch 1.8.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_OF_ETH_SRC(2) since v1.1.
+     * OXM: OXM_OF_ETH_SRC(4) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: bitwise mask.
+     */
+    MFF_ETH_SRC,
+
+    /* "eth_dst" (aka "dl_dst").
+     *
+     * Destination address in Ethernet header.
+     *
+     * Before Open vSwitch 1.8, the allowed masks were restricted to
+     * 00:00:00:00:00:00, fe:ff:ff:ff:ff:ff, 01:00:00:00:00:00,
+     * ff:ff:ff:ff:ff:ff.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_OF_ETH_DST(1) since v1.1.
+     * OXM: OXM_OF_ETH_DST(3) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: bitwise mask.
+     */
+    MFF_ETH_DST,
+
+    /* "eth_type" (aka "dl_type").
+     *
+     * Packet's Ethernet type.
+     *
+     * For an Ethernet II packet this is taken from the Ethernet header.  For
+     * an 802.2 LLC+SNAP header with OUI 00-00-00 this is taken from the SNAP
+     * header.  A packet that has neither format has value 0x05ff
+     * (OFP_DL_TYPE_NOT_ETH_TYPE).
+     *
+     * For a packet with an 802.1Q header, this is the type of the encapsulated
+     * frame.
+     *
+     * Type: be16.
+     * Maskable: no.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read-only.
+     * NXM: NXM_OF_ETH_TYPE(3) since v1.1.
+     * OXM: OXM_OF_ETH_TYPE(5) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_ETH_TYPE,
+
+/* ## ---- ## */
+/* ## VLAN ## */
+/* ## ---- ## */
+
+/* It looks odd for vlan_tci, vlan_vid, and vlan_pcp to say that they are
+ * supported in OF1.0 and OF1.1, since the detailed semantics of these fields
+ * only apply to NXM or OXM.  They are marked as supported for exact matches in
+ * OF1.0 and OF1.1 because exact matches on those fields can be successfully
+ * translated into the OF1.0 and OF1.1 flow formats. */
+
+    /* "vlan_tci".
+     *
+     * 802.1Q TCI.
+     *
+     * For a packet with an 802.1Q header, this is the Tag Control Information
+     * (TCI) field, with the CFI bit forced to 1.  For a packet with no 802.1Q
+     * header, this has value 0.
+     *
+     * This field can be used in various ways:
+     *
+     *   - If it is not constrained at all, the nx_match matches packets
+     *     without an 802.1Q header or with an 802.1Q header that has any TCI
+     *     value.
+     *
+     *   - Testing for an exact match with 0 matches only packets without an
+     *     802.1Q header.
+     *
+     *   - Testing for an exact match with a TCI value with CFI=1 matches
+     *     packets that have an 802.1Q header with a specified VID and PCP.
+     *
+     *   - Testing for an exact match with a nonzero TCI value with CFI=0 does
+     *     not make sense.  The switch may reject this combination.
+     *
+     *   - Testing with a specific VID and CFI=1, with nxm_mask=0x1fff, matches
+     *     packets that have an 802.1Q header with that VID (and any PCP).
+     *
+     *   - Testing with a specific PCP and CFI=1, with nxm_mask=0xf000, matches
+     *     packets that have an 802.1Q header with that PCP (and any VID).
+     *
+     *   - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no
+     *     802.1Q header or with an 802.1Q header with a VID of 0.
+     *
+     *   - Testing with nxm_value=0, nxm_mask=0xe000 matches packets with no
+     *     802.1Q header or with an 802.1Q header with a PCP of 0.
+     *
+     *   - Testing with nxm_value=0, nxm_mask=0xefff matches packets with no
+     *     802.1Q header or with an 802.1Q header with both VID and PCP of 0.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: NXM_OF_VLAN_TCI(4) since v1.1.
+     * OXM: none.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_VLAN_TCI,
+
+    /* "dl_vlan" (OpenFlow 1.0).
+     *
+     * VLAN ID field.  Zero if no 802.1Q header is present.
+     *
+     * Type: be16 (low 12 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: none.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_DL_VLAN,
+
+    /* "vlan_vid" (OpenFlow 1.2+).
+     *
+     * If an 802.1Q header is present, this field's value is 0x1000
+     * bitwise-or'd with the VLAN ID.  If no 802.1Q is present, this field's
+     * value is 0.
+     *
+     * Type: be16 (low 12 bits).
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_VLAN_VID(6) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_VLAN_VID,
+
+    /* "dl_vlan_pcp" (OpenFlow 1.0).
+     *
+     * VLAN priority (PCP) field.  Zero if no 802.1Q header is present.
+     *
+     * Type: u8 (low 3 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: none.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: none.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_DL_VLAN_PCP,
+
+    /* "vlan_pcp" (OpenFlow 1.2+).
+     *
+     * VLAN priority (PCP) field.  Zero if no 802.1Q header is present.
+     *
+     * Type: u8 (low 3 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: VLAN VID.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_VLAN_PCP(7) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_VLAN_PCP,
+
+/* ## ---- ## */
+/* ## MPLS ## */
+/* ## ---- ## */
+
+    /* "mpls_label".
+     *
+     * The outermost MPLS label, or 0 if no MPLS labels are present.
+     *
+     * Type: be32 (low 20 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: MPLS.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_MPLS_LABEL(34) since OF1.2 and v1.11.
+     * OF1.1: exact match.
+     */
+    MFF_MPLS_LABEL,
+
+    /* "mpls_tc".
+     *
+     * The outermost MPLS label's traffic control (TC) field, or 0 if no MPLS
+     * labels are present.
+     *
+     * Type: u8 (low 3 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: MPLS.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_MPLS_TC(35) since OF1.2 and v1.11.
+     * OF1.1: exact match.
+     */
+    MFF_MPLS_TC,
+
+    /* "mpls_bos".
+     *
+     * The outermost MPLS label's bottom of stack (BoS) field, or 0 if no MPLS
+     * labels are present.
+     *
+     * Type: u8 (low 1 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: MPLS.
+     * Access: read-only.
+     * NXM: none.
+     * OXM: OXM_OF_MPLS_BOS(36) since OF1.3 and v1.11.
+     */
+    MFF_MPLS_BOS,
+
+/* ## ---- ## */
+/* ## IPv4 ## */
+/* ## ---- ## */
+
+/* Update mf_is_l3_or_higher() if MFF_IPV4_SRC is no longer the first element
+ * for a field of layer 3 or higher */
+
+    /* "ip_src" (aka "nw_src").
+     *
+     * The source address in the IPv4 header.
+     *
+     * Before Open vSwitch 1.8, only CIDR masks were supported.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: IPv4.
+     * Access: read/write.
+     * NXM: NXM_OF_IP_SRC(7) since v1.1.
+     * OXM: OXM_OF_IPV4_SRC(11) since OF1.2 and v1.7.
+     * OF1.0: CIDR mask.
+     * OF1.1: bitwise mask.
+     * Prefix lookup member: nw_src.
+     */
+    MFF_IPV4_SRC,
+
+    /* "ip_dst" (aka "nw_dst").
+     *
+     * The destination address in the IPv4 header.
+     *
+     * Before Open vSwitch 1.8, only CIDR masks were supported.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: IPv4.
+     * Access: read/write.
+     * NXM: NXM_OF_IP_DST(8) since v1.1.
+     * OXM: OXM_OF_IPV4_DST(12) since OF1.2 and v1.7.
+     * OF1.0: CIDR mask.
+     * OF1.1: bitwise mask.
+     * Prefix lookup member: nw_dst.
+     */
+    MFF_IPV4_DST,
+
+/* ## ---- ## */
+/* ## IPv6 ## */
+/* ## ---- ## */
+
+    /* "ipv6_src".
+     *
+     * The source address in the IPv6 header.
+     *
+     * Type: IPv6.
+     * Maskable: bitwise.
+     * Formatting: IPv6.
+     * Prerequisites: IPv6.
+     * Access: read/write.
+     * NXM: NXM_NX_IPV6_SRC(19) since v1.1.
+     * OXM: OXM_OF_IPV6_SRC(26) since OF1.2 and v1.1.
+     * Prefix lookup member: ipv6_src.
+     */
+    MFF_IPV6_SRC,
+
+    /* "ipv6_dst".
+     *
+     * The destination address in the IPv6 header.
+     *
+     * Type: IPv6.
+     * Maskable: bitwise.
+     * Formatting: IPv6.
+     * Prerequisites: IPv6.
+     * Access: read/write.
+     * NXM: NXM_NX_IPV6_DST(20) since v1.1.
+     * OXM: OXM_OF_IPV6_DST(27) since OF1.2 and v1.1.
+     * Prefix lookup member: ipv6_dst.
+     */
+    MFF_IPV6_DST,
+
+    /* "ipv6_label".
+     *
+     * The flow label in the IPv6 header.
+     *
+     * Type: be32 (low 20 bits).
+     * Maskable: bitwise.
+     * Formatting: hexadecimal.
+     * Prerequisites: IPv6.
+     * Access: read-only.
+     * NXM: NXM_NX_IPV6_LABEL(27) since v1.4.
+     * OXM: OXM_OF_IPV6_FLABEL(28) since OF1.2 and v1.7.
+     */
+    MFF_IPV6_LABEL,
+
+/* ## ----------------------- ## */
+/* ## IPv4/IPv6 common fields ## */
+/* ## ----------------------- ## */
+
+    /* "nw_proto" (aka "ip_proto").
+     *
+     * The "protocol" byte in the IPv4 or IPv6 header.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read-only.
+     * NXM: NXM_OF_IP_PROTO(6) since v1.1.
+     * OXM: OXM_OF_IP_PROTO(10) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_IP_PROTO,
+
+/* Both views of the DSCP below are marked as supported in all of the versions
+ * of OpenFlow because a match on either view can be successfully translated
+ * into every OpenFlow flow format. */
+
+    /* "nw_tos" (OpenFlow 1.0/1.1).
+     *
+     * The DSCP byte in the IPv4 header or the traffic class byte from the IPv6
+     * header, with the ECN bits forced to 0.  (That is, bits 2-7 contain the
+     * type of service and bits 0-1 are zero.)
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read/write.
+     * NXM: NXM_OF_IP_TOS(5) since v1.1.
+     * OXM: none.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_IP_DSCP,
+
+    /* "ip_dscp" (OpenFlow 1.2+).
+     *
+     * The DSCP byte in the IPv4 header or the traffic class byte from the IPv6
+     * header, shifted right 2 bits.  (That is, bits 0-5 contain the type of
+     * service and bits 6-7 are zero.)
+     *
+     * Type: u8 (low 6 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_IP_DSCP(8) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_IP_DSCP_SHIFTED,
+
+    /* "nw_ecn" (aka "ip_ecn").
+     *
+     * The ECN bits in the IPv4 or IPv6 header.
+     *
+     * Type: u8 (low 2 bits).
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read/write.
+     * NXM: NXM_NX_IP_ECN(28) since v1.4.
+     * OXM: OXM_OF_IP_ECN(9) since OF1.2 and v1.7.
+     */
+    MFF_IP_ECN,
+
+    /* "nw_ttl".
+     *
+     * The time-to-live (TTL) in the IPv4 header or hop limit in the IPv6
+     * header.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read/write.
+     * NXM: NXM_NX_IP_TTL(29) since v1.4.
+     * OXM: none.
+     */
+    MFF_IP_TTL,
+
+    /* "ip_frag".
+     *
+     * IP fragment information.
+     *
+     * This field has three possible values:
+     *
+     *   - A packet that is not an IP fragment has value 0.
+     *
+     *   - A packet that is an IP fragment with offset 0 (the first fragment)
+     *     has bit 0 set and thus value 1.
+     *
+     *   - A packet that is an IP fragment with nonzero offset has bits 0 and 1
+     *     set and thus value 3.
+     *
+     * NX_IP_FRAG_ANY and NX_IP_FRAG_LATER are declared to symbolically
+     * represent the meanings of bits 0 and 1.
+     *
+     * The switch may reject matches against values that can never appear.
+     *
+     * It is important to understand how this field interacts with the OpenFlow
+     * IP fragment handling mode:
+     *
+     *   - In OFPC_FRAG_DROP mode, the OpenFlow switch drops all IP fragments
+     *     before they reach the flow table, so every packet that is available
+     *     for matching will have value 0 in this field.
+     *
+     *   - Open vSwitch does not implement OFPC_FRAG_REASM mode, but if it did
+     *     then IP fragments would be reassembled before they reached the flow
+     *     table and again every packet available for matching would always
+     *     have value 0.
+     *
+     *   - In OFPC_FRAG_NORMAL mode, all three values are possible, but
+     *     OpenFlow 1.0 says that fragments' transport ports are always 0, even
+     *     for the first fragment, so this does not provide much extra
+     *     information.
+     *
+     *   - In OFPC_FRAG_NX_MATCH mode, all three values are possible.  For
+     *     fragments with offset 0, Open vSwitch makes L4 header information
+     *     available.
+     *
+     * Type: u8 (low 2 bits).
+     * Maskable: bitwise.
+     * Formatting: frag.
+     * Prerequisites: IPv4/IPv6.
+     * Access: read-only.
+     * NXM: NXM_NX_IP_FRAG(26) since v1.3.
+     * OXM: none.
+     */
+    MFF_IP_FRAG,
+
+/* ## --- ## */
+/* ## ARP ## */
+/* ## --- ## */
+
+    /* "arp_op".
+     *
+     * ARP opcode.
+     *
+     * For an Ethernet+IP ARP packet, the opcode in the ARP header.  Always 0
+     * otherwise.  Only ARP opcodes between 1 and 255 should be specified for
+     * matching.
+     *
+     * Type: be16.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: ARP.
+     * Access: read/write.
+     * NXM: NXM_OF_ARP_OP(15) since v1.1.
+     * OXM: OXM_OF_ARP_OP(21) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_ARP_OP,
+
+    /* "arp_spa".
+     *
+     * For an Ethernet+IP ARP packet, the source protocol (IPv4) address in the
+     * ARP header.  Always 0 otherwise.
+     *
+     * Before Open vSwitch 1.8, only CIDR masks were supported.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: ARP.
+     * Access: read/write.
+     * NXM: NXM_OF_ARP_SPA(16) since v1.1.
+     * OXM: OXM_OF_ARP_SPA(22) since OF1.2 and v1.7.
+     * OF1.0: CIDR mask.
+     * OF1.1: bitwise mask.
+     */
+    MFF_ARP_SPA,
+
+    /* "arp_tpa".
+     *
+     * For an Ethernet+IP ARP packet, the target protocol (IPv4) address in the
+     * ARP header.  Always 0 otherwise.
+     *
+     * Before Open vSwitch 1.8, only CIDR masks were supported.
+     *
+     * Type: be32.
+     * Maskable: bitwise.
+     * Formatting: IPv4.
+     * Prerequisites: ARP.
+     * Access: read/write.
+     * NXM: NXM_OF_ARP_TPA(17) since v1.1.
+     * OXM: OXM_OF_ARP_TPA(23) since OF1.2 and v1.7.
+     * OF1.0: CIDR mask.
+     * OF1.1: bitwise mask.
+     */
+    MFF_ARP_TPA,
+
+    /* "arp_sha".
+     *
+     * For an Ethernet+IP ARP packet, the source hardware (Ethernet) address in
+     * the ARP header.  Always 0 otherwise.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: ARP.
+     * Access: read/write.
+     * NXM: NXM_NX_ARP_SHA(17) since v1.1.
+     * OXM: OXM_OF_ARP_SHA(24) since OF1.2 and v1.7.
+     */
+    MFF_ARP_SHA,
+
+    /* "arp_tha".
+     *
+     * For an Ethernet+IP ARP packet, the target hardware (Ethernet) address in
+     * the ARP header.  Always 0 otherwise.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: ARP.
+     * Access: read/write.
+     * NXM: NXM_NX_ARP_THA(18) since v1.1.
+     * OXM: OXM_OF_ARP_THA(25) since OF1.2 and v1.7.
+     */
+    MFF_ARP_THA,
+
+/* ## --- ## */
+/* ## TCP ## */
+/* ## --- ## */
+
+    /* "tcp_src" (aka "tp_src").
+     *
+     * TCP source port.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: TCP.
+     * Access: read/write.
+     * NXM: NXM_OF_TCP_SRC(9) since v1.1.
+     * OXM: OXM_OF_TCP_SRC(13) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_TCP_SRC,
+
+    /* "tcp_dst" (aka "tp_dst").
+     *
+     * TCP destination port.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: TCP.
+     * Access: read/write.
+     * NXM: NXM_OF_TCP_DST(10) since v1.1.
+     * OXM: OXM_OF_TCP_DST(14) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_TCP_DST,
+
+    /* "tcp_flags".
+     *
+     * Flags in the TCP header.
+     *
+     * TCP currently defines 9 flag bits, and additional 3 bits are reserved
+     * (must be transmitted as zero).  See RFCs 793, 3168, and 3540.
+     *
+     * Type: be16 (low 12 bits).
+     * Maskable: bitwise.
+     * Formatting: TCP flags.
+     * Prerequisites: TCP.
+     * Access: read-only.
+     * NXM: NXM_NX_TCP_FLAGS(34) since v2.1.
+     * OXM: OXM_OF_TCP_FLAGS(42) since OF1.5 and v2.3.
+     */
+    MFF_TCP_FLAGS,
+
+/* ## --- ## */
+/* ## UDP ## */
+/* ## --- ## */
+
+    /* "udp_src".
+     *
+     * UDP source port.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: UDP.
+     * Access: read/write.
+     * NXM: NXM_OF_UDP_SRC(11) since v1.1.
+     * OXM: OXM_OF_UDP_SRC(15) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_UDP_SRC,
+
+    /* "udp_dst".
+     *
+     * UDP destination port
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: UDP.
+     * Access: read/write.
+     * NXM: NXM_OF_UDP_DST(12) since v1.1.
+     * OXM: OXM_OF_UDP_DST(16) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_UDP_DST,
+
+/* ## ---- ## */
+/* ## SCTP ## */
+/* ## ---- ## */
+
+    /* "sctp_src".
+     *
+     * SCTP source port.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: SCTP.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_SCTP_SRC(17) since OF1.2 and v2.0.
+     * OF1.1: exact match.
+     */
+    MFF_SCTP_SRC,
+
+    /* "sctp_dst".
+     *
+     * SCTP destination port.
+     *
+     * Type: be16.
+     * Maskable: bitwise.
+     * Formatting: decimal.
+     * Prerequisites: SCTP.
+     * Access: read/write.
+     * NXM: none.
+     * OXM: OXM_OF_SCTP_DST(18) since OF1.2 and v2.0.
+     * OF1.1: exact match.
+     */
+    MFF_SCTP_DST,
+
+/* ## ---- ## */
+/* ## ICMP ## */
+/* ## ---- ## */
+
+    /* "icmp_type".
+     *
+     * ICMPv4 type.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: ICMPv4.
+     * Access: read-only.
+     * NXM: NXM_OF_ICMP_TYPE(13) since v1.1.
+     * OXM: OXM_OF_ICMPV4_TYPE(19) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_ICMPV4_TYPE,
+
+    /* "icmp_code".
+     *
+     * ICMPv4 code.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: ICMPv4.
+     * Access: read-only.
+     * NXM: NXM_OF_ICMP_CODE(14) since v1.1.
+     * OXM: OXM_OF_ICMPV4_CODE(20) since OF1.2 and v1.7.
+     * OF1.0: exact match.
+     * OF1.1: exact match.
+     */
+    MFF_ICMPV4_CODE,
+
+    /* "icmpv6_type".
+     *
+     * ICMPv6 type.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: ICMPv6.
+     * Access: read-only.
+     * NXM: NXM_NX_ICMPV6_TYPE(21) since v1.1.
+     * OXM: OXM_OF_ICMPV6_TYPE(29) since OF1.2 and v1.7.
+     */
+    MFF_ICMPV6_TYPE,
+
+    /* "icmpv6_code".
+     *
+     * ICMPv6 code.
+     *
+     * Type: u8.
+     * Maskable: no.
+     * Formatting: decimal.
+     * Prerequisites: ICMPv6.
+     * Access: read-only.
+     * NXM: NXM_NX_ICMPV6_CODE(22) since v1.1.
+     * OXM: OXM_OF_ICMPV6_CODE(30) since OF1.2 and v1.7.
+     */
+    MFF_ICMPV6_CODE,
+
+/* ## ------------------------- ## */
+/* ## ICMPv6 Neighbor Discovery ## */
+/* ## ------------------------- ## */
+
+    /* "nd_target".
+     *
+     * The target address in an IPv6 Neighbor Discovery message.
+     *
+     * Before Open vSwitch 1.8, only CIDR masks were supported.
+     *
+     * Type: IPv6.
+     * Maskable: bitwise.
+     * Formatting: IPv6.
+     * Prerequisites: ND.
+     * Access: read-only.
+     * NXM: NXM_NX_ND_TARGET(23) since v1.1.
+     * OXM: OXM_OF_IPV6_ND_TARGET(31) since OF1.2 and v1.7.
+     */
+    MFF_ND_TARGET,
+
+    /* "nd_sll".
+     *
+     * The source link layer address in an IPv6 Neighbor Discovery message.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: ND solicit.
+     * Access: read-only.
+     * NXM: NXM_NX_ND_SLL(24) since v1.1.
+     * OXM: OXM_OF_IPV6_ND_SLL(32) since OF1.2 and v1.7.
+     */
+    MFF_ND_SLL,
+
+    /* "nd_tll".
+     *
+     * The target link layer address in an IPv6 Neighbor Discovery message.
+     *
+     * Type: MAC.
+     * Maskable: bitwise.
+     * Formatting: Ethernet.
+     * Prerequisites: ND advert.
+     * Access: read-only.
+     * NXM: NXM_NX_ND_TLL(25) since v1.1.
+     * OXM: OXM_OF_IPV6_ND_TLL(33) since OF1.2 and v1.7.
+     */
+    MFF_ND_TLL,
 
     MFF_N_IDS
 };
@@ -220,8 +1413,8 @@ enum OVS_PACKED_ENUM mf_string {
     MFS_ETHERNET,
     MFS_IPV4,
     MFS_IPV6,
-    MFS_OFP_PORT,               /* An OpenFlow port number or name. */
-    MFS_OFP_PORT_OXM,           /* An OpenFlow port number or name (32-bit). */
+    MFS_OFP_PORT,               /* 16-bit OpenFlow 1.0 port number or name. */
+    MFS_OFP_PORT_OXM,           /* 32-bit OpenFlow 1.1+ port number or name. */
     MFS_FRAG,                   /* no, yes, first, later, not_later */
     MFS_TNL_FLAGS,              /* FLOW_TNL_F_* flags */
     MFS_TCP_FLAGS,              /* TCP_* flags */
@@ -299,8 +1492,9 @@ struct mf_field {
      * These are combinations of OFPUTIL_P_*.  (They are not declared as type
      * enum ofputil_protocol because that would give meta-flow.h and ofp-util.h
      * a circular dependency.) */
-    uint32_t usable_protocols;         /* If fully/CIDR masked. */
-    uint32_t usable_protocols_bitwise; /* If partially/non-CIDR masked. */
+    uint32_t usable_protocols_exact;   /* Matching or setting whole field. */
+    uint32_t usable_protocols_cidr;    /* Matching a CIDR mask in field. */
+    uint32_t usable_protocols_bitwise; /* Matching arbitrary bits in field. */
 
     int flow_be32ofs;  /* Field's be32 offset in "struct flow", if prefix tree
                         * lookup is supported for the field, or -1. */
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 7322904..ea71d99 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -2232,7 +2232,7 @@ set_field_parse__(char *arg, struct ofpbuf *ofpacts,
         return xasprintf("%s is not a valid value for field %s", value, key);
     }
 
-    *usable_protocols &= mf->usable_protocols;
+    *usable_protocols &= mf->usable_protocols_exact;
     return NULL;
 }
 
-- 
1.9.1




More information about the dev mailing list