[ovs-dev] [of1.1 v6 1/5] ofp-msgs: New approach to encoding and decoding OpenFlow headers.

Ben Pfaff blp at nicira.com
Fri Jul 20 06:28:47 UTC 2012


OpenFlow headers are not as uniform as they could be, with size, alignment,
and numbering changes from one version to another and across varieties
(e.g. ordinary messages vs. "stats" messages).  Until now the Open vSwitch
internal APIs haven't done a good job of abstracting those differences in
header formats.  This commit changes that; from this commit forward very
little code actually needs to understand the header format or numbering.
Instead, it can just encode or decode, or pull or put, the header using
a more abstract API using the ofpraw_, ofptype_, and other APIs in the
new ofp-msgs module.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
v3: New commit.  This isn't complete yet: in particular the program for
extracting the numbers from the ofp-msgs.h header file isn't written,
although there's a skeleton.  That means that nothing has been tested or
carefully looked over, either.

v3->v4: Almost ready.  The ofp-msgs.c functions need some comments
and careful review.

v4->v5: Ready for review.

v5->v6: Rebased against master (more work than you might guess).
Fixed bugs in extract-ofp-msgs reported by Simon Horman.
---
 build-aux/extract-ofp-msgs         |  351 +++++++++
 include/openflow/nicira-ext.h      |  117 +---
 include/openflow/openflow-1.0.h    |   74 +--
 include/openflow/openflow-1.1.h    |   83 +--
 include/openflow/openflow-1.2.h    |   23 +-
 include/openflow/openflow-common.h |   75 +--
 lib/.gitignore                     |    1 +
 lib/automake.mk                    |    9 +
 lib/learning-switch.c              |  128 ++--
 lib/ofp-errors.c                   |   41 +-
 lib/ofp-errors.h                   |    4 +-
 lib/ofp-msgs.c                     |  962 +++++++++++++++++++++++++
 lib/ofp-msgs.h                     |  433 ++++++++++++
 lib/ofp-print.c                    |  321 +++++----
 lib/ofp-util.c                     | 1372 ++++++------------------------------
 lib/ofp-util.h                     |  134 +----
 lib/rconn.c                        |   72 ++-
 lib/stream.c                       |    4 +-
 lib/vconn.c                        |   68 +-
 ofproto/connmgr.c                  |   24 +-
 ofproto/ofproto.c                  |  228 +++----
 tests/ofp-print.at                 |    2 +-
 tests/ofproto-dpif.at              |    1 +
 tests/ofproto-macros.at            |    2 +-
 tests/test-vconn.c                 |   68 +-
 utilities/ovs-ofctl.c              |  176 +++---
 26 files changed, 2669 insertions(+), 2104 deletions(-)
 create mode 100755 build-aux/extract-ofp-msgs
 create mode 100644 lib/ofp-msgs.c
 create mode 100644 lib/ofp-msgs.h

diff --git a/build-aux/extract-ofp-msgs b/build-aux/extract-ofp-msgs
new file mode 100755
index 0000000..fe92dae
--- /dev/null
+++ b/build-aux/extract-ofp-msgs
@@ -0,0 +1,351 @@
+#! /usr/bin/python
+
+import sys
+import os.path
+import re
+
+line = ""
+
+OFP10_VERSION = 0x01
+OFP11_VERSION = 0x02
+OFP12_VERSION = 0x03
+OFP13_VERSION = 0x04
+
+NX_VENDOR_ID = 0x00002320
+
+OFPT_VENDOR = 4
+OFPT10_STATS_REQUEST = 16
+OFPT10_STATS_REPLY = 17
+OFPT11_STATS_REQUEST = 18
+OFPT11_STATS_REPLY = 19
+OFPST_VENDOR = 0xffff
+
+version_map = {"1.0":     (OFP10_VERSION, OFP10_VERSION),
+               "1.1":     (OFP11_VERSION, OFP11_VERSION),
+               "1.2":     (OFP12_VERSION, OFP12_VERSION),
+               "1.3":     (OFP13_VERSION, OFP13_VERSION),
+               "1.0+":    (OFP10_VERSION, OFP13_VERSION),
+               "1.1+":    (OFP11_VERSION, OFP13_VERSION),
+               "1.2+":    (OFP12_VERSION, OFP13_VERSION),
+               "1.3+":    (OFP13_VERSION, OFP13_VERSION),
+               "1.0-1.1": (OFP10_VERSION, OFP11_VERSION)}
+
+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 message types from header files
+usage: %(argv0)s INPUT OUTPUT
+  where INPUT is the name of the input header file
+    and OUTPUT is the output file name.
+Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
+only controls #line directives in the output.\
+''' % {"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 extract_ofp_msgs(output_file_name):
+    raw_types = []
+
+    all_hdrs = {}
+    all_raws = {}
+    all_raws_order = []
+
+    while True:
+        get_line()
+        if re.match('enum ofpraw', 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 not line
+            or line.isspace()):
+            continue
+        elif re.match('}', line):
+            break
+
+        if not line.lstrip().startswith('/*'):
+            fatal("unexpected syntax between ofpraw types")
+
+        comment = line.lstrip()[2:].strip()
+        while not comment.endswith('*/'):
+            get_line()
+            if line.startswith('/*') or not line or line.isspace():
+                fatal("unexpected syntax within error")
+            comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
+        comment = comment[:-2].rstrip()
+
+        m = re.match(r'([A-Z]+) ([-.+\d]+) \((\d+)\): ([^.]+)\.$', comment)
+        if not m:
+            fatal("unexpected syntax between messages")
+        type_, versions, number, contents = m.groups()
+        number = int(number)
+
+        get_line()
+        m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
+                     line)
+        if not m:
+            fatal("syntax error expecting OFPRAW_ enum")
+        vinfix, name = m.groups()
+        rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
+
+        min_version, max_version = version_map[versions]
+
+        human_name = '%s_%s' % (type_, name)
+        if type_.endswith('ST'):
+            if rawname.endswith('_REQUEST'):
+                human_name = human_name[:-8] + " request"
+            elif rawname.endswith('_REPLY'):
+                human_name = human_name[:-6] + " reply"
+            else:
+                fatal("%s messages are statistics but %s doesn't end "
+                      "in _REQUEST or _REPLY" % (type_, rawname))
+
+        these_hdrs = []
+        for version in range(min_version, max_version + 1):
+            if type_ == 'OFPT':
+                if number == OFPT_VENDOR:
+                    fatal("OFPT (%d) is used for vendor extensions"
+                          % number)
+                elif (version == OFP10_VERSION
+                      and (number == OFPT10_STATS_REQUEST
+                           or number == OFPT10_STATS_REPLY)):
+                    fatal("OFPT 1.0 (%d) is used for stats messages"
+                          % number)
+                elif (version != OFP10_VERSION
+                      and (number == OFPT11_STATS_REQUEST
+                           or number == OFPT11_STATS_REPLY)):
+                    fatal("OFPT 1.1+ (%d) is used for stats messages"
+                          % number)
+                hdrs = (version, number, 0, 0, 0)
+            elif type_ == 'OFPST' and name.endswith('_REQUEST'):
+                if version == OFP10_VERSION:
+                    hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
+                else:
+                    hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
+            elif type_ == 'OFPST' and name.endswith('_REPLY'):
+                if version == OFP10_VERSION:
+                    hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
+                else:
+                    hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
+            elif type_ == 'NXT':
+                hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
+            elif type_ == 'NXST' and name.endswith('_REQUEST'):
+                if version == OFP10_VERSION:
+                    hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
+                            NX_VENDOR_ID, number)
+                else:
+                    hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
+                            NX_VENDOR_ID, number)
+            elif type_ == 'NXST' and name.endswith('_REPLY'):
+                if version == OFP10_VERSION:
+                    hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
+                            NX_VENDOR_ID, number)
+                else:
+                    hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
+                            NX_VENDOR_ID, number)
+            else:
+                fatal("type '%s' unknown" % type_)
+
+            if hdrs in all_hdrs:
+                error("Duplicate message definition for %s." % str(hdrs))
+                sys.stderr.write("%s: Here is the location "
+                                 "of the previous definition.\n"
+                                 % (all_hdrs[hdrs]))
+            all_hdrs[hdrs] = here
+            these_hdrs.append(hdrs)
+
+        extra_multiple = '0'
+        if contents == 'void':
+            min_body = '0'
+        else:
+            min_body_elem = []
+            for c in [s.strip() for s in contents.split(",")]:
+                if c.endswith('[]'):
+                    if extra_multiple == '0':
+                        extra_multiple = make_sizeof(c[:-2])
+                    else:
+                        error("Cannot have multiple [] elements")
+                else:
+                    min_body_elem.append(c)
+
+            if min_body_elem:
+                min_body = " + ".join([make_sizeof(s)
+                                       for s in min_body_elem])
+            else:
+                if extra_multiple == '0':
+                    error("Must specify contents (use 'void' if empty)")
+                min_body = 0
+
+        if rawname in all_raws:
+            fatal("%s: Duplicate name" % rawname)
+
+        all_raws[rawname] = {"hdrs": these_hdrs,
+                             "min_version": min_version,
+                             "max_version": max_version,
+                             "min_body": min_body,
+                             "extra_multiple": extra_multiple,
+                             "type": type_,
+                             "human_name": human_name,
+                             "line": first_line_number}
+        all_raws_order.append(rawname)
+
+        continue
+
+    while True:
+        get_line()
+        if re.match('enum ofptype', line):
+            break
+
+    while True:
+        get_line()
+        if re.match(r'\s*/?\*', line) or line.isspace():
+            continue
+        elif re.match('}', line):
+            break
+
+        if not re.match(r'\s*OFPTYPE_.*/\*', line):
+            fatal("unexpected syntax between OFPTYPE_ definitions")
+
+        syntax = line.strip()
+        while not syntax.endswith('*/'):
+            get_line()
+            if not line.strip().startswith('*'):
+                fatal("unexpected syntax within OFPTYPE_ definition")
+            syntax += ' %s' % line.strip().lstrip('* \t')
+            syntax = syntax.strip()
+
+        m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
+        if not m:
+            fatal("syntax error in OFPTYPE_ definition")
+
+        ofptype, raws_ = m.groups()
+        raws = [s.rstrip('.') for s in raws_.split()]
+        for raw in raws:
+            if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
+                fatal("%s: invalid OFPRAW_* name syntax" % raw)
+            if raw not in all_raws:
+                fatal("%s: not a declared OFPRAW_* name" % raw)
+            if "ofptype" in all_raws[raw]:
+                fatal("%s: already part of %s"
+                      % (raw, all_raws[raw]["ofptype"]))
+            all_raws[raw]["ofptype"] = ofptype
+
+    input_file.close()
+
+    if n_errors:
+        sys.exit(1)
+
+    output = []
+    output.append("/* Generated automatically; do not modify!     "
+                  "-*- buffer-read-only: t -*- */")
+    output.append("")
+
+    for raw in all_raws_order:
+        r = all_raws[raw]
+        output.append("static struct raw_instance %s_instances[] = {"
+                      % raw.lower())
+        for hdrs in r['hdrs']:
+            output.append("    { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
+                          % (hdrs + (raw,)))
+                
+        output.append("};")
+
+    output.append("")
+
+    output.append("static struct raw_info raw_infos[] = {")
+    for raw in all_raws_order:
+        r = all_raws[raw]
+        if "ofptype" not in r:
+            error("%s: no defined OFPTYPE_" % raw)
+            continue
+        output.append("    {")
+        output.append("        %s_instances," % raw.lower())
+        output.append("        %d, %d," % (r["min_version"], r["max_version"]))
+        output.append("#line %s \"%s\"" % (r["line"], file_name))
+        output.append("        %s," % r["min_body"])
+        output.append("#line %s \"%s\"" % (r["line"], file_name))
+        output.append("        %s," % r["extra_multiple"])
+        output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
+        output.append("        %s," % r["ofptype"])
+        output.append("        \"%s\"," % r["human_name"])
+        output.append("    },")
+
+        if r['type'].endswith("ST"):
+            for hdrs in r['hdrs']:
+                op_hdrs = list(hdrs)
+                if hdrs[0] == OFP10_VERSION:
+                    if hdrs[1] == OFPT10_STATS_REQUEST:
+                        op_hdrs[1] = OFPT10_STATS_REPLY
+                    elif hdrs[1] == OFPT10_STATS_REPLY:
+                        op_hdrs[1] = OFPT10_STATS_REQUEST
+                    else:
+                        assert False
+                else:
+                    if hdrs[1] == OFPT11_STATS_REQUEST:
+                        op_hdrs[1] = OFPT11_STATS_REPLY
+                    elif hdrs[1] == OFPT11_STATS_REPLY:
+                        op_hdrs[1] = OFPT11_STATS_REQUEST
+                    else:
+                        assert False
+                if tuple(op_hdrs) not in all_hdrs:
+                    if r["human_name"].endswith("request"):
+                        fatal("%s has no corresponding reply"
+                              % r["human_name"])
+                    else:
+                        fatal("%s has no corresponding request"
+                              % r["human_name"])
+    output.append("};")
+
+    if n_errors:
+        sys.exit(1)
+
+    return output
+
+
+if __name__ == '__main__':
+    if '--help' in sys.argv:
+        usage()
+    elif len(sys.argv) != 3:
+        sys.stderr.write("exactly one non-option arguments 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_msgs(sys.argv[2]):
+            print line
+        
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 1104dbf..217c77c 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -73,74 +73,26 @@ struct nx_vendor_error {
 struct nicira_header {
     struct ofp_header header;
     ovs_be32 vendor;            /* NX_VENDOR_ID. */
-    ovs_be32 subtype;           /* One of NXT_* below. */
+    ovs_be32 subtype;           /* See the NXT numbers in ofp-msgs.h. */
 };
 OFP_ASSERT(sizeof(struct nicira_header) == 16);
 
-/* Values for the 'subtype' member of struct nicira_header. */
-enum nicira_type {
-    /* No longer used. */
-    NXT_STATUS_REQUEST__OBSOLETE = 0,
-    NXT_STATUS_REPLY__OBSOLETE = 1,
-    NXT_ACT_SET_CONFIG__OBSOLETE = 2,
-    NXT_ACT_GET_CONFIG__OBSOLETE = 3,
-    NXT_COMMAND_REQUEST__OBSOLETE = 4,
-    NXT_COMMAND_REPLY__OBSOLETE = 5,
-    NXT_FLOW_END_CONFIG__OBSOLETE = 6,
-    NXT_FLOW_END__OBSOLETE = 7,
-    NXT_MGMT__OBSOLETE = 8,
-    NXT_TUN_ID_FROM_COOKIE__OBSOLETE = 9,
-
-    /* Controller role support.  The request body is struct nx_role_request.
-     * The reply echos the request. */
-    NXT_ROLE_REQUEST = 10,
-    NXT_ROLE_REPLY = 11,
-
-    /* Flexible flow specification (aka NXM = Nicira Extended Match). */
-    NXT_SET_FLOW_FORMAT = 12,   /* Set flow format. */
-    NXT_FLOW_MOD = 13,          /* Analogous to OFPT_FLOW_MOD. */
-    NXT_FLOW_REMOVED = 14,      /* Analogous to OFPT_FLOW_REMOVED. */
-
-    /* Use the upper 8 bits of the 'command' member in struct ofp_flow_mod to
-     * designate the table to which a flow is to be added?  See the big comment
-     * on struct nx_flow_mod_table_id for more information. */
-    NXT_FLOW_MOD_TABLE_ID = 15,
-
-    /* Alternative PACKET_IN message formats. */
-    NXT_SET_PACKET_IN_FORMAT = 16, /* Set Packet In format. */
-    NXT_PACKET_IN = 17,            /* Nicira Packet In. */
-
-    /* Are the idle_age and hard_age members in struct nx_flow_stats supported?
-     * If so, the switch does not reply to this message (which consists only of
-     * a "struct nicira_header").  If not, the switch sends an error reply. */
-    NXT_FLOW_AGE = 18,
-
-    NXT_SET_ASYNC_CONFIG = 19,  /* struct nx_async_config. */
-    NXT_SET_CONTROLLER_ID = 20, /* struct nx_controller_id. */
-
-    /* Flow table monitoring (see also NXST_FLOW_MONITOR). */
-    NXT_FLOW_MONITOR_CANCEL = 21,  /* struct nx_flow_monitor_cancel. */
-    NXT_FLOW_MONITOR_PAUSED = 22,  /* struct nicira_header. */
-    NXT_FLOW_MONITOR_RESUMED = 23, /* struct nicira_header. */
-};
-
-/* Header for Nicira vendor stats request and reply messages. */
-struct nicira_stats_msg {
-    struct ofp_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
+/* Header for Nicira vendor stats request and reply messages in OpenFlow
+ * 1.0. */
+struct nicira10_stats_msg {
+    struct ofp10_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
     ovs_be32 subtype;           /* One of NXST_* below. */
     uint8_t pad[4];             /* Align to 64-bits. */
 };
-OFP_ASSERT(sizeof(struct nicira_stats_msg) == 24);
+OFP_ASSERT(sizeof(struct nicira10_stats_msg) == 24);
 
-/* Values for the 'subtype' member of struct nicira_stats_msg. */
-enum nicira_stats_type {
-    /* Flexible flow specification (aka NXM = Nicira Extended Match). */
-    NXST_FLOW,                  /* Analogous to OFPST_FLOW. */
-    NXST_AGGREGATE,             /* Analogous to OFPST_AGGREGATE. */
-
-    /* Flow table monitoring. */
-    NXST_FLOW_MONITOR,
+/* Header for Nicira vendor stats request and reply messages in OpenFlow
+ * 1.1. */
+struct nicira11_stats_msg {
+    struct ofp11_vendor_stats_msg vsm; /* Vendor NX_VENDOR_ID. */
+    ovs_be32 subtype;           /* One of NXST_* below. */
 };
+OFP_ASSERT(sizeof(struct nicira11_stats_msg) == 24);
 
 /* Fields to use when hashing flows. */
 enum nx_hash_fields {
@@ -200,13 +152,10 @@ enum nx_hash_fields {
  *      table match, then none is modified or deleted.
  */
 struct nx_flow_mod_table_id {
-    struct ofp_header header;
-    ovs_be32 vendor;            /* NX_VENDOR_ID. */
-    ovs_be32 subtype;           /* NXT_FLOW_MOD_TABLE_ID. */
     uint8_t set;                /* Nonzero to enable, zero to disable. */
     uint8_t pad[7];
 };
-OFP_ASSERT(sizeof(struct nx_flow_mod_table_id) == 24);
+OFP_ASSERT(sizeof(struct nx_flow_mod_table_id) == 8);
 
 enum nx_packet_in_format {
     NXPIF_OPENFLOW10 = 0,       /* Standard OpenFlow 1.0 compatible. */
@@ -215,10 +164,9 @@ enum nx_packet_in_format {
 
 /* NXT_SET_PACKET_IN_FORMAT request. */
 struct nx_set_packet_in_format {
-    struct nicira_header nxh;
     ovs_be32 format;            /* One of NXPIF_*. */
 };
-OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 20);
+OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 4);
 
 /* NXT_PACKET_IN (analogous to OFPT_PACKET_IN).
  *
@@ -245,7 +193,6 @@ OFP_ASSERT(sizeof(struct nx_set_packet_in_format) == 20);
  * The 'cookie' and 'table_id' fields have no meaning when 'reason' is
  * OFPR_NO_MATCH.  In this case they should be set to 0. */
 struct nx_packet_in {
-    struct nicira_header nxh;
     ovs_be32 buffer_id;       /* ID assigned by datapath. */
     ovs_be16 total_len;       /* Full length of frame. */
     uint8_t reason;           /* Reason packet is sent (one of OFPR_*). */
@@ -267,7 +214,7 @@ struct nx_packet_in {
     /* uint8_t pad[2]; */          /* Align to 64 bit + 16 bit. */
     /* uint8_t data[0]; */         /* Ethernet frame. */
 };
-OFP_ASSERT(sizeof(struct nx_packet_in) == 40);
+OFP_ASSERT(sizeof(struct nx_packet_in) == 24);
 
 /* Configures the "role" of the sending controller.  The default role is:
  *
@@ -289,10 +236,9 @@ OFP_ASSERT(sizeof(struct nx_packet_in) == 40);
  *      messages, but they do receive OFPT_PORT_STATUS messages.
  */
 struct nx_role_request {
-    struct nicira_header nxh;
     ovs_be32 role;              /* One of NX_ROLE_*. */
 };
-OFP_ASSERT(sizeof(struct nx_role_request) == 20);
+OFP_ASSERT(sizeof(struct nx_role_request) == 4);
 
 enum nx_role {
     NX_ROLE_OTHER,              /* Default role, full access. */
@@ -318,12 +264,11 @@ enum nx_role {
  * miss_send_len from default of zero to OFP_DEFAULT_MISS_SEND_LEN (128).
  */
 struct nx_async_config {
-    struct nicira_header nxh;
     ovs_be32 packet_in_mask[2];    /* Bitmasks of OFPR_* values. */
     ovs_be32 port_status_mask[2];  /* Bitmasks of OFPRR_* values. */
     ovs_be32 flow_removed_mask[2]; /* Bitmasks of OFPPR_* values. */
 };
-OFP_ASSERT(sizeof(struct nx_async_config) == 40);
+OFP_ASSERT(sizeof(struct nx_async_config) == 24);
 
 /* Nicira vendor flow actions. */
 
@@ -1784,10 +1729,9 @@ enum nx_flow_format {
 
 /* NXT_SET_FLOW_FORMAT request. */
 struct nx_set_flow_format {
-    struct nicira_header nxh;
     ovs_be32 format;            /* One of NXFF_*. */
 };
-OFP_ASSERT(sizeof(struct nx_set_flow_format) == 20);
+OFP_ASSERT(sizeof(struct nx_set_flow_format) == 4);
 
 /* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD).
  *
@@ -1796,7 +1740,6 @@ OFP_ASSERT(sizeof(struct nx_set_flow_format) == 20);
  * is used only to add or modify flow cookies.
  */
 struct nx_flow_mod {
-    struct nicira_header nxh;
     ovs_be64 cookie;              /* Opaque controller-issued identifier. */
     ovs_be16 command;             /* One of OFPFC_*. */
     ovs_be16 idle_timeout;        /* Idle time before discarding (seconds). */
@@ -1819,11 +1762,10 @@ struct nx_flow_mod {
      *     multiple of 8).
      */
 };
-OFP_ASSERT(sizeof(struct nx_flow_mod) == 48);
+OFP_ASSERT(sizeof(struct nx_flow_mod) == 32);
 
 /* NXT_FLOW_REMOVED (analogous to OFPT_FLOW_REMOVED). */
 struct nx_flow_removed {
-    struct nicira_header nxh;
     ovs_be64 cookie;          /* Opaque controller-issued identifier. */
     ovs_be16 priority;        /* Priority level of flow entry. */
     uint8_t reason;           /* One of OFPRR_*. */
@@ -1840,7 +1782,7 @@ struct nx_flow_removed {
      *   - Exactly (match_len + 7)/8*8 - match_len (between 0 and 7) bytes of
      *     all-zero bytes. */
 };
-OFP_ASSERT(sizeof(struct nx_flow_removed) == 56);
+OFP_ASSERT(sizeof(struct nx_flow_removed) == 40);
 
 /* Nicira vendor stats request of type NXST_FLOW (analogous to OFPST_FLOW
  * request).
@@ -1849,7 +1791,6 @@ OFP_ASSERT(sizeof(struct nx_flow_removed) == 56);
  * NXM_NX_COOKIE and NXM_NX_COOKIE_W matches.
  */
 struct nx_flow_stats_request {
-    struct nicira_stats_msg nsm;
     ovs_be16 out_port;        /* Require matching entries to include this
                                  as an output port.  A value of OFPP_NONE
                                  indicates no restriction. */
@@ -1864,7 +1805,7 @@ struct nx_flow_stats_request {
      *     message.
      */
 };
-OFP_ASSERT(sizeof(struct nx_flow_stats_request) == 32);
+OFP_ASSERT(sizeof(struct nx_flow_stats_request) == 8);
 
 /* Body for Nicira vendor stats reply of type NXST_FLOW (analogous to
  * OFPST_FLOW reply).
@@ -1917,7 +1858,6 @@ OFP_ASSERT(sizeof(struct nx_flow_stats) == 48);
 /* Nicira vendor stats request of type NXST_AGGREGATE (analogous to
  * OFPST_AGGREGATE request). */
 struct nx_aggregate_stats_request {
-    struct nicira_stats_msg nsm;
     ovs_be16 out_port;        /* Require matching entries to include this
                                  as an output port.  A value of OFPP_NONE
                                  indicates no restriction. */
@@ -1932,18 +1872,17 @@ struct nx_aggregate_stats_request {
      *     message.
      */
 };
-OFP_ASSERT(sizeof(struct nx_aggregate_stats_request) == 32);
+OFP_ASSERT(sizeof(struct nx_aggregate_stats_request) == 8);
 
 /* Body for nicira_stats_msg reply of type NXST_AGGREGATE (analogous to
  * OFPST_AGGREGATE reply). */
 struct nx_aggregate_stats_reply {
-    struct nicira_stats_msg nsm;
     ovs_be64 packet_count;     /* Number of packets, UINT64_MAX if unknown. */
     ovs_be64 byte_count;       /* Number of bytes, UINT64_MAX if unknown. */
     ovs_be32 flow_count;       /* Number of flows. */
     uint8_t pad[4];            /* Align to 64 bits. */
 };
-OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
+OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 24);
 
 /* NXT_SET_CONTROLLER_ID.
  *
@@ -1955,11 +1894,10 @@ OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
  * The NXAST_CONTROLLER action is the only current user of controller
  * connection IDs. */
 struct nx_controller_id {
-    struct nicira_header nxh;
     uint8_t zero[6];            /* Must be zero. */
     ovs_be16 controller_id;     /* New controller connection ID. */
 };
-OFP_ASSERT(sizeof(struct nx_controller_id) == 24);
+OFP_ASSERT(sizeof(struct nx_controller_id) == 8);
 
 /* Action structure for NXAST_CONTROLLER.
  *
@@ -2213,11 +2151,12 @@ struct nx_flow_update_abbrev {
 };
 OFP_ASSERT(sizeof(struct nx_flow_update_abbrev) == 8);
 
-/* Used by a controller to cancel an outstanding monitor. */
+/* NXT_FLOW_MONITOR_CANCEL.
+ *
+ * Used by a controller to cancel an outstanding monitor. */
 struct nx_flow_monitor_cancel {
-    struct nicira_header nxh;   /* Type NXT_FLOW_MONITOR_CANCEL. */
     ovs_be32 id;                /* 'id' from nx_flow_monitor_request. */
 };
-OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 20);
+OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4);
 
 #endif /* openflow/nicira-ext.h */
diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h
index d71b007..23cfb8d 100644
--- a/include/openflow/openflow-1.0.h
+++ b/include/openflow/openflow-1.0.h
@@ -43,31 +43,6 @@ enum ofp_port {
     OFPP_NONE       = 0xffff   /* Not associated with a physical port. */
 };
 
-/* OpenFlow 1.0 specific message types, in addition to the common message
- * types. */
-enum ofp10_type {
-    /* Controller command messages. */
-    OFPT10_PORT_MOD = 15,       /* Controller/switch message */
-
-    /* Statistics messages. */
-    OFPT10_STATS_REQUEST,       /* Controller/switch message */
-    OFPT10_STATS_REPLY,         /* Controller/switch message */
-
-    /* Barrier messages. */
-    OFPT10_BARRIER_REQUEST,     /* Controller/switch message */
-    OFPT10_BARRIER_REPLY,       /* Controller/switch message */
-
-    /* Queue Configuration messages. */
-    OFPT10_QUEUE_GET_CONFIG_REQUEST,  /* Controller/switch message */
-    OFPT10_QUEUE_GET_CONFIG_REPLY     /* Controller/switch message */
-};
-
-/* OFPT_HELLO.  This message has an empty body, but implementations must
- * ignore any data included in the body, to allow for future extensions. */
-struct ofp_hello {
-    struct ofp_header header;
-};
-
 #define OFP_DEFAULT_MISS_SEND_LEN   128
 
 enum ofp_config_flags {
@@ -85,12 +60,11 @@ enum ofp_config_flags {
 
 /* Switch configuration. */
 struct ofp_switch_config {
-    struct ofp_header header;
     ovs_be16 flags;             /* OFPC_* flags. */
     ovs_be16 miss_send_len;     /* Max bytes of new flow that datapath should
                                    send to the controller. */
 };
-OFP_ASSERT(sizeof(struct ofp_switch_config) == 12);
+OFP_ASSERT(sizeof(struct ofp_switch_config) == 4);
 
 /* OpenFlow 1.0 specific capabilities supported by the datapath (struct
  * ofp_switch_features, member capabilities). */
@@ -159,7 +133,6 @@ OFP_ASSERT(sizeof(struct ofp10_phy_port) == 48);
 
 /* Modify behavior of the physical port */
 struct ofp10_port_mod {
-    struct ofp_header header;
     ovs_be16 port_no;
     uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
                                       configurable.  This is used to
@@ -174,30 +147,27 @@ struct ofp10_port_mod {
                                bits to prevent any action taking place. */
     uint8_t pad[4];         /* Pad to 64-bits. */
 };
-OFP_ASSERT(sizeof(struct ofp10_port_mod) == 32);
+OFP_ASSERT(sizeof(struct ofp10_port_mod) == 24);
 
 /* Query for port queue configuration. */
 struct ofp10_queue_get_config_request {
-    struct ofp_header header;
     ovs_be16 port;          /* Port to be queried. Should refer
                                to a valid physical port (i.e. < OFPP_MAX) */
     uint8_t pad[2];
     /* 32-bit alignment. */
 };
-OFP_ASSERT(sizeof(struct ofp10_queue_get_config_request) == 12);
+OFP_ASSERT(sizeof(struct ofp10_queue_get_config_request) == 4);
 
 /* Queue configuration for a given port. */
 struct ofp10_queue_get_config_reply {
-    struct ofp_header header;
     ovs_be16 port;
     uint8_t pad[6];
     /* struct ofp10_packet_queue queues[0]; List of configured queues. */
 };
-OFP_ASSERT(sizeof(struct ofp10_queue_get_config_reply) == 16);
+OFP_ASSERT(sizeof(struct ofp10_queue_get_config_reply) == 8);
 
 /* Packet received on port (datapath -> controller). */
 struct ofp_packet_in {
-    struct ofp_header header;
     ovs_be32 buffer_id;     /* ID assigned by datapath. */
     ovs_be16 total_len;     /* Full length of frame. */
     ovs_be16 in_port;       /* Port on which frame was received. */
@@ -210,7 +180,7 @@ struct ofp_packet_in {
                                offsetof(struct ofp_packet_in, data) ==
                                sizeof(struct ofp_packet_in) - 2. */
 };
-OFP_ASSERT(sizeof(struct ofp_packet_in) == 20);
+OFP_ASSERT(sizeof(struct ofp_packet_in) == 12);
 
 enum ofp10_action_type {
     OFPAT10_OUTPUT,             /* Output to switch port. */
@@ -289,7 +259,6 @@ OFP_ASSERT(sizeof(union ofp_action) == 8);
 
 /* Send packet (controller -> datapath). */
 struct ofp_packet_out {
-    struct ofp_header header;
     ovs_be32 buffer_id;           /* ID assigned by datapath or UINT32_MAX. */
     ovs_be16 in_port;             /* Packet's input port (OFPP_NONE if none). */
     ovs_be16 actions_len;         /* Size of action array in bytes. */
@@ -300,7 +269,7 @@ struct ofp_packet_out {
      *     of the message length.
      */
 };
-OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
+OFP_ASSERT(sizeof(struct ofp_packet_out) == 8);
 
 enum ofp_flow_mod_command {
     OFPFC_ADD,              /* New flow. */
@@ -403,7 +372,6 @@ enum ofp_flow_mod_flags {
 
 /* Flow setup and teardown (controller -> datapath). */
 struct ofp_flow_mod {
-    struct ofp_header header;
     struct ofp10_match match;    /* Fields to match */
     ovs_be64 cookie;             /* Opaque controller-issued identifier. */
 
@@ -423,11 +391,10 @@ struct ofp_flow_mod {
                                             from the length field in the
                                             header. */
 };
-OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
 
 /* Flow removed (datapath -> controller). */
 struct ofp_flow_removed {
-    struct ofp_header header;
     struct ofp10_match match; /* Description of fields. */
     ovs_be64 cookie;          /* Opaque controller-issued identifier. */
 
@@ -443,18 +410,16 @@ struct ofp_flow_removed {
     ovs_be64 packet_count;
     ovs_be64 byte_count;
 };
-OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
+OFP_ASSERT(sizeof(struct ofp_flow_removed) == 80);
 
 /* OFPT_ERROR: Error message (datapath -> controller). */
 struct ofp_error_msg {
-    struct ofp_header header;
-
     ovs_be16 type;
     ovs_be16 code;
     uint8_t data[0];          /* Variable-length data.  Interpreted based
                                  on the type and code. */
 };
-OFP_ASSERT(sizeof(struct ofp_error_msg) == 12);
+OFP_ASSERT(sizeof(struct ofp_error_msg) == 4);
 
 /* Statistics request or reply message. */
 struct ofp_stats_msg {
@@ -471,10 +436,9 @@ enum ofp_stats_reply_flags {
 
 #define DESC_STR_LEN   256
 #define SERIAL_NUM_LEN 32
-/* Reply to OFPST_DESC request.  Each entry is a NULL-terminated ASCII
+/* Body of reply to OFPST_DESC request.  Each entry is a NULL-terminated ASCII
  * string. */
 struct ofp_desc_stats {
-    struct ofp_stats_msg osm;
     char mfr_desc[DESC_STR_LEN];       /* Manufacturer description. */
     char hw_desc[DESC_STR_LEN];        /* Hardware description. */
     char sw_desc[DESC_STR_LEN];        /* Software description. */
@@ -482,11 +446,10 @@ struct ofp_desc_stats {
     char dp_desc[DESC_STR_LEN];        /* Human readable description of
                                           the datapath. */
 };
-OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1068);
+OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056);
 
 /* Stats request of type OFPST_AGGREGATE or OFPST_FLOW. */
 struct ofp_flow_stats_request {
-    struct ofp_stats_msg osm;
     struct ofp10_match match; /* Fields to match. */
     uint8_t table_id;         /* ID of table to read (from ofp_table_stats)
                                  or 0xff for all tables. */
@@ -495,7 +458,7 @@ struct ofp_flow_stats_request {
                                  as an output port.  A value of OFPP_NONE
                                  indicates no restriction. */
 };
-OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 56);
+OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44);
 
 /* Body of reply to OFPST_FLOW request. */
 struct ofp_flow_stats {
@@ -520,13 +483,12 @@ OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88);
 
 /* Reply to OFPST_AGGREGATE request. */
 struct ofp_aggregate_stats_reply {
-    struct ofp_stats_msg osm;
     ovs_32aligned_be64 packet_count; /* Number of packets in flows. */
     ovs_32aligned_be64 byte_count;   /* Number of bytes in flows. */
     ovs_be32 flow_count;      /* Number of flows. */
     uint8_t pad[4];           /* Align to 64 bits. */
 };
-OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 36);
+OFP_ASSERT(sizeof(struct ofp_aggregate_stats_reply) == 24);
 
 /* Body of reply to OFPST_TABLE request. */
 struct ofp_table_stats {
@@ -545,13 +507,12 @@ OFP_ASSERT(sizeof(struct ofp_table_stats) == 64);
 
 /* Stats request of type OFPST_PORT. */
 struct ofp_port_stats_request {
-    struct ofp_stats_msg osm;
     ovs_be16 port_no;        /* OFPST_PORT message may request statistics
                                 for a single port (specified with port_no)
                                 or for all ports (port_no == OFPP_NONE). */
     uint8_t pad[6];
 };
-OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 20);
+OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8);
 
 /* Body of reply to OFPST_PORT request. If a counter is unsupported, set
  * the field to all ones. */
@@ -582,12 +543,11 @@ OFP_ASSERT(sizeof(struct ofp_port_stats) == 104);
 
 /* Body for stats request of type OFPST_QUEUE. */
 struct ofp_queue_stats_request {
-    struct ofp_stats_msg osm;
     ovs_be16 port_no;        /* All ports if OFPP_ALL. */
     uint8_t pad[2];          /* Align to 32-bits. */
     ovs_be32 queue_id;       /* All queues if OFPQ_ALL. */
 };
-OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 20);
+OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8);
 
 /* Body for stats reply of type OFPST_QUEUE consists of an array of this
  * structure type. */
@@ -602,7 +562,7 @@ struct ofp_queue_stats {
 OFP_ASSERT(sizeof(struct ofp_queue_stats) == 32);
 
 /* Vendor extension stats message. */
-struct ofp_vendor_stats_msg {
+struct ofp10_vendor_stats_msg {
     struct ofp_stats_msg osm;   /* Type OFPST_VENDOR. */
     ovs_be32 vendor;            /* Vendor ID:
                                  * - MSB 0: low-order bytes are IEEE OUI.
@@ -610,7 +570,7 @@ struct ofp_vendor_stats_msg {
                                  *   consortium. */
     /* Followed by vendor-defined arbitrary additional data. */
 };
-OFP_ASSERT(sizeof(struct ofp_vendor_stats_msg) == 16);
+OFP_ASSERT(sizeof(struct ofp10_vendor_stats_msg) == 16);
 
 /* Vendor extension. */
 struct ofp_vendor_header {
diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h
index f0f3793..7c78c63 100644
--- a/include/openflow/openflow-1.1.h
+++ b/include/openflow/openflow-1.1.h
@@ -70,27 +70,6 @@
 #define OFPP11_MAX    0xffffff00
 #define OFPP11_OFFSET (OFPP11_MAX - OFPP_MAX)
 
-/* OpenFlow 1.1 specific message types, in addition to the common message
- * types. */
-enum ofp11_type {
-    /* Controller command messages. */
-    OFPT11_GROUP_MOD = 15,      /* Controller/switch message */
-    OFPT11_PORT_MOD,            /* Controller/switch message */
-    OFPT11_TABLE_MOD,           /* Controller/switch message */
-
-    /* Statistics messages. */
-    OFPT11_STATS_REQUEST,       /* Controller/switch message */
-    OFPT11_STATS_REPLY,         /* Controller/switch message */
-
-    /* Barrier messages. */
-    OFPT11_BARRIER_REQUEST,     /* Controller/switch message */
-    OFPT11_BARRIER_REPLY,       /* Controller/switch message */
-
-    /* Queue Configuration messages. */
-    OFPT11_QUEUE_GET_CONFIG_REQUEST,  /* Controller/switch message */
-    OFPT11_QUEUE_GET_CONFIG_REPLY,    /* Controller/switch message */
-};
-
 /* OpenFlow 1.1 port config flags are just the common flags. */
 #define OFPPC11_ALL \
     (OFPPC_PORT_DOWN | OFPPC_NO_RECV | OFPPC_NO_FWD | OFPPC_NO_PACKET_IN)
@@ -143,7 +122,6 @@ struct ofp11_port {
 
 /* Modify behavior of the physical port */
 struct ofp11_port_mod {
-    struct ofp_header header;
     ovs_be32 port_no;
     uint8_t pad[4];
     uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
@@ -159,11 +137,10 @@ struct ofp11_port_mod {
                                to prevent any action taking place. */
     uint8_t pad3[4];        /* Pad to 64 bits. */
 };
-OFP_ASSERT(sizeof(struct ofp11_port_mod) == 40);
+OFP_ASSERT(sizeof(struct ofp11_port_mod) == 32);
 
 /* Group setup and teardown (controller -> datapath). */
 struct ofp11_group_mod {
-    struct ofp_header header;
     ovs_be16 command;             /* One of OFPGC_*. */
     uint8_t type;                 /* One of OFPGT_*. */
     uint8_t pad;                  /* Pad to 64 bits. */
@@ -171,17 +148,16 @@ struct ofp11_group_mod {
     /* struct ofp11_bucket buckets[0]; The bucket length is inferred from the
                                        length field in the header. */
 };
-OFP_ASSERT(sizeof(struct ofp11_group_mod) == 16);
+OFP_ASSERT(sizeof(struct ofp11_group_mod) == 8);
 
 /* Query for port queue configuration. */
 struct ofp11_queue_get_config_request {
-    struct ofp_header header;
     ovs_be32 port;
     /* Port to be queried. Should refer
        to a valid physical port (i.e. < OFPP_MAX) */
     uint8_t pad[4];
 };
-OFP_ASSERT(sizeof(struct ofp11_queue_get_config_request) == 16);
+OFP_ASSERT(sizeof(struct ofp11_queue_get_config_request) == 8);
 
 /* Group commands */
 enum ofp11_group_mod_command {
@@ -448,12 +424,11 @@ OFP_ASSERT(sizeof(struct ofp11_action_pop_mpls) == 8);
 
 /* Configure/Modify behavior of a flow table */
 struct ofp11_table_mod {
-    struct ofp_header header;
     uint8_t table_id;       /* ID of the table, 0xFF indicates all tables */
     uint8_t pad[3];         /* Pad to 32 bits */
     ovs_be32 config;        /* Bitmap of OFPTC_* flags */
 };
-OFP_ASSERT(sizeof(struct ofp11_table_mod) == 16);
+OFP_ASSERT(sizeof(struct ofp11_table_mod) == 8);
 
 /* Flags to indicate behavior of the flow table for unmatched packets.
    These flags are used in ofp_table_stats messages to describe the current
@@ -469,7 +444,6 @@ enum ofp11_table_config {
 
 /* Flow setup and teardown (controller -> datapath). */
 struct ofp11_flow_mod {
-    struct ofp_header header;
     ovs_be64 cookie;             /* Opaque controller-issued identifier. */
     ovs_be64 cookie_mask;        /* Mask used to restrict the cookie bits
                                     that must match when the command is
@@ -496,7 +470,7 @@ struct ofp11_flow_mod {
     /* Open Flow version specific match */
     /* struct ofp_instruction instructions[0];  Instruction set */
 };
-OFP_ASSERT(sizeof(struct ofp11_flow_mod) == 48);
+OFP_ASSERT(sizeof(struct ofp11_flow_mod) == 40);
 
 /* Group types. Values in the range [128, 255] are reserved for experimental
  * use. */
@@ -543,12 +517,11 @@ OFP_ASSERT(sizeof(struct ofp11_bucket) == 16);
 
 /* Queue configuration for a given port. */
 struct ofp11_queue_get_config_reply {
-    struct ofp_header header;
     ovs_be32 port;
     uint8_t pad[4];
     /* struct ofp_packet_queue queues[0];  List of configured queues. */
 };
-OFP_ASSERT(sizeof(struct ofp11_queue_get_config_reply) == 16);
+OFP_ASSERT(sizeof(struct ofp11_queue_get_config_reply) == 8);
 
 struct ofp11_stats_msg {
     struct ofp_header header;
@@ -559,9 +532,19 @@ struct ofp11_stats_msg {
 };
 OFP_ASSERT(sizeof(struct ofp11_stats_msg) == 16);
 
+/* Vendor extension stats message. */
+struct ofp11_vendor_stats_msg {
+    struct ofp11_stats_msg osm; /* Type OFPST_VENDOR. */
+    ovs_be32 vendor;            /* Vendor ID:
+                                 * - MSB 0: low-order bytes are IEEE OUI.
+                                 * - MSB != 0: defined by OpenFlow
+                                 *   consortium. */
+    /* Followed by vendor-defined arbitrary additional data. */
+};
+OFP_ASSERT(sizeof(struct ofp11_vendor_stats_msg) == 20);
+
 /* Stats request of type OFPST_FLOW. */
 struct ofp11_flow_stats_request {
-    struct ofp11_stats_msg osm;
     uint8_t table_id;         /* ID of table to read (from ofp_table_stats),
                                  0xff for all tables. */
     uint8_t pad[3];           /* Align to 64 bits. */
@@ -579,7 +562,7 @@ struct ofp11_flow_stats_request {
                                  no restriction. */
     struct ofp11_match match; /* Fields to match. */
 };
-OFP_ASSERT(sizeof(struct ofp11_flow_stats_request) == 136);
+OFP_ASSERT(sizeof(struct ofp11_flow_stats_request) == 120);
 
 /* Body of reply to OFPST_FLOW request. */
 struct ofp11_flow_stats {
@@ -607,7 +590,6 @@ OFP_ASSERT(sizeof(struct ofp11_flow_stats) == 48);
 
 /* Body of reply to OFPST_TABLE request. */
 struct ofp11_table_stats {
-    struct ofp11_stats_msg osm;
     uint8_t table_id;        /* Identifier of table. Lower numbered tables
                                 are consulted first. */
     uint8_t pad[7];          /* Align to 64-bits. */
@@ -627,23 +609,21 @@ struct ofp11_table_stats {
     ovs_be64 lookup_count;   /* Number of packets looked up in table. */
     ovs_be64 matched_count;  /* Number of packets that hit table. */
 };
-OFP_ASSERT(sizeof(struct ofp11_table_stats) == 104);
+OFP_ASSERT(sizeof(struct ofp11_table_stats) == 88);
 
 /* Body for ofp_stats_request of type OFPST_PORT. */
 struct ofp11_port_stats_request {
-    struct ofp11_stats_msg osm;
     ovs_be32 port_no;        /* OFPST_PORT message must request statistics
                               * either for a single port (specified in
                               * port_no) or for all ports (if port_no ==
                               * OFPP_ANY). */
     uint8_t pad[4];
 };
-OFP_ASSERT(sizeof(struct ofp11_port_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_port_stats_request) == 8);
 
 /* Body of reply to OFPST_PORT request. If a counter is unsupported, set
  * the field to all ones. */
 struct ofp11_port_stats {
-    struct ofp11_stats_msg osm;
     ovs_be32 port_no;
     uint8_t pad[4];           /* Align to 64-bits. */
     ovs_be64 rx_packets;      /* Number of received packets. */
@@ -663,31 +643,28 @@ struct ofp11_port_stats {
     ovs_be64 rx_crc_err;      /* Number of CRC errors. */
     ovs_be64 collisions;      /* Number of collisions. */
 };
-OFP_ASSERT(sizeof(struct ofp11_port_stats) == 120);
+OFP_ASSERT(sizeof(struct ofp11_port_stats) == 104);
 
 struct ofp11_queue_stats_request {
-    struct ofp11_stats_msg osm;
     ovs_be32 port_no;         /* All ports if OFPP_ANY. */
     ovs_be32 queue_id;        /* All queues if OFPQ_ALL. */
 };
-OFP_ASSERT(sizeof(struct ofp11_queue_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_queue_stats_request) == 8);
 
 struct ofp11_queue_stats {
-    struct ofp11_stats_msg osm;
     ovs_be32 port_no;
     ovs_be32 queue_id;         /* Queue id. */
     ovs_be64 tx_bytes;         /* Number of transmitted bytes. */
     ovs_be64 tx_packets;       /* Number of transmitted packets. */
     ovs_be64 tx_errors;        /* # of packets dropped due to overrun. */
 };
-OFP_ASSERT(sizeof(struct ofp11_queue_stats) == 48);
+OFP_ASSERT(sizeof(struct ofp11_queue_stats) == 32);
 
 struct ofp11_group_stats_request {
-    struct ofp11_stats_msg osm;
     ovs_be32 group_id;         /* All groups if OFPG_ALL. */
     uint8_t pad[4];            /* Align to 64 bits. */
 };
-OFP_ASSERT(sizeof(struct ofp11_group_stats_request) == 24);
+OFP_ASSERT(sizeof(struct ofp11_group_stats_request) == 8);
 
 /* Body of reply to OFPST11_GROUP request */
 struct ofp11_group_stats {
@@ -706,11 +683,10 @@ OFP_ASSERT(sizeof(struct ofp11_group_stats) == 32);
 
 /* Used in group stats replies. */
 struct ofp11_bucket_counter {
-    struct ofp11_stats_msg osm;
     ovs_be64 packet_count;   /* Number of packets processed by bucket. */
     ovs_be64 byte_count;     /* Number of bytes processed by bucket. */
 };
-OFP_ASSERT(sizeof(struct ofp11_bucket_counter) == 32);
+OFP_ASSERT(sizeof(struct ofp11_bucket_counter) == 16);
 
 /* Body of reply to OFPST11_GROUP_DESC request. */
 struct ofp11_group_desc_stats {
@@ -724,7 +700,6 @@ OFP_ASSERT(sizeof(struct ofp11_group_desc_stats) == 8);
 
 /* Send packet (controller -> datapath). */
 struct ofp11_packet_out {
-    struct ofp_header header;
     ovs_be32 buffer_id;       /* ID assigned by datapath (-1 if none). */
     ovs_be32 in_port;         /* Packet's input port or OFPP_CONTROLLER. */
     ovs_be16 actions_len;     /* Size of action array in bytes. */
@@ -734,11 +709,10 @@ struct ofp11_packet_out {
                                  from the length field in the header.
                                  (Only meaningful if buffer_id == -1.) */
 };
-OFP_ASSERT(sizeof(struct ofp11_packet_out) == 24);
+OFP_ASSERT(sizeof(struct ofp11_packet_out) == 16);
 
 /* Packet received on port (datapath -> controller). */
 struct ofp11_packet_in {
-    struct ofp_header header;
     ovs_be32 buffer_id;     /* ID assigned by datapath. */
     ovs_be32 in_port;       /* Port on which frame was received. */
     ovs_be32 in_phy_port;   /* Physical Port on which frame was received. */
@@ -752,11 +726,10 @@ struct ofp11_packet_in {
                                offsetof(struct ofp_packet_in, data) ==
                                sizeof(struct ofp_packet_in) - 2. */
 };
-OFP_ASSERT(sizeof(struct ofp11_packet_in) == 24);
+OFP_ASSERT(sizeof(struct ofp11_packet_in) == 16);
 
 /* Flow removed (datapath -> controller). */
 struct ofp11_flow_removed {
-    struct ofp_header header;
     ovs_be64 cookie;          /* Opaque controller-issued identifier. */
 
     ovs_be16 priority;        /* Priority level of flow entry. */
@@ -772,6 +745,6 @@ struct ofp11_flow_removed {
     ovs_be64 byte_count;
     struct ofp11_match match; /* Description of fields. */
 };
-OFP_ASSERT(sizeof(struct ofp11_flow_removed) == 136);
+OFP_ASSERT(sizeof(struct ofp11_flow_removed) == 128);
 
 #endif /* openflow/openflow-1.1.h */
diff --git a/include/openflow/openflow-1.2.h b/include/openflow/openflow-1.2.h
index 58093a8..0a73ed1 100644
--- a/include/openflow/openflow-1.2.h
+++ b/include/openflow/openflow-1.2.h
@@ -55,14 +55,6 @@
 
 #include "openflow/openflow-1.1.h"
 
-/* OpenFlow 1.2 specific message types, in addition to the common message
- * types. */
-enum ofp12_type {
-    /* Controller role change request messages. */
-    OFPT12_ROLE_REQUEST = 24,   /* Controller/switch message */
-    OFPT12_ROLE_REPLY,          /* Controller/switch message */
-};
-
 /*
  * OXM Class IDs.
  * The high order bit differentiate reserved classes from member classes.
@@ -264,7 +256,6 @@ enum ofp12_queue_properties {
 
 /* Body of reply to OFPST_TABLE request. */
 struct ofp12_table_stats {
-    struct ofp11_stats_msg osm;
     uint8_t table_id;        /* Identifier of table.  Lower numbered tables
                                 are consulted first. */
     uint8_t pad[7];          /* Align to 64-bits. */
@@ -290,17 +281,16 @@ struct ofp12_table_stats {
     ovs_be64 lookup_count;   /* Number of packets looked up in table. */
     ovs_be64 matched_count;  /* Number of packets that hit table. */
 };
-OFP_ASSERT(sizeof(struct ofp12_table_stats) == 144);
+OFP_ASSERT(sizeof(struct ofp12_table_stats) == 128);
 
 /* Body of reply to OFPST12_GROUP_FEATURES request. Group features. */
 struct ofp12_group_features_stats {
-    struct ofp11_stats_msg osm;
     ovs_be32  types;           /* Bitmap of OFPGT_* values supported. */
     ovs_be32  capabilities;    /* Bitmap of OFPGFC12_* capability supported. */
     ovs_be32  max_groups[4];   /* Maximum number of groups for each type. */
     ovs_be32  actions[4];      /* Bitmaps of OFPAT_* that are supported. */
 };
-OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 56);
+OFP_ASSERT(sizeof(struct ofp12_group_features_stats) == 40);
 
 /* Group configuration flags */
 enum ofp12_group_capabilities {
@@ -321,12 +311,11 @@ OFP_ASSERT(sizeof(struct ofp12_experimenter_stats_header) == 8);
 
 /* Role request and reply message. */
 struct ofp12_role_request {
-    struct ofp_header header; /* Type OFPT12_ROLE_REQUEST/OFPT12_ROLE_REPLY. */
     ovs_be32 role;            /* One of OFPCR12_ROLE_*. */
     uint8_t pad[4];           /* Align to 64 bits. */
     ovs_be64 generation_id;   /* Master Election Generation Id */
 };
-OFP_ASSERT(sizeof(struct ofp12_role_request) == 24);
+OFP_ASSERT(sizeof(struct ofp12_role_request) == 16);
 
 /* Controller roles. */
 enum ofp12_controller_role {
@@ -338,7 +327,6 @@ enum ofp12_controller_role {
 
 /* Packet received on port (datapath -> controller). */
 struct ofp12_packet_in {
-    struct ofp_header header;
     ovs_be32 buffer_id;     /* ID assigned by datapath. */
     ovs_be16 total_len;     /* Full length of frame. */
     uint8_t reason;         /* Reason packet is being sent (one of OFPR_*) */
@@ -354,11 +342,10 @@ struct ofp12_packet_in {
     /* uint8_t pad[2];         Align to 64 bit + 16 bit */
     /* uint8_t data[0];        Ethernet frame */
 };
-OFP_ASSERT(sizeof(struct ofp12_packet_in) == 16);
+OFP_ASSERT(sizeof(struct ofp12_packet_in) == 8);
 
 /* Flow removed (datapath -> controller). */
 struct ofp12_flow_removed {
-    struct ofp_header header;
     ovs_be64 cookie;          /* Opaque controller-issued identifier. */
 
     ovs_be16 priority;        /* Priority level of flow entry. */
@@ -374,6 +361,6 @@ struct ofp12_flow_removed {
     ovs_be64 byte_count;
     /* struct ofp12_match match;  Description of fields. Variable size. */
 };
-OFP_ASSERT(sizeof(struct ofp12_flow_removed) == 48);
+OFP_ASSERT(sizeof(struct ofp12_flow_removed) == 40);
 
 #endif /* openflow/openflow-1.2.h */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index fe91b10..ae91c44 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -83,32 +83,6 @@
 
 #define OFP_ETH_ALEN 6          /* Bytes in an Ethernet address. */
 
-/* Common OpenFlow message types. */
-enum ofp_type {
-    /* Immutable messages. */
-    OFPT_HELLO,               /* Symmetric message */
-    OFPT_ERROR,               /* Symmetric message */
-    OFPT_ECHO_REQUEST,        /* Symmetric message */
-    OFPT_ECHO_REPLY,          /* Symmetric message */
-    OFPT_VENDOR,              /* Symmetric message */
-
-    /* Switch configuration messages. */
-    OFPT_FEATURES_REQUEST,    /* Controller/switch message */
-    OFPT_FEATURES_REPLY,      /* Controller/switch message */
-    OFPT_GET_CONFIG_REQUEST,  /* Controller/switch message */
-    OFPT_GET_CONFIG_REPLY,    /* Controller/switch message */
-    OFPT_SET_CONFIG,          /* Controller/switch message */
-
-    /* Asynchronous messages. */
-    OFPT_PACKET_IN,           /* Async message */
-    OFPT_FLOW_REMOVED,        /* Async message */
-    OFPT_PORT_STATUS,         /* Async message */
-
-    /* Controller command messages. */
-    OFPT_PACKET_OUT,          /* Controller/switch message */
-    OFPT_FLOW_MOD,            /* Controller/switch message */
-};
-
 /* Header on all OpenFlow packets. */
 struct ofp_header {
     uint8_t version;    /* An OpenFlow version number, e.g. OFP10_VERSION. */
@@ -183,7 +157,6 @@ OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16);
 
 /* Switch features. */
 struct ofp_switch_features {
-    struct ofp_header header;
     ovs_be64 datapath_id;   /* Datapath unique ID.  The lower 48-bits are for
                                a MAC address, while the upper 16-bits are
                                implementer-defined. */
@@ -200,7 +173,7 @@ struct ofp_switch_features {
     /* Followed by an array of struct ofp10_phy_port or struct ofp11_port
      * structures.  The number is inferred from header.length. */
 };
-OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
+OFP_ASSERT(sizeof(struct ofp_switch_features) == 24);
 
 /* Common capabilities supported by the datapath (struct ofp_switch_features,
  * member capabilities). */
@@ -293,55 +266,11 @@ enum ofp_port_reason {
 
 /* A physical port has changed in the datapath */
 struct ofp_port_status {
-    struct ofp_header header;
     uint8_t reason;          /* One of OFPPR_*. */
     uint8_t pad[7];          /* Align to 64-bits. */
     /* Followed by struct ofp10_phy_port or struct ofp11_port.  */
 };
-OFP_ASSERT(sizeof(struct ofp_port_status) == 16);
-
-enum ofp_stats_types {
-    /* Description of this OpenFlow switch. (OFPMP_DESC)
-     * The OF1.0 request is struct ofp_stats_msg.
-     * The OF1.0 reply is struct ofp_desc_stats. */
-    OFPST_DESC = 0,
-
-    /* Individual flow statistics. (OFPMP_FLOW)
-     * The OF1.0 request is struct ofp_flow_stats_request.
-     * The OF1.0 reply body is an array of struct ofp_flow_stats. */
-    OFPST_FLOW = 1,
-
-    /* Aggregate flow statistics. (OFPMP_AGGREGATE)
-     * The OF1.0 request is struct ofp_flow_stats_request.
-     * The OF1.0 reply is struct ofp_aggregate_stats_reply. */
-    OFPST_AGGREGATE = 2,
-
-    /* Flow table statistics. (OFPMP_TABLE)
-     * The OF1.0 request is struct ofp_stats_msg.
-     * The OF1.0 reply body is an array of struct ofp_table_stats. */
-    OFPST_TABLE = 3,
-
-    /* Physical port statistics. (OFPMP_PORT_STATS)
-     * The OF1.0 request is struct ofp_port_stats_request.
-     * The OF1.0 reply body is an array of struct ofp_port_stats. */
-    OFPST_PORT = 4,
-
-    /* Queue statistics for a port. (OFPMP_QUEUE)
-     * The OF1.0 request is struct ofp_stats_msg.
-     * The OF1.0 reply body is an array of struct ofp_queue_stats. */
-    OFPST_QUEUE = 5,
-
-    /* Port description. (OFPMP_PORT_DESC)
-     * This was introduced as part of OF1.3, but is useful for bridges
-     * with many ports, so we support it with OF1.0, too.
-     * The OF1.0 request is struct ofp_stats_msg.
-     * The OF1.0 reply body is an array of struct ofp10_phy_port. */
-    OFPST_PORT_DESC = 13,
-
-    /* Vendor extension.
-     * The OF1.0 request and reply begin with struct ofp_vendor_stats. */
-    OFPST_VENDOR = 0xffff
-};
+OFP_ASSERT(sizeof(struct ofp_port_status) == 8);
 
 /* The match type indicates the match structure (set of fields that compose the
  * match) in use. The match type is placed in the type field at the beginning
diff --git a/lib/.gitignore b/lib/.gitignore
index ba73f28..f4c59ad 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -4,6 +4,7 @@
 /dirs.c
 /coverage-counters.c
 /ofp-errors.inc
+/ofp-msgs.inc
 /vswitch-idl.c
 /vswitch-idl.h
 /vswitch-idl.ovsidl
diff --git a/lib/automake.mk b/lib/automake.mk
index b727fed..c316737 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -100,6 +100,8 @@ lib_libopenvswitch_a_SOURCES = \
 	lib/ofp-actions.h \
 	lib/ofp-errors.c \
 	lib/ofp-errors.h \
+	lib/ofp-msgs.c \
+	lib/ofp-msgs.h \
 	lib/ofp-parse.c \
 	lib/ofp-parse.h \
 	lib/ofp-print.c \
@@ -321,6 +323,13 @@ $(srcdir)/lib/ofp-errors.inc: \
 $(srcdir)/lib/ofp-errors.c: $(srcdir)/lib/ofp-errors.inc
 EXTRA_DIST += build-aux/extract-ofp-errors lib/ofp-errors.inc
 
+$(srcdir)/lib/ofp-msgs.inc: \
+	lib/ofp-msgs.h $(srcdir)/build-aux/extract-ofp-msgs
+	$(run_python) $(srcdir)/build-aux/extract-ofp-msgs \
+		$(srcdir)/lib/ofp-msgs.h $@ > $@.tmp && mv $@.tmp $@
+$(srcdir)/lib/ofp-msgs.c: $(srcdir)/lib/ofp-msgs.inc
+EXTRA_DIST += build-aux/extract-ofp-msgs lib/ofp-msgs.inc
+
 INSTALL_DATA_LOCAL += lib-install-data-local
 lib-install-data-local:
 	$(MKDIR_P) $(DESTDIR)$(RUNDIR)
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index b41bea0..887a365 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -31,6 +31,7 @@
 #include "ofpbuf.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-parse.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
@@ -81,7 +82,7 @@ static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *);
 static void send_features_request(struct lswitch *, struct rconn *);
 
 static enum ofperr process_switch_features(struct lswitch *,
-                                           struct ofp_switch_features *);
+                                           struct ofp_header *);
 static void process_packet_in(struct lswitch *, struct rconn *,
                               const struct ofp_header *);
 static void process_echo_request(struct lswitch *, struct rconn *,
@@ -228,84 +229,78 @@ void
 lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
                        const struct ofpbuf *msg)
 {
-    const struct ofp_header *oh = msg->data;
-    const struct ofputil_msg_type *type;
+    enum ofptype type;
+    struct ofpbuf b;
+
+    b = *msg;
+    if (ofptype_pull(&type, &b)) {
+        return;
+    }
 
     if (sw->datapath_id == 0
-        && oh->type != OFPT_ECHO_REQUEST
-        && oh->type != OFPT_FEATURES_REPLY) {
+        && type != OFPTYPE_ECHO_REQUEST
+        && type != OFPTYPE_FEATURES_REPLY) {
         send_features_request(sw, rconn);
         return;
     }
 
-    ofputil_decode_msg_type(oh, &type);
-    switch (ofputil_msg_type_code(type)) {
-    case OFPUTIL_OFPT_ECHO_REQUEST:
+    switch (type) {
+    case OFPTYPE_ECHO_REQUEST:
         process_echo_request(sw, rconn, msg->data);
         break;
 
-    case OFPUTIL_OFPT_FEATURES_REPLY:
+    case OFPTYPE_FEATURES_REPLY:
         process_switch_features(sw, msg->data);
         break;
 
-    case OFPUTIL_OFPT_PACKET_IN:
-    case OFPUTIL_NXT_PACKET_IN:
+    case OFPTYPE_PACKET_IN:
         process_packet_in(sw, rconn, msg->data);
         break;
 
-    case OFPUTIL_OFPT_FLOW_REMOVED:
+    case OFPTYPE_FLOW_REMOVED:
         /* Nothing to do. */
         break;
 
-    case OFPUTIL_MSG_INVALID:
-    case OFPUTIL_OFPT_HELLO:
-    case OFPUTIL_OFPT_ERROR:
-    case OFPUTIL_OFPT_ECHO_REPLY:
-    case OFPUTIL_OFPT_FEATURES_REQUEST:
-    case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
-    case OFPUTIL_OFPT_GET_CONFIG_REPLY:
-    case OFPUTIL_OFPT_SET_CONFIG:
-    case OFPUTIL_OFPT_PORT_STATUS:
-    case OFPUTIL_OFPT_PACKET_OUT:
-    case OFPUTIL_OFPT_FLOW_MOD:
-    case OFPUTIL_OFPT_PORT_MOD:
-    case OFPUTIL_OFPT_BARRIER_REQUEST:
-    case OFPUTIL_OFPT_BARRIER_REPLY:
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
-    case OFPUTIL_OFPST_DESC_REQUEST:
-    case OFPUTIL_OFPST_FLOW_REQUEST:
-    case OFPUTIL_OFPST_AGGREGATE_REQUEST:
-    case OFPUTIL_OFPST_TABLE_REQUEST:
-    case OFPUTIL_OFPST_PORT_REQUEST:
-    case OFPUTIL_OFPST_QUEUE_REQUEST:
-    case OFPUTIL_OFPST_PORT_DESC_REQUEST:
-    case OFPUTIL_OFPST_DESC_REPLY:
-    case OFPUTIL_OFPST_FLOW_REPLY:
-    case OFPUTIL_OFPST_QUEUE_REPLY:
-    case OFPUTIL_OFPST_PORT_REPLY:
-    case OFPUTIL_OFPST_TABLE_REPLY:
-    case OFPUTIL_OFPST_AGGREGATE_REPLY:
-    case OFPUTIL_OFPST_PORT_DESC_REPLY:
-    case OFPUTIL_NXT_ROLE_REQUEST:
-    case OFPUTIL_NXT_ROLE_REPLY:
-    case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
-    case OFPUTIL_NXT_SET_FLOW_FORMAT:
-    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
-    case OFPUTIL_NXT_FLOW_MOD:
-    case OFPUTIL_NXT_FLOW_REMOVED:
-    case OFPUTIL_NXT_FLOW_AGE:
-    case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
-    case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
-    case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
-    case OFPUTIL_NXT_SET_ASYNC_CONFIG:
-    case OFPUTIL_NXT_SET_CONTROLLER_ID:
-    case OFPUTIL_NXST_FLOW_REQUEST:
-    case OFPUTIL_NXST_AGGREGATE_REQUEST:
-    case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
-    case OFPUTIL_NXST_FLOW_REPLY:
-    case OFPUTIL_NXST_AGGREGATE_REPLY:
-    case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+    case OFPTYPE_HELLO:
+    case OFPTYPE_ERROR:
+    case OFPTYPE_ECHO_REPLY:
+    case OFPTYPE_FEATURES_REQUEST:
+    case OFPTYPE_GET_CONFIG_REQUEST:
+    case OFPTYPE_GET_CONFIG_REPLY:
+    case OFPTYPE_SET_CONFIG:
+    case OFPTYPE_PORT_STATUS:
+    case OFPTYPE_PACKET_OUT:
+    case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_PORT_MOD:
+    case OFPTYPE_BARRIER_REQUEST:
+    case OFPTYPE_BARRIER_REPLY:
+    case OFPTYPE_DESC_STATS_REQUEST:
+    case OFPTYPE_DESC_STATS_REPLY:
+    case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_AGGREGATE_STATS_REQUEST:
+    case OFPTYPE_AGGREGATE_STATS_REPLY:
+    case OFPTYPE_TABLE_STATS_REQUEST:
+    case OFPTYPE_TABLE_STATS_REPLY:
+    case OFPTYPE_PORT_STATS_REQUEST:
+    case OFPTYPE_PORT_STATS_REPLY:
+    case OFPTYPE_QUEUE_STATS_REQUEST:
+    case OFPTYPE_QUEUE_STATS_REPLY:
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
+    case OFPTYPE_PORT_DESC_STATS_REPLY:
+    case OFPTYPE_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REPLY:
+    case OFPTYPE_SET_FLOW_FORMAT:
+    case OFPTYPE_FLOW_MOD_TABLE_ID:
+    case OFPTYPE_SET_PACKET_IN_FORMAT:
+    case OFPTYPE_FLOW_AGE:
+    case OFPTYPE_SET_ASYNC_CONFIG:
+    case OFPTYPE_SET_CONTROLLER_ID:
+    case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+    case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+    case OFPTYPE_FLOW_MONITOR_CANCEL:
+    case OFPTYPE_FLOW_MONITOR_PAUSED:
+    case OFPTYPE_FLOW_MONITOR_RESUMED:
     default:
         if (VLOG_IS_DBG_ENABLED()) {
             char *s = ofp_to_string(msg->data, msg->size, 2);
@@ -325,11 +320,12 @@ send_features_request(struct lswitch *sw, struct rconn *rconn)
         struct ofp_switch_config *osc;
 
         /* Send OFPT_FEATURES_REQUEST. */
-        make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &b);
+        b = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
         queue_tx(sw, rconn, b);
 
         /* Send OFPT_SET_CONFIG. */
-        osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &b);
+        b = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, OFP10_VERSION, sizeof *osc);
+        osc = ofpbuf_put_uninit(b, sizeof *osc);
         osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
         queue_tx(sw, rconn, b);
 
@@ -354,14 +350,14 @@ queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *b)
 }
 
 static enum ofperr
-process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf)
+process_switch_features(struct lswitch *sw, struct ofp_header *oh)
 {
     struct ofputil_switch_features features;
     struct ofputil_phy_port port;
     enum ofperr error;
     struct ofpbuf b;
 
-    error = ofputil_decode_switch_features(osf, &features, &b);
+    error = ofputil_decode_switch_features(oh, &features, &b);
     if (error) {
         VLOG_ERR("received invalid switch feature reply (%s)",
                  ofperr_to_string(error));
@@ -370,7 +366,7 @@ process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf)
 
     sw->datapath_id = features.datapath_id;
 
-    while (!ofputil_pull_phy_port(osf->header.version, &b, &port)) {
+    while (!ofputil_pull_phy_port(oh->version, &b, &port)) {
         struct lswitch_port *lp = shash_find_data(&sw->queue_names, port.name);
         if (lp && hmap_node_is_null(&lp->hmap_node)) {
             lp->port_no = port.port_no;
diff --git a/lib/ofp-errors.c b/lib/ofp-errors.c
index e1349b0..13b5c4c 100644
--- a/lib/ofp-errors.c
+++ b/lib/ofp-errors.c
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include "byte-order.h"
 #include "dynamic-string.h"
+#include "ofp-msgs.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
@@ -176,25 +177,28 @@ ofperr_encode_msg__(enum ofperr error, const struct ofperr_domain *domain,
 
     pair = ofperr_get_pair__(error, domain);
     if (!ofperr_is_nx_extension(error)) {
-        oem = make_openflow_xid(data_len + sizeof *oem, OFPT_ERROR, xid, &buf);
+        buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid,
+                               sizeof *oem + data_len);
+
+        oem = ofpbuf_put_uninit(buf, sizeof *oem);
         oem->type = htons(pair->type);
         oem->code = htons(pair->code);
     } else {
         struct nx_vendor_error *nve;
 
-        oem = make_openflow_xid(data_len + sizeof *oem + sizeof *nve,
-                                OFPT_ERROR, xid, &buf);
+        buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid,
+                               sizeof *oem + sizeof *nve + data_len);
+
+        oem = ofpbuf_put_uninit(buf, sizeof *oem);
         oem->type = htons(NXET_VENDOR);
         oem->code = htons(NXVC_VENDOR_ERROR);
 
-        nve = (struct nx_vendor_error *) oem->data;
+        nve = ofpbuf_put_uninit(buf, sizeof *nve);
         nve->vendor = htonl(NX_VENDOR_ID);
         nve->type = htons(pair->type);
         nve->code = htons(pair->code);
     }
-    oem->header.version = domain->version;
 
-    buf->size -= data_len;
     ofpbuf_put(buf, data, data_len);
 
     return buf;
@@ -268,34 +272,33 @@ ofperr_get_code(enum ofperr error, const struct ofperr_domain *domain)
 /* Tries to decodes 'oh', which should be an OpenFlow OFPT_ERROR message.
  * Returns an OFPERR_* constant on success, 0 on failure.
  *
- * If 'payload_ofs' is nonnull, on success '*payload_ofs' is set to the offset
- * to the payload starting from 'oh' and on failure it is set to 0. */
+ * If 'payload' is nonnull, on success '*payload' is initialized to the
+ * error's payload, and on failure it is cleared. */
 enum ofperr
-ofperr_decode_msg(const struct ofp_header *oh, size_t *payload_ofs)
+ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
     const struct ofperr_domain *domain;
     const struct ofp_error_msg *oem;
+    enum ofpraw raw;
     uint16_t type, code;
     enum ofperr error;
     struct ofpbuf b;
 
-    if (payload_ofs) {
-        *payload_ofs = 0;
+    if (payload) {
+        memset(payload, 0, sizeof *payload);
     }
 
     /* Pull off the error message. */
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
-    oem = ofpbuf_try_pull(&b, sizeof *oem);
-    if (!oem) {
+    error = ofpraw_pull(&raw, &b);
+    if (error) {
         return 0;
     }
+    oem = ofpbuf_pull(&b, sizeof *oem);
 
-    /* Check message type and version. */
-    if (oh->type != OFPT_ERROR) {
-        return 0;
-    }
+    /* Check version. */
     domain = ofperr_domain_from_version(oh->version);
     if (!domain) {
         return 0;
@@ -325,8 +328,8 @@ ofperr_decode_msg(const struct ofp_header *oh, size_t *payload_ofs)
     if (!error) {
         error = ofperr_decode_type(domain, type);
     }
-    if (error && payload_ofs) {
-        *payload_ofs = (uint8_t *) b.data - (uint8_t *) oh;
+    if (error && payload) {
+        ofpbuf_use_const(payload, b.data, b.size);
     }
     return error;
 }
diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
index dddf8d0..1af70da 100644
--- a/lib/ofp-errors.h
+++ b/lib/ofp-errors.h
@@ -23,6 +23,7 @@
 
 struct ds;
 struct ofp_header;
+struct ofpbuf;
 
 /* Error codes.
  *
@@ -508,7 +509,8 @@ enum ofperr ofperr_decode(const struct ofperr_domain *,
 enum ofperr ofperr_decode_type(const struct ofperr_domain *, uint16_t type);
 enum ofperr ofperr_from_name(const char *);
 
-enum ofperr ofperr_decode_msg(const struct ofp_header *, size_t *payload_ofs);
+enum ofperr ofperr_decode_msg(const struct ofp_header *,
+                              struct ofpbuf *payload);
 struct ofpbuf *ofperr_encode_reply(enum ofperr, const struct ofp_header *);
 struct ofpbuf *ofperr_encode_hello(enum ofperr, const struct ofperr_domain *,
                                    const char *);
diff --git a/lib/ofp-msgs.c b/lib/ofp-msgs.c
new file mode 100644
index 0000000..479f768
--- /dev/null
+++ b/lib/ofp-msgs.c
@@ -0,0 +1,962 @@
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "ofp-msgs.h"
+#include <assert.h>
+#include "byte-order.h"
+#include "dynamic-string.h"
+#include "hash.h"
+#include "hmap.h"
+#include "ofpbuf.h"
+#include "openflow/nicira-ext.h"
+#include "openflow/openflow.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(ofp_msgs);
+
+#define OFPT_VENDOR 4
+#define OFPT10_STATS_REQUEST 16
+#define OFPT10_STATS_REPLY 17
+#define OFPT11_STATS_REQUEST 18
+#define OFPT11_STATS_REPLY 19
+#define OFPST_VENDOR 0xffff
+
+/* A thin abstraction of OpenFlow headers:
+ *
+ *   - 'version' and 'type' come straight from struct ofp_header, so these are
+ *     always present and meaningful.
+ *
+ *   - 'stat' comes from the 'type' member in statistics messages only.  It is
+ *     meaningful, therefore, only if 'version' and 'type' taken together
+ *     specify a statistics request or reply.  Otherwise it is 0.
+ *
+ *   - 'vendor' is meaningful only for vendor messages, that is, if 'version'
+ *     and 'type' specify a vendor message or if 'version' and 'type' specify
+ *     a statistics message and 'stat' specifies a vendor statistic type.
+ *     Otherwise it is 0.
+ *
+ *   - 'subtype' is meaningful only for vendor messages and otherwise 0.  It
+ *     specifies a vendor-defined subtype.  There is no standard format for
+ *     these but 32 bits seems like it should be enough. */
+struct ofphdrs {
+    uint8_t version;            /* From ofp_header. */
+    uint8_t type;               /* From ofp_header. */
+    uint16_t stat;              /* From ofp10_stats_msg or ofp11_stats_msg. */
+    uint32_t vendor;            /* From ofp_vendor_header,
+                                 * ofp10_vendor_stats_msg, or
+                                 * ofp11_vendor_stats_msg. */
+    uint32_t subtype;           /* From nicira_header, nicira10_stats_msg, or
+                                 * nicira11_stats_msg. */
+};
+BUILD_ASSERT_DECL(sizeof(struct ofphdrs) == 12);
+
+/* A mapping from OpenFlow headers to OFPRAW_*.  */
+struct raw_instance {
+    struct hmap_node hmap_node; /* In 'raw_instance_map'. */
+    struct ofphdrs hdrs;        /* Key. */
+    enum ofpraw raw;            /* Value. */
+    unsigned int hdrs_len;      /* ofphdrs_len(hdrs). */
+};
+
+/* Information about a particular 'enum ofpraw'. */
+struct raw_info {
+    /* All possible instantiations of this OFPRAW_* into OpenFlow headers. */
+    struct raw_instance *instances; /* min_version - max_version + 1 elems. */
+    uint8_t min_version;
+    uint8_t max_version;
+
+    unsigned int min_body;
+    unsigned int extra_multiple;
+    enum ofptype type;
+    const char *name;
+};
+
+/* All understood OpenFlow message types, indexed by their 'struct ofphdrs'. */
+static struct hmap raw_instance_map;
+#include "ofp-msgs.inc"
+
+static ovs_be32 alloc_xid(void);
+
+/* ofphdrs functions. */
+static uint32_t ofphdrs_hash(const struct ofphdrs *);
+static bool ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b);
+static enum ofperr ofphdrs_decode(struct ofphdrs *,
+                                  const struct ofp_header *oh, size_t length);
+static void ofphdrs_decode_assert(struct ofphdrs *,
+                                  const struct ofp_header *oh, size_t length);
+size_t ofphdrs_len(const struct ofphdrs *);
+
+static const struct raw_info *raw_info_get(enum ofpraw);
+static struct raw_instance *raw_instance_get(const struct raw_info *,
+                                             uint8_t version);
+
+static enum ofperr ofpraw_from_ofphdrs(enum ofpraw *, const struct ofphdrs *);
+
+/* Returns a transaction ID to use for an outgoing OpenFlow message. */
+static ovs_be32
+alloc_xid(void)
+{
+    static uint32_t next_xid = 1;
+    return htonl(next_xid++);
+}
+
+static uint32_t
+ofphdrs_hash(const struct ofphdrs *hdrs)
+{
+    BUILD_ASSERT_DECL(sizeof *hdrs == 12);
+    return hash_words((const uint32_t *) hdrs, 3, 0);
+}
+
+static bool
+ofphdrs_equal(const struct ofphdrs *a, const struct ofphdrs *b)
+{
+    return !memcmp(a, b, sizeof *a);
+}
+
+static void
+log_bad_vendor(uint32_t vendor)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+    VLOG_WARN_RL(&rl, "OpenFlow message has unknown vendor %#"PRIx32, vendor);
+}
+
+static enum ofperr
+ofphdrs_decode(struct ofphdrs *hdrs,
+               const struct ofp_header *oh, size_t length)
+{
+    memset(hdrs, 0, sizeof *hdrs);
+    if (length < sizeof *oh) {
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+
+    /* Get base message version and type (OFPT_*). */
+    hdrs->version = oh->version;
+    hdrs->type = oh->type;
+
+    if (hdrs->type == OFPT_VENDOR) {
+        /* Get vendor. */
+        const struct ofp_vendor_header *ovh;
+
+        if (length < sizeof *ovh) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        ovh = (const struct ofp_vendor_header *) oh;
+        hdrs->vendor = ntohl(ovh->vendor);
+        if (hdrs->vendor == NX_VENDOR_ID) {
+            /* Get Nicira message subtype (NXT_*). */
+            const struct nicira_header *nh;
+
+            if (length < sizeof *nh) {
+                return OFPERR_OFPBRC_BAD_LEN;
+            }
+            nh = (const struct nicira_header *) oh;
+            hdrs->subtype = ntohl(nh->subtype);
+        } else {
+            log_bad_vendor(hdrs->vendor);
+            return OFPERR_OFPBRC_BAD_VENDOR;
+        }
+    } else if (hdrs->version == OFP10_VERSION
+               && (hdrs->type == OFPT10_STATS_REQUEST ||
+                   hdrs->type == OFPT10_STATS_REPLY)) {
+        const struct ofp_stats_msg *osm;
+
+        /* Get statistic type (OFPST_*). */
+        if (length < sizeof *osm) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        osm = (const struct ofp_stats_msg *) oh;
+        hdrs->stat = ntohs(osm->type);
+
+        if (hdrs->stat == OFPST_VENDOR) {
+            /* Get vendor. */
+            const struct ofp10_vendor_stats_msg *ovsm;
+
+            if (length < sizeof *ovsm) {
+                return OFPERR_OFPBRC_BAD_LEN;
+            }
+
+            ovsm = (const struct ofp10_vendor_stats_msg *) oh;
+            hdrs->vendor = ntohl(ovsm->vendor);
+            if (hdrs->vendor == NX_VENDOR_ID) {
+                /* Get Nicira statistic type (NXST_*). */
+                const struct nicira10_stats_msg *nsm;
+
+                if (length < sizeof *nsm) {
+                    return OFPERR_OFPBRC_BAD_LEN;
+                }
+                nsm = (const struct nicira10_stats_msg *) oh;
+                hdrs->subtype = ntohl(nsm->subtype);
+            } else {
+                log_bad_vendor(hdrs->vendor);
+                return OFPERR_OFPBRC_BAD_VENDOR;
+            }
+        }
+    } else if (hdrs->version == OFP11_VERSION
+               && (hdrs->type == OFPT11_STATS_REQUEST ||
+                   hdrs->type == OFPT11_STATS_REPLY)) {
+        const struct ofp11_stats_msg *osm;
+
+        /* Get statistic type (OFPST_*). */
+        if (length < sizeof *osm) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        osm = (const struct ofp11_stats_msg *) oh;
+        hdrs->stat = ntohs(osm->type);
+
+        if (hdrs->stat == OFPST_VENDOR) {
+            /* Get vendor. */
+            const struct ofp11_vendor_stats_msg *ovsm;
+
+            if (length < sizeof *ovsm) {
+                return OFPERR_OFPBRC_BAD_LEN;
+            }
+
+            ovsm = (const struct ofp11_vendor_stats_msg *) oh;
+            hdrs->vendor = ntohl(ovsm->vendor);
+            if (hdrs->vendor == NX_VENDOR_ID) {
+                /* Get Nicira statistic type (NXST_*). */
+                const struct nicira11_stats_msg *nsm;
+
+                if (length < sizeof *nsm) {
+                    return OFPERR_OFPBRC_BAD_LEN;
+                }
+                nsm = (const struct nicira11_stats_msg *) oh;
+                hdrs->subtype = ntohl(nsm->subtype);
+            } else {
+                log_bad_vendor(hdrs->vendor);
+                return OFPERR_OFPBRC_BAD_VENDOR;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static void
+ofphdrs_decode_assert(struct ofphdrs *hdrs,
+                      const struct ofp_header *oh, size_t length)
+{
+    enum ofperr error = ofphdrs_decode(hdrs, oh, length);
+    assert(!error);
+}
+
+static bool
+ofphdrs_is_stat(const struct ofphdrs *hdrs)
+{
+    return (hdrs->version == OFP10_VERSION
+            ? (hdrs->type == OFPT10_STATS_REQUEST ||
+               hdrs->type == OFPT10_STATS_REPLY)
+            : (hdrs->type == OFPT11_STATS_REQUEST ||
+               hdrs->type == OFPT11_STATS_REPLY));
+}
+
+size_t
+ofphdrs_len(const struct ofphdrs *hdrs)
+{
+    if (hdrs->type == OFPT_VENDOR) {
+        return sizeof(struct nicira_header);
+    }
+
+    if (hdrs->version == OFP10_VERSION) {
+        if (hdrs->type == OFPT10_STATS_REQUEST ||
+            hdrs->type == OFPT10_STATS_REPLY) {
+            return (hdrs->stat == OFPST_VENDOR
+                    ? sizeof(struct nicira10_stats_msg)
+                    : sizeof(struct ofp_stats_msg));
+        }
+    } else if (hdrs->version == OFP11_VERSION) {
+        if (hdrs->type == OFPT11_STATS_REQUEST ||
+            hdrs->type == OFPT11_STATS_REPLY) {
+            return (hdrs->stat == OFPST_VENDOR
+                    ? sizeof(struct nicira11_stats_msg)
+                    : sizeof(struct ofp11_stats_msg));
+        }
+    }
+
+    return sizeof(struct ofp_header);
+}
+
+/* Determines the OFPRAW_* type of the OpenFlow message at 'oh', which has
+ * length 'oh->length'.  (The caller must ensure that 'oh->length' bytes of
+ * data are readable at 'oh'.)  On success, returns 0 and stores the type into
+ * '*raw'.  On failure, returns an OFPERR_* error code and zeros '*raw'.
+ *
+ * This function checks that 'oh' is a valid length for its particular type of
+ * message, and returns an error if not. */
+enum ofperr
+ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh)
+{
+    struct ofpbuf msg;
+
+    ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+    return ofpraw_pull(raw, &msg);
+}
+
+/* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
+ * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
+ * stores the type into '*rawp'.  On failure, returns an OFPERR_* error code
+ * and zeros '*rawp'.
+ *
+ * This function checks that the message has a valid length for its particular
+ * type of message, and returns an error if not.
+ *
+ * In addition to setting '*rawp', this function pulls off the OpenFlow header
+ * (including the stats headers, vendor header, and any subtype header) with
+ * ofpbuf_pull().  It also sets 'msg->l2' to the start of the OpenFlow header
+ * and 'msg->l3' just beyond the headers (that is, to the final value of
+ * msg->data). */
+enum ofperr
+ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+    const struct raw_instance *instance;
+    const struct raw_info *info;
+    struct ofphdrs hdrs;
+
+    unsigned int min_len;
+    unsigned int len;
+
+    enum ofperr error;
+    enum ofpraw raw;
+
+    /* Set default outputs. */
+    msg->l2 = msg->l3 = msg->data;
+    *rawp = 0;
+
+    len = msg->size;
+    error = ofphdrs_decode(&hdrs, msg->data, len);
+    if (error) {
+        return error;
+    }
+
+    error = ofpraw_from_ofphdrs(&raw, &hdrs);
+    if (error) {
+        return error;
+    }
+
+    info = raw_info_get(raw);
+    instance = raw_instance_get(info, hdrs.version);
+    msg->l2 = ofpbuf_pull(msg, instance->hdrs_len);
+    msg->l3 = msg->data;
+
+    min_len = instance->hdrs_len + info->min_body;
+    switch (info->extra_multiple) {
+    case 0:
+        if (len != min_len) {
+            VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
+                         "length %u)", info->name, len, min_len);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        break;
+
+    case 1:
+        if (len < min_len) {
+            VLOG_WARN_RL(&rl, "received %s with incorrect length %u (expected "
+                         "length at least %u bytes)",
+                         info->name, len, min_len);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        break;
+
+    default:
+        if (len < min_len || (len - min_len) % info->extra_multiple) {
+            VLOG_WARN_RL(&rl, "received %s with incorrect length %u (must be "
+                         "exactly %u bytes or longer by an integer multiple "
+                         "of %u bytes)",
+                         info->name, len, min_len, info->extra_multiple);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        break;
+    }
+
+    *rawp = raw;
+    return 0;
+}
+
+/* Does the same job as ofpraw_pull(), except that it assert-fails if
+ * ofpbuf_pull() would have reported an error.  Thus, it's able to use the
+ * return value for the OFPRAW_* message type instead of an error code.
+ *
+ * (It only makes sense to use this function if you previously called
+ * ofpbuf_decode() on the message and thus know that it's OK.) */
+enum ofpraw
+ofpraw_pull_assert(struct ofpbuf *msg)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_pull(&raw, msg);
+    assert(!error);
+    return raw;
+}
+
+/* Determines the OFPRAW_* type of the OpenFlow message that starts at 'oh' and
+ * has length 'length' bytes.  On success, returns 0 and stores the type into
+ * '*rawp'.  On failure, returns an OFPERR_* error code and zeros '*rawp'.
+ *
+ * Unlike other functions for decoding message types, this one is not picky
+ * about message length.  For example, it will successfully decode a message
+ * whose body is shorter than the minimum length for a message of its type.
+ * Thus, this is the correct function to use for decoding the type of a message
+ * that might have been truncated, such as the payload of an OpenFlow error
+ * message (which is allowed to be truncated to 64 bytes). */
+enum ofperr
+ofpraw_decode_partial(enum ofpraw *raw,
+                      const struct ofp_header *oh, size_t length)
+{
+    struct ofphdrs hdrs;
+    enum ofperr error;
+
+    error = ofphdrs_decode(&hdrs, oh, length);
+    if (!error) {
+        error = ofpraw_from_ofphdrs(raw, &hdrs);
+    }
+
+    if (error) {
+        *raw = 0;
+    }
+    return error;
+}
+
+/* Encoding messages using OFPRAW_* values. */
+
+static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid,
+                         size_t extra_tailroom, struct ofpbuf *);
+
+/* Allocates and returns a new ofpbuf that contains an OpenFlow header for
+ * 'raw' with OpenFlow version 'version' and a fresh OpenFlow transaction ID.
+ * The ofpbuf has enough tailroom for the minimum body length of 'raw', plus
+ * 'extra_tailroom' additional bytes.
+ *
+ * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
+ * must specify a valid (raw, version) pair.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start.  The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+struct ofpbuf *
+ofpraw_alloc(enum ofpraw raw, uint8_t version, size_t extra_tailroom)
+{
+    return ofpraw_alloc_xid(raw, version, alloc_xid(), extra_tailroom);
+}
+
+/* Same as ofpraw_alloc() but the caller provides the transaction ID. */
+struct ofpbuf *
+ofpraw_alloc_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+                 size_t extra_tailroom)
+{
+    struct ofpbuf *buf = ofpbuf_new(0);
+    ofpraw_put__(raw, version, xid, extra_tailroom, buf);
+    return buf;
+}
+
+/* Same as ofpraw_alloc(), but obtains the OpenFlow version and transaction ID
+ * from 'request->version' and 'request->xid', respectively.
+ *
+ * Even though the version comes from 'request->version', the caller must still
+ * know what it is doing, by specifying a valid pairing of 'raw' and
+ * 'request->version', just like ofpraw_alloc(). */
+struct ofpbuf *
+ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request,
+                   size_t extra_tailroom)
+{
+    return ofpraw_alloc_xid(raw, request->version, request->xid,
+                            extra_tailroom);
+}
+
+/* Allocates and returns a new ofpbuf that contains an OpenFlow header that is
+ * a stats reply to the stats request in 'request', using the same OpenFlow
+ * version and transaction ID as 'request'.  The ofpbuf has enough tailroom for
+ * the stats reply's minimum body length, plus 'extra_tailroom' additional
+ * bytes.
+ *
+ * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
+ * value.  Every stats request has a corresponding reply, so the (raw, version)
+ * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start.  The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+struct ofpbuf *
+ofpraw_alloc_stats_reply(const struct ofp_header *request,
+                         size_t extra_tailroom)
+{
+    enum ofpraw request_raw;
+    enum ofpraw reply_raw;
+    enum ofperr error;
+
+    error = ofpraw_decode_partial(&request_raw, request,
+                                  ntohs(request->length));
+    assert(!error);
+
+    reply_raw = ofpraw_stats_request_to_reply(request_raw, request->version);
+    assert(reply_raw);
+
+    return ofpraw_alloc_reply(reply_raw, request, extra_tailroom);
+}
+
+/* Appends to 'buf' an OpenFlow header for 'raw' with OpenFlow version
+ * 'version' and a fresh OpenFlow transaction ID.  Preallocates enough tailroom
+ * in 'buf' for the minimum body length of 'raw', plus 'extra_tailroom'
+ * additional bytes.
+ *
+ * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
+ * must specify a valid (raw, version) pair.
+ *
+ * Upon return, 'buf->l2' points to the beginning of the OpenFlow header and
+ * 'buf->l3' points just after it, to where the message's body will start.  The
+ * caller must actually allocating the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit(). */
+void
+ofpraw_put(enum ofpraw raw, uint8_t version, struct ofpbuf *buf)
+{
+    ofpraw_put__(raw, version, alloc_xid(), 0, buf);
+}
+
+/* Same as ofpraw_put() but the caller provides the transaction ID. */
+void
+ofpraw_put_xid(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+               struct ofpbuf *buf)
+{
+    ofpraw_put__(raw, version, xid, 0, buf);
+}
+
+/* Same as ofpraw_put(), but obtains the OpenFlow version and transaction ID
+ * from 'request->version' and 'request->xid', respectively.
+ *
+ * Even though the version comes from 'request->version', the caller must still
+ * know what it is doing, by specifying a valid pairing of 'raw' and
+ * 'request->version', just like ofpraw_put(). */
+void
+ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request,
+                 struct ofpbuf *buf)
+{
+    ofpraw_put__(raw, request->version, request->xid, 0, buf);
+}
+
+/* Appends to 'buf' an OpenFlow header that is a stats reply to the stats
+ * request in 'request', using the same OpenFlow version and transaction ID as
+ * 'request'.  Preallocate enough tailroom in 'buf for the stats reply's
+ * minimum body length, plus 'extra_tailroom' additional bytes.
+ *
+ * 'request' must be a stats request, that is, an OFPRAW_OFPST* or OFPRAW_NXST*
+ * value.  Every stats request has a corresponding reply, so the (raw, version)
+ * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
+ *
+ * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
+ * and 'l3' points just after it, to where the message's body will start.  The
+ * caller must actually allocate the body into the space reserved for it,
+ * e.g. with ofpbuf_put_uninit().
+ *
+ * The caller owns the returned ofpbuf and must free it when it is no longer
+ * needed, e.g. with ofpbuf_delete(). */
+void
+ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *buf)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_decode_partial(&raw, request, ntohs(request->length));
+    assert(!error);
+
+    raw = ofpraw_stats_request_to_reply(raw, request->version);
+    assert(raw);
+
+    ofpraw_put__(raw, request->version, request->xid, 0, buf);
+}
+
+static void
+ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
+             size_t extra_tailroom, struct ofpbuf *buf)
+{
+    const struct raw_info *info = raw_info_get(raw);
+    const struct raw_instance *instance = raw_instance_get(info, version);
+    const struct ofphdrs *hdrs = &instance->hdrs;
+    struct ofp_header *oh;
+
+    ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body
+                                   + extra_tailroom));
+    buf->l2 = ofpbuf_put_uninit(buf, instance->hdrs_len);
+    buf->l3 = ofpbuf_tail(buf);
+
+    oh = buf->l2;
+    oh->version = version;
+    oh->type = hdrs->type;
+    oh->length = htons(buf->size);
+    oh->xid = xid;
+
+    if (hdrs->type == OFPT_VENDOR) {
+        struct nicira_header *nh = buf->l2;
+
+        assert(hdrs->vendor == NX_VENDOR_ID);
+        nh->vendor = htonl(hdrs->vendor);
+        nh->subtype = htonl(hdrs->subtype);
+    } else if (version == OFP10_VERSION
+               && (hdrs->type == OFPT10_STATS_REQUEST ||
+                   hdrs->type == OFPT10_STATS_REPLY)) {
+        struct ofp_stats_msg *osm = buf->l2;
+
+        osm->type = htons(hdrs->stat);
+        osm->flags = htons(0);
+
+        if (hdrs->stat == OFPST_VENDOR) {
+            struct ofp10_vendor_stats_msg *ovsm = buf->l2;
+
+            ovsm->vendor = htonl(hdrs->vendor);
+            if (hdrs->vendor == NX_VENDOR_ID) {
+                struct nicira10_stats_msg *nsm = buf->l2;
+
+                nsm->subtype = htonl(hdrs->subtype);
+                memset(nsm->pad, 0, sizeof nsm->pad);
+            } else {
+                NOT_REACHED();
+            }
+        }
+    } else if (version == OFP11_VERSION
+               && (hdrs->type == OFPT11_STATS_REQUEST ||
+                   hdrs->type == OFPT11_STATS_REPLY)) {
+        struct ofp11_stats_msg *osm = buf->l2;
+
+        osm->type = htons(hdrs->stat);
+        osm->flags = htons(0);
+        memset(osm->pad, 0, sizeof osm->pad);
+
+        if (hdrs->stat == OFPST_VENDOR) {
+            struct ofp11_vendor_stats_msg *ovsm = buf->l2;
+
+            ovsm->vendor = htonl(hdrs->vendor);
+            if (hdrs->vendor == NX_VENDOR_ID) {
+                struct nicira11_stats_msg *nsm = buf->l2;
+
+                nsm->subtype = htonl(hdrs->subtype);
+            } else {
+                NOT_REACHED();
+            }
+        }
+    }
+}
+
+/* Returns 'raw''s name.
+ *
+ * The name is the name used for 'raw' in the OpenFlow specification.  For
+ * example, ofpraw_get_name(OFPRAW_OFPT10_FEATURES_REPLY) is
+ * "OFPT_FEATURES_REPLY".
+ *
+ * The caller must not modify or free the returned string. */
+const char *
+ofpraw_get_name(enum ofpraw raw)
+{
+    return raw_info_get(raw)->name;
+}
+
+/* Returns the stats reply that corresponds to 'raw' in the given OpenFlow
+ * 'version'. */
+enum ofpraw
+ofpraw_stats_request_to_reply(enum ofpraw raw, uint8_t version)
+{
+    const struct raw_info *info = raw_info_get(raw);
+    const struct raw_instance *instance = raw_instance_get(info, version);
+    enum ofpraw reply_raw;
+    struct ofphdrs hdrs;
+    enum ofperr error;
+
+    hdrs = instance->hdrs;
+    if (hdrs.version == OFP10_VERSION) {
+        assert(hdrs.type == OFPT10_STATS_REQUEST);
+        hdrs.type = OFPT10_STATS_REPLY;
+    } else {
+        assert(hdrs.type == OFPT11_STATS_REQUEST);
+        hdrs.type = OFPT11_STATS_REPLY;
+    }
+
+    error = ofpraw_from_ofphdrs(&reply_raw, &hdrs);
+    assert(!error);
+
+    return reply_raw;
+}
+
+/* Determines the OFPTYPE_* type of the OpenFlow message at 'oh', which has
+ * length 'oh->length'.  (The caller must ensure that 'oh->length' bytes of
+ * data are readable at 'oh'.)  On success, returns 0 and stores the type into
+ * '*typep'.  On failure, returns an OFPERR_* error code and zeros '*typep'.
+ *
+ * This function checks that 'oh' is a valid length for its particular type of
+ * message, and returns an error if not. */
+enum ofperr
+ofptype_decode(enum ofptype *typep, const struct ofp_header *oh)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_decode(&raw, oh);
+    *typep = error ? 0 : ofptype_from_ofpraw(raw);
+    return error;
+}
+
+/* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts
+ * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
+ * stores the type into '*typep'.  On failure, returns an OFPERR_* error code
+ * and zeros '*typep'.
+ *
+ * This function checks that the message has a valid length for its particular
+ * type of message, and returns an error if not.
+ *
+ * In addition to setting '*typep', this function pulls off the OpenFlow header
+ * (including the stats headers, vendor header, and any subtype header) with
+ * ofpbuf_pull().  It also sets 'msg->l2' to the start of the OpenFlow header
+ * and 'msg->l3' just beyond the headers (that is, to the final value of
+ * msg->data). */
+enum ofperr
+ofptype_pull(enum ofptype *typep, struct ofpbuf *buf)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_pull(&raw, buf);
+    *typep = error ? 0 : ofptype_from_ofpraw(raw);
+    return error;
+}
+
+/* Returns the OFPTYPE_* type that corresponds to 'raw'.
+ *
+ * (This is a one-way trip, because the mapping from ofpraw to ofptype is
+ * many-to-one.)  */
+enum ofptype
+ofptype_from_ofpraw(enum ofpraw raw)
+{
+    return raw_info_get(raw)->type;
+}
+
+/* Updates the 'length' field of the OpenFlow message in 'buf' to
+ * 'buf->size'. */
+void
+ofpmsg_update_length(struct ofpbuf *buf)
+{
+    struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh);
+    oh->length = htons(buf->size);
+}
+
+/* Returns just past the Openflow header (including the stats headers, vendor
+ * header, and any subtype header) in 'oh'. */
+const void *
+ofpmsg_body(const struct ofp_header *oh)
+{
+    struct ofphdrs hdrs;
+
+    ofphdrs_decode_assert(&hdrs, oh, ntohs(oh->length));
+    return (const uint8_t *) oh + ofphdrs_len(&hdrs);
+}
+
+/* Initializes 'replies' as a new list of stats messages that reply to
+ * 'request', which must be a stats request message.  Initially the list will
+ * consist of only a single reply part without any body.  The caller should
+ * use calls to the other ofpmp_*() functions to add to the body and split the
+ * message into multiple parts, if necessary. */
+void
+ofpmp_init(struct list *replies, const struct ofp_header *request)
+{
+    struct ofpbuf *msg;
+
+    list_init(replies);
+
+    msg = ofpraw_alloc_stats_reply(request, 1000);
+    list_push_back(replies, &msg->list_node);
+}
+
+/* Prepares to append up to 'len' bytes to the series of statistics replies in
+ * 'replies', which should have been initialized with ofpmp_init(), if
+ * necessary adding a new reply to the list.
+ *
+ * Returns an ofpbuf with at least 'len' bytes of tailroom.  The 'len' bytes
+ * have not actually been allocated, so the caller must do so with
+ * e.g. ofpbuf_put_uninit(). */
+struct ofpbuf *
+ofpmp_reserve(struct list *replies, size_t len)
+{
+    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+
+    if (msg->size + len <= UINT16_MAX) {
+        ofpbuf_prealloc_tailroom(msg, len);
+        return msg;
+    } else {
+        unsigned int hdrs_len;
+        struct ofpbuf *next;
+        struct ofphdrs hdrs;
+
+        ofphdrs_decode_assert(&hdrs, msg->data, msg->size);
+        hdrs_len = ofphdrs_len(&hdrs);
+
+        next = ofpbuf_new(MAX(1024, hdrs_len + len));
+        ofpbuf_put(next, msg->data, hdrs_len);
+        list_push_back(replies, &next->list_node);
+
+        return next;
+    }
+}
+
+/* Appends 'len' bytes to the series of statistics replies in 'replies', and
+ * returns the first byte. */
+void *
+ofpmp_append(struct list *replies, size_t len)
+{
+    return ofpbuf_put_uninit(ofpmp_reserve(replies, len), len);
+}
+
+/* Sometimes, when composing stats replies, it's difficult to predict how long
+ * an individual reply chunk will be before actually encoding it into the reply
+ * buffer.  This function allows easy handling of this case: just encode the
+ * reply, then use this function to break the message into two pieces if it
+ * exceeds the OpenFlow message limit.
+ *
+ * In detail, if the final stats message in 'replies' is too long for OpenFlow,
+ * this function breaks it into two separate stats replies, the first one with
+ * the first 'start_ofs' bytes, the second one containing the bytes from that
+ * offset onward. */
+void
+ofpmp_postappend(struct list *replies, size_t start_ofs)
+{
+    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+
+    assert(start_ofs <= UINT16_MAX);
+    if (msg->size > UINT16_MAX) {
+        size_t len = msg->size - start_ofs;
+        memcpy(ofpmp_append(replies, len),
+               (const uint8_t *) msg->data + start_ofs, len);
+        msg->size = start_ofs;
+    }
+}
+
+static ovs_be16 *
+ofpmp_flags__(const struct ofp_header *oh)
+{
+    return (oh->version == OFP10_VERSION
+            ? &((struct ofp_stats_msg *) oh)->flags
+            : &((struct ofp11_stats_msg *) oh)->flags);
+}
+
+/* Returns the OFPSF_* flags found in the OpenFlow stats header of 'oh', which
+ * must be an OpenFlow stats request or reply.
+ *
+ * (OFPSF_REPLY_MORE is the only defined flag.) */
+uint16_t
+ofpmp_flags(const struct ofp_header *oh)
+{
+    return ntohs(*ofpmp_flags__(oh));
+}
+
+/* Returns true if the OFPSF_REPLY_MORE flag is set in the OpenFlow stats
+ * header of 'oh', which must be an OpenFlow stats request or reply, false if
+ * it is not set. */
+bool
+ofpmp_more(const struct ofp_header *oh)
+{
+    return (ofpmp_flags(oh) & OFPSF_REPLY_MORE) != 0;
+}
+
+static void ofpmsgs_init(void);
+
+static const struct raw_info *
+raw_info_get(enum ofpraw raw)
+{
+    ofpmsgs_init();
+
+    assert(raw < ARRAY_SIZE(raw_infos));
+    return &raw_infos[raw];
+}
+
+static struct raw_instance *
+raw_instance_get(const struct raw_info *info, uint8_t version)
+{
+    assert(version >= info->min_version && version <= info->max_version);
+    return &info->instances[version - info->min_version];
+}
+
+static enum ofperr
+ofpraw_from_ofphdrs(enum ofpraw *raw, const struct ofphdrs *hdrs)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+    struct raw_instance *raw_hdrs;
+    uint32_t hash;
+
+    ofpmsgs_init();
+
+    hash = ofphdrs_hash(hdrs);
+    HMAP_FOR_EACH_WITH_HASH (raw_hdrs, hmap_node, hash, &raw_instance_map) {
+        if (ofphdrs_equal(hdrs, &raw_hdrs->hdrs)) {
+            *raw = raw_hdrs->raw;
+            return 0;
+        }
+    }
+
+    if (!VLOG_DROP_WARN(&rl)) {
+        struct ds s;
+
+        ds_init(&s);
+        ds_put_format(&s, "version %"PRIu8", type %"PRIu8,
+                      hdrs->version, hdrs->type);
+        if (ofphdrs_is_stat(hdrs)) {
+            ds_put_format(&s, ", stat %"PRIu16, hdrs->stat);
+        }
+        if (hdrs->vendor) {
+            ds_put_format(&s, ", vendor 0x%"PRIx32", subtype %"PRIu32,
+                          hdrs->vendor, hdrs->subtype);
+        }
+        VLOG_WARN("unknown OpenFlow message (%s)", ds_cstr(&s));
+        ds_destroy(&s);
+    }
+
+    return (hdrs->vendor ? OFPERR_OFPBRC_BAD_SUBTYPE
+            : ofphdrs_is_stat(hdrs) ? OFPERR_OFPBRC_BAD_STAT
+            : OFPERR_OFPBRC_BAD_TYPE);
+}
+
+static void
+ofpmsgs_init(void)
+{
+    const struct raw_info *info;
+
+    if (raw_instance_map.buckets) {
+        return;
+    }
+
+    hmap_init(&raw_instance_map);
+    for (info = raw_infos; info < &raw_infos[ARRAY_SIZE(raw_infos)]; info++)
+    {
+        int n_instances = info->max_version - info->min_version + 1;
+        struct raw_instance *inst;
+
+        for (inst = info->instances;
+             inst < &info->instances[n_instances];
+             inst++) {
+            inst->hdrs_len = ofphdrs_len(&inst->hdrs);
+            hmap_insert(&raw_instance_map, &inst->hmap_node,
+                        ofphdrs_hash(&inst->hdrs));
+        }
+    }
+}
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
new file mode 100644
index 0000000..ed73fc7
--- /dev/null
+++ b/lib/ofp-msgs.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2012 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFP_MSGS_H
+#define OFP_MSGS_H 1
+
+/* OpenFlow message headers abstraction.
+ *
+ * OpenFlow headers are unnecessarily complicated:
+ *
+ *   - Some messages with the same meaning were renumbered between 1.0 and 1.1.
+ *
+ *   - "Statistics" (aka multipart) messages have a different format from other
+ *     messages.
+ *
+ *   - The 1.0 header for statistics messages is an odd number of 32-bit words
+ *     long, leaving 64-bit quantities in the body misaligned.  The 1.1 header
+ *     for statistics added a padding word to fix this misalignment, although
+ *     many statistic message bodies did not change.
+ *
+ *   - Vendor-defined messages have an additional header but no standard way to
+ *     distinguish individual types of message within a given vendor.
+ *
+ * This file attempts to abstract out the differences between the various forms
+ * of headers.
+ */
+
+#include "openvswitch/types.h"
+#include "ofp-errors.h"
+#include "util.h"
+
+struct list;
+
+/* Raw identifiers for OpenFlow messages.
+ *
+ * Some OpenFlow messages with similar meanings have multiple variants across
+ * OpenFlow versions or vendor extensions.  Each variant has a different
+ * OFPRAW_* enumeration constant.  More specifically, if two messages have
+ * different types, different numbers, or different arguments, then they must
+ * have different OFPRAW_* values.
+ *
+ * The comments here must follow a stylized form because the "extract-ofp-msgs"
+ * program parses them at build time to generate data tables.  The syntax of
+ * each comment is:
+ *
+ *    type versions (number): arguments.
+ *
+ * where the syntax of each part is:
+ *
+ *    - type: One of OFPT (standard OpenFlow message), OFPST (standard OpenFlow
+ *      statistics message), NXT (Nicira extension message), or NXST (Nicira
+ *      extension statistics message).
+ *
+ *      As new vendors implement extensions it will make sense to expand the
+ *      dictionary of possible types.
+ *
+ *    - versions: The OpenFlow version or versions in which this message is
+ *      supported, e.g. "1.0" or "1.1" or "1.0+".
+ *
+ *    - number:
+ *         For OFPT, the 'type' in struct ofp_header.
+ *         For OFPST, the 'type' in struct ofp_stats_msg or ofp11_stats_msg.
+ *         For NXT, the 'subtype' in struct nicira_header.
+ *         For NXST, the 'subtype' in struct nicira10_stats_msg or
+ *           nicira11_stats_msg.
+ *
+ *    - arguments: The types of data that follow the OpenFlow headers (the
+ *      message "body").  This can be "void" if the message has no body.
+ *      Otherwise, it should be a comma-separated sequence of C types.  The
+ *      last type in the sequence can end with [] if the body ends in a
+ *      variable-length sequence.
+ *
+ *      The arguments are used to validate the lengths of messages when a
+ *      header is parsed.  Any message whose length isn't valid as a length of
+ *      the specified types will be rejected with OFPERR_OFPBRC_BAD_LEN.
+ *
+ *      A few OpenFlow messages, such as OFPT_PACKET_IN, intentionally end with
+ *      only part of a structure, up to some specified member.  The syntax "up
+ *      to <member>" indicates this, e.g. "struct ofp11_packet_in up to data".
+ */
+enum ofpraw {
+/* Standard messages. */
+
+    /* OFPT 1.0+ (0): uint8_t[]. */
+    OFPRAW_OFPT_HELLO,
+
+    /* OFPT 1.0+ (1): struct ofp_error_msg, uint8_t[]. */
+    OFPRAW_OFPT_ERROR,
+
+    /* OFPT 1.0+ (2): uint8_t[]. */
+    OFPRAW_OFPT_ECHO_REQUEST,
+
+    /* OFPT 1.0+ (3): uint8_t[]. */
+    OFPRAW_OFPT_ECHO_REPLY,
+
+    /* OFPT 1.0+ (5): void. */
+    OFPRAW_OFPT_FEATURES_REQUEST,
+
+    /* OFPT 1.0 (6): struct ofp_switch_features, struct ofp10_phy_port[]. */
+    OFPRAW_OFPT10_FEATURES_REPLY,
+    /* OFPT 1.1+ (6): struct ofp_switch_features, struct ofp11_port[]. */
+    OFPRAW_OFPT11_FEATURES_REPLY,
+
+    /* OFPT 1.0+ (7): void. */
+    OFPRAW_OFPT_GET_CONFIG_REQUEST,
+
+    /* OFPT 1.0+ (8): struct ofp_switch_config. */
+    OFPRAW_OFPT_GET_CONFIG_REPLY,
+
+    /* OFPT 1.0-1.1 (9): struct ofp_switch_config. */
+    OFPRAW_OFPT_SET_CONFIG,
+
+    /* OFPT 1.0 (10): struct ofp_packet_in up to data, uint8_t[]. */
+    OFPRAW_OFPT10_PACKET_IN,
+    /* OFPT 1.1 (10): struct ofp11_packet_in up to data, uint8_t[]. */
+    OFPRAW_OFPT11_PACKET_IN,
+    /* NXT 1.0+ (17): struct nx_packet_in, uint8_t[]. */
+    OFPRAW_NXT_PACKET_IN,
+
+    /* OFPT 1.0 (11): struct ofp_flow_removed. */
+    OFPRAW_OFPT10_FLOW_REMOVED,
+    /* NXT 1.0+ (14): struct nx_flow_removed, uint8_t[8][]. */
+    OFPRAW_NXT_FLOW_REMOVED,
+
+    /* OFPT 1.0 (12): struct ofp_port_status, struct ofp10_phy_port. */
+    OFPRAW_OFPT10_PORT_STATUS,
+    /* OFPT 1.1+ (12): struct ofp_port_status, struct ofp11_port. */
+    OFPRAW_OFPT11_PORT_STATUS,
+
+    /* OFPT 1.0 (13): struct ofp_packet_out, uint8_t[]. */
+    OFPRAW_OFPT10_PACKET_OUT,
+    /* OFPT 1.1+ (13): struct ofp11_packet_out, uint8_t[]. */
+    OFPRAW_OFPT11_PACKET_OUT,
+
+    /* OFPT 1.0 (14): struct ofp_flow_mod, struct ofp_action_header[]. */
+    OFPRAW_OFPT10_FLOW_MOD,
+    /* OFPT 1.1+ (14): struct ofp11_flow_mod, struct ofp11_instruction[]. */
+    OFPRAW_OFPT11_FLOW_MOD,
+    /* NXT 1.0+ (13): struct nx_flow_mod, uint8_t[8][]. */
+    OFPRAW_NXT_FLOW_MOD,
+
+    /* OFPT 1.0 (15): struct ofp10_port_mod. */
+    OFPRAW_OFPT10_PORT_MOD,
+    /* OFPT 1.1 (16): struct ofp11_port_mod. */
+    OFPRAW_OFPT11_PORT_MOD,
+
+    /* OFPT 1.0 (18): void. */
+    OFPRAW_OFPT10_BARRIER_REQUEST,
+    /* OFPT 1.1 (20): void. */
+    OFPRAW_OFPT11_BARRIER_REQUEST,
+
+    /* OFPT 1.0 (19): void. */
+    OFPRAW_OFPT10_BARRIER_REPLY,
+    /* OFPT 1.1 (21): void. */
+    OFPRAW_OFPT11_BARRIER_REPLY,
+
+/* Standard statistics. */
+
+    /* OFPST 1.0+ (0): void. */
+    OFPRAW_OFPST_DESC_REQUEST,
+
+    /* OFPST 1.0+ (0): struct ofp_desc_stats. */
+    OFPRAW_OFPST_DESC_REPLY,
+
+    /* OFPST 1.0 (1): struct ofp_flow_stats_request. */
+    OFPRAW_OFPST_FLOW_REQUEST,
+    /* NXST 1.0 (0): struct nx_flow_stats_request, uint8_t[8][]. */
+    OFPRAW_NXST_FLOW_REQUEST,
+
+    /* OFPST 1.0 (1): uint8_t[]. */
+    OFPRAW_OFPST_FLOW_REPLY,
+    /* NXST 1.0 (0): uint8_t[]. */
+    OFPRAW_NXST_FLOW_REPLY,
+
+    /* OFPST 1.0 (2): struct ofp_flow_stats_request. */
+    OFPRAW_OFPST_AGGREGATE_REQUEST,
+    /* NXST 1.0 (1): struct nx_flow_stats_request, uint8_t[8][]. */
+    OFPRAW_NXST_AGGREGATE_REQUEST,
+
+    /* OFPST 1.0 (2): struct ofp_aggregate_stats_reply. */
+    OFPRAW_OFPST_AGGREGATE_REPLY,
+    /* NXST 1.0 (1): struct nx_aggregate_stats_reply. */
+    OFPRAW_NXST_AGGREGATE_REPLY,
+
+    /* OFPST 1.0 (3): void. */
+    OFPRAW_OFPST_TABLE_REQUEST,
+
+    /* OFPST 1.0 (3): struct ofp_table_stats[]. */
+    OFPRAW_OFPST_TABLE_REPLY,
+
+    /* OFPST 1.0 (4): struct ofp_port_stats_request. */
+    OFPRAW_OFPST_PORT_REQUEST,
+
+    /* OFPST 1.0 (4): struct ofp_port_stats[]. */
+    OFPRAW_OFPST_PORT_REPLY,
+
+    /* OFPST 1.0 (5): struct ofp_queue_stats_request. */
+    OFPRAW_OFPST_QUEUE_REQUEST,
+
+    /* OFPST 1.0 (5): struct ofp_queue_stats[]. */
+    OFPRAW_OFPST_QUEUE_REPLY,
+
+    /* OFPST 1.0 (13): void. */
+    OFPRAW_OFPST_PORT_DESC_REQUEST,
+
+    /* OFPST 1.0 (13): struct ofp10_phy_port[]. */
+    OFPRAW_OFPST_PORT_DESC_REPLY,
+
+/* Nicira extension messages.
+ *
+ * Nicira extensions that correspond to standard OpenFlow messages are listed
+ * alongside the standard versions above. */
+
+    /* NXT 1.0+ (10): struct nx_role_request. */
+    OFPRAW_NXT_ROLE_REQUEST,
+
+    /* NXT 1.0+ (11): struct nx_role_request. */
+    OFPRAW_NXT_ROLE_REPLY,
+
+    /* NXT 1.0+ (12): struct nx_set_flow_format. */
+    OFPRAW_NXT_SET_FLOW_FORMAT,
+
+    /* NXT 1.0+ (15): struct nx_flow_mod_table_id. */
+    OFPRAW_NXT_FLOW_MOD_TABLE_ID,
+
+    /* NXT 1.0+ (16): struct nx_set_packet_in_format. */
+    OFPRAW_NXT_SET_PACKET_IN_FORMAT,
+
+    /* NXT 1.0+ (18): void. */
+    OFPRAW_NXT_FLOW_AGE,
+
+    /* NXT 1.0+ (19): struct nx_async_config. */
+    OFPRAW_NXT_SET_ASYNC_CONFIG,
+
+    /* NXT 1.0+ (20): struct nx_controller_id. */
+    OFPRAW_NXT_SET_CONTROLLER_ID,
+
+    /* NXT 1.0+ (21): struct nx_flow_monitor_cancel. */
+    OFPRAW_NXT_FLOW_MONITOR_CANCEL,
+
+    /* NXT 1.0+ (22): void. */
+    OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+
+    /* NXT 1.0+ (23): void. */
+    OFPRAW_NXT_FLOW_MONITOR_RESUMED,
+
+/* Nicira extension statistics.
+ *
+ * Nicira extension statistics that correspond to standard OpenFlow statistics
+ * are listed alongside the standard versions above. */
+
+    /* NXST 1.0 (2): uint8_t[8][]. */
+    OFPRAW_NXST_FLOW_MONITOR_REQUEST,
+
+    /* NXST 1.0 (2): uint8_t[8][]. */
+    OFPRAW_NXST_FLOW_MONITOR_REPLY,
+};
+
+/* Decoding messages into OFPRAW_* values. */
+enum ofperr ofpraw_decode(enum ofpraw *, const struct ofp_header *);
+enum ofperr ofpraw_pull(enum ofpraw *, struct ofpbuf *);
+enum ofpraw ofpraw_pull_assert(struct ofpbuf *);
+
+enum ofperr ofpraw_decode_partial(enum ofpraw *,
+                                  const struct ofp_header *, size_t length);
+
+/* Encoding messages using OFPRAW_* values. */
+struct ofpbuf *ofpraw_alloc(enum ofpraw, uint8_t ofp_version,
+                            size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_xid(enum ofpraw, uint8_t ofp_version,
+                                ovs_be32 xid, size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_reply(enum ofpraw,
+                                  const struct ofp_header *request,
+                                  size_t extra_tailroom);
+struct ofpbuf *ofpraw_alloc_stats_reply(const struct ofp_header *request,
+                                        size_t extra_tailroom);
+
+void ofpraw_put(enum ofpraw, uint8_t ofp_version, struct ofpbuf *);
+void ofpraw_put_xid(enum ofpraw, uint8_t ofp_version, ovs_be32 xid,
+                    struct ofpbuf *);
+void ofpraw_put_reply(enum ofpraw, const struct ofp_header *request,
+                      struct ofpbuf *);
+void ofpraw_put_stats_reply(const struct ofp_header *request, struct ofpbuf *);
+
+/* Information about OFPRAW_* values. */
+const char *ofpraw_get_name(enum ofpraw);
+enum ofpraw ofpraw_stats_request_to_reply(enum ofpraw, uint8_t version);
+
+/* Semantic identifiers for OpenFlow messages.
+ *
+ * Each OFPTYPE_* enumeration constant represents one or more concrete format
+ * of OpenFlow message.  When two variants of a message have essentially the
+ * same meaning, they are assigned a single OFPTYPE_* value.
+ *
+ * The comments here must follow a stylized form because the "extract-ofp-msgs"
+ * program parses them at build time to generate data tables.  The format is
+ * simply to list each OFPRAW_* enumeration constant for a given OFPTYPE_*,
+ * each followed by a period. */
+enum ofptype {
+    /* Immutable messages. */
+    OFPTYPE_HELLO,               /* OFPRAW_OFPT_HELLO. */
+    OFPTYPE_ERROR,               /* OFPRAW_OFPT_ERROR. */
+    OFPTYPE_ECHO_REQUEST,        /* OFPRAW_OFPT_ECHO_REQUEST. */
+    OFPTYPE_ECHO_REPLY,          /* OFPRAW_OFPT_ECHO_REPLY. */
+
+    /* Switch configuration messages. */
+    OFPTYPE_FEATURES_REQUEST,    /* OFPRAW_OFPT_FEATURES_REQUEST. */
+    OFPTYPE_FEATURES_REPLY,      /* OFPRAW_OFPT10_FEATURES_REPLY.
+                                  * OFPRAW_OFPT11_FEATURES_REPLY. */
+    OFPTYPE_GET_CONFIG_REQUEST,  /* OFPRAW_OFPT_GET_CONFIG_REQUEST. */
+    OFPTYPE_GET_CONFIG_REPLY,    /* OFPRAW_OFPT_GET_CONFIG_REPLY. */
+    OFPTYPE_SET_CONFIG,          /* OFPRAW_OFPT_SET_CONFIG. */
+
+    /* Asynchronous messages. */
+    OFPTYPE_PACKET_IN,           /* OFPRAW_OFPT10_PACKET_IN.
+                                  * OFPRAW_OFPT11_PACKET_IN.
+                                  * OFPRAW_NXT_PACKET_IN. */
+    OFPTYPE_FLOW_REMOVED,        /* OFPRAW_OFPT10_FLOW_REMOVED.
+                                  * OFPRAW_NXT_FLOW_REMOVED. */
+    OFPTYPE_PORT_STATUS,         /* OFPRAW_OFPT10_PORT_STATUS.
+                                  * OFPRAW_OFPT11_PORT_STATUS. */
+
+    /* Controller command messages. */
+    OFPTYPE_PACKET_OUT,          /* OFPRAW_OFPT10_PACKET_OUT.
+                                  * OFPRAW_OFPT11_PACKET_OUT. */
+    OFPTYPE_FLOW_MOD,            /* OFPRAW_OFPT10_FLOW_MOD.
+                                  * OFPRAW_OFPT11_FLOW_MOD.
+                                  * OFPRAW_NXT_FLOW_MOD. */
+    OFPTYPE_PORT_MOD,            /* OFPRAW_OFPT10_PORT_MOD.
+                                  * OFPRAW_OFPT11_PORT_MOD. */
+
+    /* Barrier messages. */
+    OFPTYPE_BARRIER_REQUEST,     /* OFPRAW_OFPT10_BARRIER_REQUEST.
+                                  * OFPRAW_OFPT11_BARRIER_REQUEST. */
+    OFPTYPE_BARRIER_REPLY,       /* OFPRAW_OFPT10_BARRIER_REPLY.
+                                  * OFPRAW_OFPT11_BARRIER_REPLY. */
+
+    /* Statistics. */
+    OFPTYPE_DESC_STATS_REQUEST,      /* OFPRAW_OFPST_DESC_REQUEST. */
+    OFPTYPE_DESC_STATS_REPLY,        /* OFPRAW_OFPST_DESC_REPLY. */
+    OFPTYPE_FLOW_STATS_REQUEST,      /* OFPRAW_OFPST_FLOW_REQUEST.
+                                      * OFPRAW_NXST_FLOW_REQUEST. */
+    OFPTYPE_FLOW_STATS_REPLY,        /* OFPRAW_OFPST_FLOW_REPLY.
+                                      * OFPRAW_NXST_FLOW_REPLY. */
+    OFPTYPE_AGGREGATE_STATS_REQUEST, /* OFPRAW_OFPST_AGGREGATE_REQUEST.
+                                      * OFPRAW_NXST_AGGREGATE_REQUEST. */
+    OFPTYPE_AGGREGATE_STATS_REPLY,   /* OFPRAW_OFPST_AGGREGATE_REPLY.
+                                      * OFPRAW_NXST_AGGREGATE_REPLY. */
+    OFPTYPE_TABLE_STATS_REQUEST,     /* OFPRAW_OFPST_TABLE_REQUEST. */
+    OFPTYPE_TABLE_STATS_REPLY,       /* OFPRAW_OFPST_TABLE_REPLY. */
+    OFPTYPE_PORT_STATS_REQUEST,      /* OFPRAW_OFPST_PORT_REQUEST. */
+    OFPTYPE_PORT_STATS_REPLY,        /* OFPRAW_OFPST_PORT_REPLY. */
+    OFPTYPE_QUEUE_STATS_REQUEST,     /* OFPRAW_OFPST_QUEUE_REQUEST. */
+    OFPTYPE_QUEUE_STATS_REPLY,       /* OFPRAW_OFPST_QUEUE_REPLY. */
+    OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
+    OFPTYPE_PORT_DESC_STATS_REPLY,   /* OFPRAW_OFPST_PORT_DESC_REPLY. */
+
+    /* Nicira extensions. */
+    OFPTYPE_ROLE_REQUEST,         /* OFPRAW_NXT_ROLE_REQUEST. */
+    OFPTYPE_ROLE_REPLY,           /* OFPRAW_NXT_ROLE_REPLY. */
+    OFPTYPE_SET_FLOW_FORMAT,      /* OFPRAW_NXT_SET_FLOW_FORMAT. */
+    OFPTYPE_FLOW_MOD_TABLE_ID,    /* OFPRAW_NXT_FLOW_MOD_TABLE_ID. */
+    OFPTYPE_SET_PACKET_IN_FORMAT, /* OFPRAW_NXT_SET_PACKET_IN_FORMAT. */
+    OFPTYPE_FLOW_AGE,             /* OFPRAW_NXT_FLOW_AGE. */
+    OFPTYPE_SET_ASYNC_CONFIG,     /* OFPRAW_NXT_SET_ASYNC_CONFIG. */
+    OFPTYPE_SET_CONTROLLER_ID,    /* OFPRAW_NXT_SET_CONTROLLER_ID. */
+
+    /* Flow monitor extension. */
+    OFPTYPE_FLOW_MONITOR_STATS_REQUEST, /* OFPRAW_NXST_FLOW_MONITOR_REQUEST. */
+    OFPTYPE_FLOW_MONITOR_STATS_REPLY,   /* OFPRAW_NXST_FLOW_MONITOR_REPLY. */
+    OFPTYPE_FLOW_MONITOR_CANCEL,        /* OFPRAW_NXT_FLOW_MONITOR_CANCEL. */
+    OFPTYPE_FLOW_MONITOR_PAUSED,        /* OFPRAW_NXT_FLOW_MONITOR_PAUSED. */
+    OFPTYPE_FLOW_MONITOR_RESUMED,       /* OFPRAW_NXT_FLOW_MONITOR_RESUMED. */
+};
+
+/* Decoding messages into OFPTYPE_* values. */
+enum ofperr ofptype_decode(enum ofptype *, const struct ofp_header *);
+enum ofperr ofptype_pull(enum ofptype *, struct ofpbuf *);
+enum ofptype ofptype_from_ofpraw(enum ofpraw);
+
+/* OpenFlow message properties. */
+void ofpmsg_update_length(struct ofpbuf *);
+const void *ofpmsg_body(const struct ofp_header *);
+
+/* Multipart messages (aka "statistics").
+ *
+ * Individual OpenFlow messages are limited to 64 kB in size, but some messages
+ * need to be longer.  Therefore, multipart messages allow a longer message to
+ * be divided into multiple parts at some convenient boundary.  For example,
+ * limiting the response to a "flow dump" request to 64 kB would unreasonably
+ * limit the maximum number of flows in an OpenFlow switch, so a "flow dump" is
+ * expressed as a multipart request/reply pair, with the reply broken into
+ * pieces between flows.
+ *
+ * Multipart messages always consist of a request/reply pair.
+ *
+ * In OpenFlow 1.0, 1.1, and 1.2, requests must always fit in a single message,
+ * that is, only a multipart reply may have more than one part.  OpenFlow 1.3
+ * adds one multipart request.  This code does not yet support multipart
+ * requests. */
+
+/* Encoding multipart replies.
+ *
+ * These functions are useful for multipart replies that might really require
+ * more than one message.  A multipart message that is known in advance to fit
+ * within 64 kB doesn't need any special treatment, so you might as well use
+ * the ofpraw_alloc_*() functions.
+ *
+ * These functions work with a "struct list" of "struct ofpbuf"s, each of
+ * which represents one part of a multipart message. */
+void ofpmp_init(struct list *, const struct ofp_header *request);
+struct ofpbuf *ofpmp_reserve(struct list *, size_t len);
+void *ofpmp_append(struct list *, size_t len);
+void ofpmp_postappend(struct list *, size_t start_ofs);
+
+/* Decoding multipart replies. */
+uint16_t ofpmp_flags(const struct ofp_header *);
+bool ofpmp_more(const struct ofp_header *);
+
+#endif /* ofp-msgs.h */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 48b8daa..ad88925 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -38,6 +38,7 @@
 #include "nx-match.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
@@ -155,7 +156,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
 }
 
 static void
-ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
+ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
                      int verbosity)
 {
     struct ofputil_packet_out po;
@@ -163,7 +164,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
     enum ofperr error;
 
     ofpbuf_init(&ofpacts, 64);
-    error = ofputil_decode_packet_out(&po, opo, &ofpacts);
+    error = ofputil_decode_packet_out(&po, oh, &ofpacts);
     if (error) {
         ofpbuf_uninit(&ofpacts);
         ofp_print_error(string, error);
@@ -485,14 +486,13 @@ ofputil_action_bitmap_to_name(uint32_t bit)
 }
 
 static void
-ofp_print_switch_features(struct ds *string,
-                          const struct ofp_switch_features *osf)
+ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_switch_features features;
     enum ofperr error;
     struct ofpbuf b;
 
-    error = ofputil_decode_switch_features(osf, &features, &b);
+    error = ofputil_decode_switch_features(oh, &features, &b);
     if (error) {
         ofp_print_error(string, error);
         return;
@@ -512,7 +512,7 @@ ofp_print_switch_features(struct ds *string,
                         ofputil_action_bitmap_to_name, ' ');
     ds_put_char(string, '\n');
 
-    ofp_print_phy_ports(string, osf->header.version, &b);
+    ofp_print_phy_ports(string, oh->version, &b);
 }
 
 static void
@@ -668,13 +668,13 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
 }
 
 static void
-ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
-                   enum ofputil_msg_code code, int verbosity)
+ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
 {
     struct ofputil_flow_mod fm;
     struct ofpbuf ofpacts;
     bool need_priority;
     enum ofperr error;
+    enum ofpraw raw;
 
     ofpbuf_init(&ofpacts, 64);
     error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID, &ofpacts);
@@ -709,14 +709,15 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
     }
 
     ds_put_char(s, ' ');
-    if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
-        const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
+    ofpraw_decode(&raw, oh);
+    if (verbosity >= 3 && raw == OFPRAW_OFPT10_FLOW_MOD) {
+        const struct ofp_flow_mod *ofm = ofpmsg_body(oh);
         ofp10_match_print(s, &ofm->match, verbosity);
 
         /* ofp_print_match() doesn't print priority. */
         need_priority = true;
-    } else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
-        const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
+    } else if (verbosity >= 3 && raw == OFPRAW_NXT_FLOW_MOD) {
+        const struct nx_flow_mod *nfm = ofpmsg_body(oh);
         const void *nxm = nfm + 1;
         char *nxm_s;
 
@@ -884,41 +885,38 @@ ofp_print_error(struct ds *string, enum ofperr error)
 }
 
 static void
-ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
+ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
 {
-    size_t len = ntohs(oem->header.length);
-    size_t payload_ofs, payload_len;
-    const void *payload;
+    size_t len = ntohs(oh->length);
+    struct ofpbuf payload;
     enum ofperr error;
     char *s;
 
-    error = ofperr_decode_msg(&oem->header, &payload_ofs);
+    error = ofperr_decode_msg(oh, &payload);
     if (!error) {
         ds_put_cstr(string, "***decode error***");
-        ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
+        ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
         return;
     }
 
     ds_put_format(string, " %s\n", ofperr_get_name(error));
 
-    payload = (const uint8_t *) oem + payload_ofs;
-    payload_len = len - payload_ofs;
     if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
-        ds_put_printable(string, payload, payload_len);
+        ds_put_printable(string, payload.data, payload.size);
     } else {
-        s = ofp_to_string(payload, payload_len, 1);
+        s = ofp_to_string(payload.data, payload.size, 1);
         ds_put_cstr(string, s);
         free(s);
     }
 }
 
 static void
-ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
+ofp_print_port_status(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_port_status ps;
     enum ofperr error;
 
-    error = ofputil_decode_port_status(ops, &ps);
+    error = ofputil_decode_port_status(oh, &ps);
     if (error) {
         ofp_print_error(string, error);
         return;
@@ -936,8 +934,10 @@ ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
 }
 
 static void
-ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods)
+ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
 {
+    const struct ofp_desc_stats *ods = ofpmsg_body(oh);
+
     ds_put_char(string, '\n');
     ds_put_format(string, "Manufacturer: %.*s\n",
             (int) sizeof ods->mfr_desc, ods->mfr_desc);
@@ -952,13 +952,12 @@ ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods)
 }
 
 static void
-ofp_print_flow_stats_request(struct ds *string,
-                             const struct ofp_stats_msg *osm)
+ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_flow_stats_request fsr;
     enum ofperr error;
 
-    error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
+    error = ofputil_decode_flow_stats_request(&fsr, oh);
     if (error) {
         ofp_print_error(string, error);
         return;
@@ -1037,23 +1036,20 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
 }
 
 static void
-ofp_print_ofpst_aggregate_reply(struct ds *string,
-                                const struct ofp_aggregate_stats_reply *asr)
+ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
 {
-    ds_put_format(string, " packet_count=%"PRIu64,
-                  ntohll(get_32aligned_be64(&asr->packet_count)));
-    ds_put_format(string, " byte_count=%"PRIu64,
-                  ntohll(get_32aligned_be64(&asr->byte_count)));
-    ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
-}
+    struct ofputil_aggregate_stats as;
+    enum ofperr error;
 
-static void
-ofp_print_nxst_aggregate_reply(struct ds *string,
-                               const struct nx_aggregate_stats_reply *nasr)
-{
-    ds_put_format(string, " packet_count=%"PRIu64, ntohll(nasr->packet_count));
-    ds_put_format(string, " byte_count=%"PRIu64, ntohll(nasr->byte_count));
-    ds_put_format(string, " flow_count=%"PRIu32, ntohl(nasr->flow_count));
+    error = ofputil_decode_aggregate_stats_reply(&as, oh);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_format(string, " packet_count=%"PRIu64, as.packet_count);
+    ds_put_format(string, " byte_count=%"PRIu64, as.byte_count);
+    ds_put_format(string, " flow_count=%"PRIu32, as.flow_count);
 }
 
 static void print_port_stat(struct ds *string, const char *leader,
@@ -1075,9 +1071,9 @@ static void print_port_stat(struct ds *string, const char *leader,
 }
 
 static void
-ofp_print_ofpst_port_request(struct ds *string,
-                             const struct ofp_port_stats_request *psr)
+ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
 {
+    const struct ofp_port_stats_request *psr = ofpmsg_body(oh);
     ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
 }
 
@@ -1085,14 +1081,25 @@ static void
 ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
                            int verbosity)
 {
-    const struct ofp_port_stats *ps = ofputil_stats_body(oh);
-    size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
+    struct ofp_port_stats *ps;
+    struct ofpbuf b;
+    size_t n;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    n = b.size / sizeof *ps;
     ds_put_format(string, " %zu ports\n", n);
     if (verbosity < 1) {
         return;
     }
 
-    for (; n--; ps++) {
+    for (;;) {
+        ps = ofpbuf_try_pull(&b, sizeof *ps);
+        if (!ps) {
+            return;
+        }
+
         ds_put_format(string, "  port %2"PRIu16": ", ntohs(ps->port_no));
 
         ds_put_cstr(string, "rx ");
@@ -1117,15 +1124,27 @@ static void
 ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
                             int verbosity)
 {
-    const struct ofp_table_stats *ts = ofputil_stats_body(oh);
-    size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
+    struct ofp_table_stats *ts;
+    struct ofpbuf b;
+    size_t n;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    n = b.size / sizeof *ts;
     ds_put_format(string, " %zu tables\n", n);
     if (verbosity < 1) {
         return;
     }
 
-    for (; n--; ts++) {
+    for (;;) {
         char name[OFP_MAX_TABLE_NAME_LEN + 1];
+
+        ts = ofpbuf_try_pull(&b, sizeof *ts);
+        if (!ts) {
+            return;
+        }
+
         ovs_strlcpy(name, ts->name, sizeof name);
 
         ds_put_format(string, "  %d: %-8s: ", ts->table_id, name);
@@ -1151,9 +1170,10 @@ ofp_print_queue_name(struct ds *string, uint32_t queue_id)
 }
 
 static void
-ofp_print_ofpst_queue_request(struct ds *string,
-                              const struct ofp_queue_stats_request *qsr)
+ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
 {
+    const struct ofp_queue_stats_request *qsr = ofpmsg_body(oh);
+
     ds_put_cstr(string, "port=");
     ofputil_format_port(ntohs(qsr->port_no), string);
 
@@ -1165,14 +1185,25 @@ static void
 ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
                             int verbosity)
 {
-    const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
-    size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
+    struct ofp_queue_stats *qs;
+    struct ofpbuf b;
+    size_t n;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    n = b.size / sizeof *qs;
     ds_put_format(string, " %zu queues\n", n);
     if (verbosity < 1) {
         return;
     }
 
-    for (; n--; qs++) {
+    for (;;) {
+        qs = ofpbuf_try_pull(&b, sizeof *qs);
+        if (!qs) {
+            return;
+        }
+
         ds_put_cstr(string, "  port ");
         ofputil_format_port(ntohs(qs->port_no), string);
         ds_put_cstr(string, " queue ");
@@ -1192,7 +1223,7 @@ ofp_print_ofpst_port_desc_reply(struct ds *string,
     struct ofpbuf b;
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
-    ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
+    ofpraw_pull_assert(&b);
     ds_put_char(string, '\n');
     ofp_print_phy_ports(string, oh->version, &b);
 }
@@ -1200,22 +1231,19 @@ ofp_print_ofpst_port_desc_reply(struct ds *string,
 static void
 ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
 {
-    const struct ofp_stats_msg *srq = (const struct ofp_stats_msg *) oh;
+    uint16_t flags = ofpmp_flags(oh);
 
-    if (srq->flags) {
-        ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
-                      ntohs(srq->flags));
+    if (flags) {
+        ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
     }
 }
 
 static void
 ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
 {
-    const struct ofp_stats_msg *srp = (const struct ofp_stats_msg *) oh;
-
-    if (srp->flags) {
-        uint16_t flags = ntohs(srp->flags);
+    uint16_t flags = ofpmp_flags(oh);
 
+    if (flags) {
         ds_put_cstr(string, " flags=");
         if (flags & OFPSF_REPLY_MORE) {
             ds_put_cstr(string, "[more]");
@@ -1520,195 +1548,174 @@ ofp_print_version(const struct ofp_header *oh,
 }
 
 static void
-ofp_to_string__(const struct ofp_header *oh,
-                const struct ofputil_msg_type *type, struct ds *string,
-                int verbosity)
+ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
+                struct ds *string, int verbosity)
 {
-    enum ofputil_msg_code code;
     const void *msg = oh;
 
-    ds_put_cstr(string, ofputil_msg_type_name(type));
+    ds_put_cstr(string, ofpraw_get_name(raw));
     ofp_print_version(oh, string);
-    code = ofputil_msg_type_code(type);
-    switch (code) {
-    case OFPUTIL_MSG_INVALID:
-        break;
 
-    case OFPUTIL_OFPT_HELLO:
+    switch (ofptype_from_ofpraw(raw)) {
+    case OFPTYPE_HELLO:
         ds_put_char(string, '\n');
         ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
                         0, true);
         break;
 
-    case OFPUTIL_OFPT_ERROR:
-        ofp_print_error_msg(string, msg);
+    case OFPTYPE_ERROR:
+        ofp_print_error_msg(string, oh);
         break;
 
-    case OFPUTIL_OFPT_ECHO_REQUEST:
-    case OFPUTIL_OFPT_ECHO_REPLY:
+    case OFPTYPE_ECHO_REQUEST:
+    case OFPTYPE_ECHO_REPLY:
         ofp_print_echo(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPT_FEATURES_REQUEST:
-        break;
-
-    case OFPUTIL_OFPT_FEATURES_REPLY:
-        ofp_print_switch_features(string, msg);
+    case OFPTYPE_FEATURES_REQUEST:
         break;
 
-    case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+    case OFPTYPE_FEATURES_REPLY:
+        ofp_print_switch_features(string, oh);
         break;
 
-    case OFPUTIL_OFPT_GET_CONFIG_REPLY:
-    case OFPUTIL_OFPT_SET_CONFIG:
-        ofp_print_switch_config(string, msg);
+    case OFPTYPE_GET_CONFIG_REQUEST:
         break;
 
-    case OFPUTIL_OFPT_PACKET_IN:
-    case OFPUTIL_NXT_PACKET_IN:
-        ofp_print_packet_in(string, msg, verbosity);
+    case OFPTYPE_GET_CONFIG_REPLY:
+    case OFPTYPE_SET_CONFIG:
+        ofp_print_switch_config(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_OFPT_FLOW_REMOVED:
-    case OFPUTIL_NXT_FLOW_REMOVED:
-        ofp_print_flow_removed(string, msg);
+    case OFPTYPE_PACKET_IN:
+        ofp_print_packet_in(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPT_PORT_STATUS:
-        ofp_print_port_status(string, msg);
+    case OFPTYPE_FLOW_REMOVED:
+        ofp_print_flow_removed(string, oh);
         break;
 
-    case OFPUTIL_OFPT_PACKET_OUT:
-        ofp_print_packet_out(string, msg, verbosity);
+    case OFPTYPE_PORT_STATUS:
+        ofp_print_port_status(string, oh);
         break;
 
-    case OFPUTIL_OFPT_FLOW_MOD:
-    case OFPUTIL_NXT_FLOW_MOD:
-        ofp_print_flow_mod(string, msg, code, verbosity);
+    case OFPTYPE_PACKET_OUT:
+        ofp_print_packet_out(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPT_PORT_MOD:
-        ofp_print_port_mod(string, msg);
+    case OFPTYPE_FLOW_MOD:
+        ofp_print_flow_mod(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPT_BARRIER_REQUEST:
-    case OFPUTIL_OFPT_BARRIER_REPLY:
+    case OFPTYPE_PORT_MOD:
+        ofp_print_port_mod(string, oh);
         break;
 
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
-        /* XXX */
+    case OFPTYPE_BARRIER_REQUEST:
+    case OFPTYPE_BARRIER_REPLY:
         break;
 
-    case OFPUTIL_OFPST_DESC_REQUEST:
-    case OFPUTIL_OFPST_PORT_DESC_REQUEST:
+    case OFPTYPE_DESC_STATS_REQUEST:
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
         break;
 
-    case OFPUTIL_OFPST_FLOW_REQUEST:
-    case OFPUTIL_NXST_FLOW_REQUEST:
-    case OFPUTIL_OFPST_AGGREGATE_REQUEST:
-    case OFPUTIL_NXST_AGGREGATE_REQUEST:
+    case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_AGGREGATE_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
-        ofp_print_flow_stats_request(string, msg);
+        ofp_print_flow_stats_request(string, oh);
         break;
 
-    case OFPUTIL_OFPST_TABLE_REQUEST:
+    case OFPTYPE_TABLE_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
         break;
 
-    case OFPUTIL_OFPST_PORT_REQUEST:
+    case OFPTYPE_PORT_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
-        ofp_print_ofpst_port_request(string, msg);
+        ofp_print_ofpst_port_request(string, oh);
         break;
 
-    case OFPUTIL_OFPST_QUEUE_REQUEST:
+    case OFPTYPE_QUEUE_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
-        ofp_print_ofpst_queue_request(string, msg);
+        ofp_print_ofpst_queue_request(string, oh);
         break;
 
-    case OFPUTIL_OFPST_DESC_REPLY:
+    case OFPTYPE_DESC_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
-        ofp_print_ofpst_desc_reply(string, msg);
+        ofp_print_ofpst_desc_reply(string, oh);
         break;
 
-    case OFPUTIL_OFPST_FLOW_REPLY:
-    case OFPUTIL_NXST_FLOW_REPLY:
+    case OFPTYPE_FLOW_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_flow_stats_reply(string, oh);
         break;
 
-    case OFPUTIL_OFPST_QUEUE_REPLY:
+    case OFPTYPE_QUEUE_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_ofpst_queue_reply(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPST_PORT_REPLY:
+    case OFPTYPE_PORT_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_ofpst_port_reply(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPST_TABLE_REPLY:
+    case OFPTYPE_TABLE_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_ofpst_table_reply(string, oh, verbosity);
         break;
 
-    case OFPUTIL_OFPST_AGGREGATE_REPLY:
+    case OFPTYPE_AGGREGATE_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
-        ofp_print_ofpst_aggregate_reply(string, msg);
+        ofp_print_aggregate_stats_reply(string, oh);
         break;
 
-    case OFPUTIL_OFPST_PORT_DESC_REPLY:
+    case OFPTYPE_PORT_DESC_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_ofpst_port_desc_reply(string, oh);
         break;
 
-    case OFPUTIL_NXT_ROLE_REQUEST:
-    case OFPUTIL_NXT_ROLE_REPLY:
-        ofp_print_nxt_role_message(string, msg);
+    case OFPTYPE_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REPLY:
+        ofp_print_nxt_role_message(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
-        ofp_print_nxt_flow_mod_table_id(string, msg);
+    case OFPTYPE_FLOW_MOD_TABLE_ID:
+        ofp_print_nxt_flow_mod_table_id(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_SET_FLOW_FORMAT:
-        ofp_print_nxt_set_flow_format(string, msg);
+    case OFPTYPE_SET_FLOW_FORMAT:
+        ofp_print_nxt_set_flow_format(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
-        ofp_print_nxt_set_packet_in_format(string, msg);
+    case OFPTYPE_SET_PACKET_IN_FORMAT:
+        ofp_print_nxt_set_packet_in_format(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_FLOW_AGE:
+    case OFPTYPE_FLOW_AGE:
         break;
 
-    case OFPUTIL_NXT_SET_CONTROLLER_ID:
-        ofp_print_nxt_set_controller_id(string, msg);
+    case OFPTYPE_SET_CONTROLLER_ID:
+        ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_SET_ASYNC_CONFIG:
-        ofp_print_nxt_set_async_config(string, msg);
-        break;
-
-    case OFPUTIL_NXST_AGGREGATE_REPLY:
-        ofp_print_stats_reply(string, oh);
-        ofp_print_nxst_aggregate_reply(string, msg);
+    case OFPTYPE_SET_ASYNC_CONFIG:
+        ofp_print_nxt_set_async_config(string, ofpmsg_body(oh));
         break;
 
-    case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
+    case OFPTYPE_FLOW_MONITOR_CANCEL:
         ofp_print_nxt_flow_monitor_cancel(string, msg);
         break;
 
-    case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
-    case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
+    case OFPTYPE_FLOW_MONITOR_PAUSED:
+    case OFPTYPE_FLOW_MONITOR_RESUMED:
         break;
 
-    case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
+    case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
         ofp_print_nxst_flow_monitor_request(string, msg);
         break;
 
-    case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+    case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
         ofp_print_nxst_flow_monitor_reply(string, msg);
         break;
     }
@@ -1738,12 +1745,12 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
                       "(***only uses %"PRIu16" bytes out of %zu***)\n",
                       ntohs(oh->length), len);
     } else {
-        const struct ofputil_msg_type *type;
         enum ofperr error;
+        enum ofpraw raw;
 
-        error = ofputil_decode_msg_type(oh, &type);
+        error = ofpraw_decode(&raw, oh);
         if (!error) {
-            ofp_to_string__(oh, type, &string, verbosity);
+            ofp_to_string__(oh, raw, &string, verbosity);
             if (verbosity >= 5) {
                 if (ds_last(&string) != '\n') {
                     ds_put_char(&string, '\n');
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index faa0687..fa6b2a8 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -34,6 +34,7 @@
 #include "nx-match.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "packets.h"
@@ -540,613 +541,6 @@ ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type)
             ? htons(FLOW_DL_TYPE_NONE)
             : ofp_dl_type);
 }
-
-/* Returns a transaction ID to use for an outgoing OpenFlow message. */
-static ovs_be32
-alloc_xid(void)
-{
-    static uint32_t next_xid = 1;
-    return htonl(next_xid++);
-}
-
-/* Basic parsing of OpenFlow messages. */
-
-struct ofputil_msg_type {
-    enum ofputil_msg_code code; /* OFPUTIL_*. */
-    uint8_t ofp_version;        /* An OpenFlow version or 0 for "any". */
-    uint32_t value;             /* OFPT_*, OFPST_*, NXT_*, or NXST_*. */
-    const char *name;           /* e.g. "OFPT_FLOW_REMOVED". */
-    unsigned int min_size;      /* Minimum total message size in bytes. */
-    /* 0 if 'min_size' is the exact size that the message must be.  Otherwise,
-     * the message may exceed 'min_size' by an even multiple of this value. */
-    unsigned int extra_multiple;
-};
-
-/* Represents a malformed OpenFlow message. */
-static const struct ofputil_msg_type ofputil_invalid_type = {
-    OFPUTIL_MSG_INVALID, 0, 0, "OFPUTIL_MSG_INVALID", 0, 0
-};
-
-struct ofputil_msg_category {
-    const char *name;           /* e.g. "OpenFlow message" */
-    const struct ofputil_msg_type *types;
-    size_t n_types;
-    enum ofperr missing_error;  /* Error value for missing type. */
-};
-
-static enum ofperr
-ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size)
-{
-    switch (type->extra_multiple) {
-    case 0:
-        if (size != type->min_size) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
-                         "length %u (expected length %u)",
-                         type->name, size, type->min_size);
-            return OFPERR_OFPBRC_BAD_LEN;
-        }
-        return 0;
-
-    case 1:
-        if (size < type->min_size) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
-                         "length %u (expected length at least %u bytes)",
-                         type->name, size, type->min_size);
-            return OFPERR_OFPBRC_BAD_LEN;
-        }
-        return 0;
-
-    default:
-        if (size < type->min_size
-            || (size - type->min_size) % type->extra_multiple) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect "
-                         "length %u (must be exactly %u bytes or longer "
-                         "by an integer multiple of %u bytes)",
-                         type->name, size,
-                         type->min_size, type->extra_multiple);
-            return OFPERR_OFPBRC_BAD_LEN;
-        }
-        return 0;
-    }
-}
-
-static enum ofperr
-ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
-                                uint8_t version, uint32_t value,
-                                const struct ofputil_msg_type **typep)
-{
-    const struct ofputil_msg_type *type;
-
-    for (type = cat->types; type < &cat->types[cat->n_types]; type++) {
-        if (type->value == value
-            && (!type->ofp_version || version == type->ofp_version)) {
-            *typep = type;
-            return 0;
-        }
-    }
-
-    VLOG_WARN_RL(&bad_ofmsg_rl, "received %s of unknown type %"PRIu32,
-                 cat->name, value);
-    return cat->missing_error;
-}
-
-static enum ofperr
-ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
-                      const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type nxt_messages[] = {
-        { OFPUTIL_NXT_ROLE_REQUEST, OFP10_VERSION,
-          NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
-          sizeof(struct nx_role_request), 0 },
-
-        { OFPUTIL_NXT_ROLE_REPLY, OFP10_VERSION,
-          NXT_ROLE_REPLY, "NXT_ROLE_REPLY",
-          sizeof(struct nx_role_request), 0 },
-
-        { OFPUTIL_NXT_SET_FLOW_FORMAT, OFP10_VERSION,
-          NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
-          sizeof(struct nx_set_flow_format), 0 },
-
-        { OFPUTIL_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION,
-          NXT_SET_PACKET_IN_FORMAT, "NXT_SET_PACKET_IN_FORMAT",
-          sizeof(struct nx_set_packet_in_format), 0 },
-
-        { OFPUTIL_NXT_PACKET_IN, OFP10_VERSION,
-          NXT_PACKET_IN, "NXT_PACKET_IN",
-          sizeof(struct nx_packet_in), 1 },
-
-        { OFPUTIL_NXT_FLOW_MOD, OFP10_VERSION,
-          NXT_FLOW_MOD, "NXT_FLOW_MOD",
-          sizeof(struct nx_flow_mod), 8 },
-
-        { OFPUTIL_NXT_FLOW_REMOVED, OFP10_VERSION,
-          NXT_FLOW_REMOVED, "NXT_FLOW_REMOVED",
-          sizeof(struct nx_flow_removed), 8 },
-
-        { OFPUTIL_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION,
-          NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID",
-          sizeof(struct nx_flow_mod_table_id), 0 },
-
-        { OFPUTIL_NXT_FLOW_AGE, OFP10_VERSION,
-          NXT_FLOW_AGE, "NXT_FLOW_AGE",
-          sizeof(struct nicira_header), 0 },
-
-        { OFPUTIL_NXT_SET_ASYNC_CONFIG, OFP10_VERSION,
-          NXT_SET_ASYNC_CONFIG, "NXT_SET_ASYNC_CONFIG",
-          sizeof(struct nx_async_config), 0 },
-
-        { OFPUTIL_NXT_SET_CONTROLLER_ID, OFP10_VERSION,
-          NXT_SET_CONTROLLER_ID, "NXT_SET_CONTROLLER_ID",
-          sizeof(struct nx_controller_id), 0 },
-
-        { OFPUTIL_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION,
-          NXT_FLOW_MONITOR_CANCEL, "NXT_FLOW_MONITOR_CANCEL",
-          sizeof(struct nx_flow_monitor_cancel), 0 },
-
-        { OFPUTIL_NXT_FLOW_MONITOR_PAUSED, OFP10_VERSION,
-          NXT_FLOW_MONITOR_PAUSED, "NXT_FLOW_MONITOR_PAUSED",
-          sizeof(struct nicira_header), 0 },
-
-        { OFPUTIL_NXT_FLOW_MONITOR_RESUMED, OFP10_VERSION,
-          NXT_FLOW_MONITOR_RESUMED, "NXT_FLOW_MONITOR_RESUMED",
-          sizeof(struct nicira_header), 0 },
-    };
-
-    static const struct ofputil_msg_category nxt_category = {
-        "Nicira extension message",
-        nxt_messages, ARRAY_SIZE(nxt_messages),
-        OFPERR_OFPBRC_BAD_SUBTYPE
-    };
-
-    const struct ofp_vendor_header *ovh;
-    const struct nicira_header *nh;
-
-    if (length < sizeof(struct ofp_vendor_header)) {
-        if (length == ntohs(oh->length)) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor message");
-        }
-        return OFPERR_OFPBRC_BAD_LEN;
-    }
-
-    ovh = (const struct ofp_vendor_header *) oh;
-    if (ovh->vendor != htonl(NX_VENDOR_ID)) {
-        VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor message for unknown "
-                     "vendor %"PRIx32, ntohl(ovh->vendor));
-        return OFPERR_OFPBRC_BAD_VENDOR;
-    }
-
-    if (length < sizeof(struct nicira_header)) {
-        if (length == ntohs(oh->length)) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "received Nicira vendor message of "
-                         "length %u (expected at least %zu)",
-                         ntohs(ovh->header.length),
-                         sizeof(struct nicira_header));
-        }
-        return OFPERR_OFPBRC_BAD_LEN;
-    }
-
-    nh = (const struct nicira_header *) oh;
-    return ofputil_lookup_openflow_message(&nxt_category, oh->version,
-                                           ntohl(nh->subtype), typep);
-}
-
-static enum ofperr
-check_nxstats_msg(const struct ofp_header *oh, size_t length)
-{
-    const struct ofp_stats_msg *osm = (const struct ofp_stats_msg *) oh;
-    ovs_be32 vendor;
-
-    if (length < sizeof(struct ofp_vendor_stats_msg)) {
-        if (length == ntohs(oh->length)) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor stats message");
-        }
-        return OFPERR_OFPBRC_BAD_LEN;
-    }
-
-    memcpy(&vendor, osm + 1, sizeof vendor);
-    if (vendor != htonl(NX_VENDOR_ID)) {
-        VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor stats message for "
-                     "unknown vendor %"PRIx32, ntohl(vendor));
-        return OFPERR_OFPBRC_BAD_VENDOR;
-    }
-
-    if (length < sizeof(struct nicira_stats_msg)) {
-        if (length == ntohs(osm->header.length)) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message");
-        }
-        return OFPERR_OFPBRC_BAD_LEN;
-    }
-
-    return 0;
-}
-
-static enum ofperr
-ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length,
-                            const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type nxst_requests[] = {
-        { OFPUTIL_NXST_FLOW_REQUEST, OFP10_VERSION,
-          NXST_FLOW, "NXST_FLOW request",
-          sizeof(struct nx_flow_stats_request), 8 },
-
-        { OFPUTIL_NXST_AGGREGATE_REQUEST, OFP10_VERSION,
-          NXST_AGGREGATE, "NXST_AGGREGATE request",
-          sizeof(struct nx_aggregate_stats_request), 8 },
-
-        { OFPUTIL_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION,
-          NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR request",
-          sizeof(struct nicira_stats_msg), 8 },
-    };
-
-    static const struct ofputil_msg_category nxst_request_category = {
-        "Nicira extension statistics request",
-        nxst_requests, ARRAY_SIZE(nxst_requests),
-        OFPERR_OFPBRC_BAD_SUBTYPE
-    };
-
-    const struct nicira_stats_msg *nsm;
-    enum ofperr error;
-
-    error = check_nxstats_msg(oh, length);
-    if (error) {
-        return error;
-    }
-
-    nsm = (struct nicira_stats_msg *) oh;
-    return ofputil_lookup_openflow_message(&nxst_request_category, oh->version,
-                                           ntohl(nsm->subtype), typep);
-}
-
-static enum ofperr
-ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length,
-                          const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type nxst_replies[] = {
-        { OFPUTIL_NXST_FLOW_REPLY, OFP10_VERSION,
-          NXST_FLOW, "NXST_FLOW reply",
-          sizeof(struct nicira_stats_msg), 8 },
-
-        { OFPUTIL_NXST_AGGREGATE_REPLY, OFP10_VERSION,
-          NXST_AGGREGATE, "NXST_AGGREGATE reply",
-          sizeof(struct nx_aggregate_stats_reply), 0 },
-
-        { OFPUTIL_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
-          NXST_FLOW_MONITOR, "NXST_FLOW_MONITOR reply",
-          sizeof(struct nicira_stats_msg), 8 },
-    };
-
-    static const struct ofputil_msg_category nxst_reply_category = {
-        "Nicira extension statistics reply",
-        nxst_replies, ARRAY_SIZE(nxst_replies),
-        OFPERR_OFPBRC_BAD_SUBTYPE
-    };
-
-    const struct nicira_stats_msg *nsm;
-    enum ofperr error;
-
-    error = check_nxstats_msg(oh, length);
-    if (error) {
-        return error;
-    }
-
-    nsm = (struct nicira_stats_msg *) oh;
-    return ofputil_lookup_openflow_message(&nxst_reply_category, oh->version,
-                                           ntohl(nsm->subtype), typep);
-}
-
-static enum ofperr
-check_stats_msg(const struct ofp_header *oh, size_t length)
-{
-    if (length < sizeof(struct ofp_stats_msg)) {
-        if (length == ntohs(oh->length)) {
-            VLOG_WARN_RL(&bad_ofmsg_rl, "truncated stats message");
-        }
-        return OFPERR_OFPBRC_BAD_LEN;
-    }
-
-    return 0;
-}
-
-static enum ofperr
-ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length,
-                             const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type ofpst_requests[] = {
-        { OFPUTIL_OFPST_DESC_REQUEST, OFP10_VERSION,
-          OFPST_DESC, "OFPST_DESC request",
-          sizeof(struct ofp_stats_msg), 0 },
-
-        { OFPUTIL_OFPST_FLOW_REQUEST, OFP10_VERSION,
-          OFPST_FLOW, "OFPST_FLOW request",
-          sizeof(struct ofp_flow_stats_request), 0 },
-
-        { OFPUTIL_OFPST_AGGREGATE_REQUEST, OFP10_VERSION,
-          OFPST_AGGREGATE, "OFPST_AGGREGATE request",
-          sizeof(struct ofp_flow_stats_request), 0 },
-
-        { OFPUTIL_OFPST_TABLE_REQUEST, OFP10_VERSION,
-          OFPST_TABLE, "OFPST_TABLE request",
-          sizeof(struct ofp_stats_msg), 0 },
-
-        { OFPUTIL_OFPST_PORT_REQUEST, OFP10_VERSION,
-          OFPST_PORT, "OFPST_PORT request",
-          sizeof(struct ofp_port_stats_request), 0 },
-
-        { OFPUTIL_OFPST_QUEUE_REQUEST, OFP10_VERSION,
-          OFPST_QUEUE, "OFPST_QUEUE request",
-          sizeof(struct ofp_queue_stats_request), 0 },
-
-        { OFPUTIL_OFPST_PORT_DESC_REQUEST, OFP10_VERSION,
-          OFPST_PORT_DESC, "OFPST_PORT_DESC request",
-          sizeof(struct ofp_stats_msg), 0 },
-
-        { 0, 0,
-          OFPST_VENDOR, "OFPST_VENDOR request",
-          sizeof(struct ofp_vendor_stats_msg), 1 },
-    };
-
-    static const struct ofputil_msg_category ofpst_request_category = {
-        "OpenFlow statistics",
-        ofpst_requests, ARRAY_SIZE(ofpst_requests),
-        OFPERR_OFPBRC_BAD_STAT
-    };
-
-    const struct ofp_stats_msg *request = (const struct ofp_stats_msg *) oh;
-    enum ofperr error;
-
-    error = check_stats_msg(oh, length);
-    if (error) {
-        return error;
-    }
-
-    error = ofputil_lookup_openflow_message(&ofpst_request_category,
-                                            oh->version, ntohs(request->type),
-                                            typep);
-    if (!error && request->type == htons(OFPST_VENDOR)) {
-        error = ofputil_decode_nxst_request(oh, length, typep);
-    }
-    return error;
-}
-
-static enum ofperr
-ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length,
-                           const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type ofpst_replies[] = {
-        { OFPUTIL_OFPST_DESC_REPLY, OFP10_VERSION,
-          OFPST_DESC, "OFPST_DESC reply",
-          sizeof(struct ofp_desc_stats), 0 },
-
-        { OFPUTIL_OFPST_FLOW_REPLY, OFP10_VERSION,
-          OFPST_FLOW, "OFPST_FLOW reply",
-          sizeof(struct ofp_stats_msg), 1 },
-
-        { OFPUTIL_OFPST_AGGREGATE_REPLY, OFP10_VERSION,
-          OFPST_AGGREGATE, "OFPST_AGGREGATE reply",
-          sizeof(struct ofp_aggregate_stats_reply), 0 },
-
-        { OFPUTIL_OFPST_TABLE_REPLY, OFP10_VERSION,
-          OFPST_TABLE, "OFPST_TABLE reply",
-          sizeof(struct ofp_stats_msg), sizeof(struct ofp_table_stats) },
-
-        { OFPUTIL_OFPST_PORT_REPLY, OFP10_VERSION,
-          OFPST_PORT, "OFPST_PORT reply",
-          sizeof(struct ofp_stats_msg), sizeof(struct ofp_port_stats) },
-
-        { OFPUTIL_OFPST_QUEUE_REPLY, OFP10_VERSION,
-          OFPST_QUEUE, "OFPST_QUEUE reply",
-          sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) },
-
-        { OFPUTIL_OFPST_PORT_DESC_REPLY, OFP10_VERSION,
-          OFPST_PORT_DESC, "OFPST_PORT_DESC reply",
-          sizeof(struct ofp_stats_msg), sizeof(struct ofp10_phy_port) },
-
-        { 0, 0,
-          OFPST_VENDOR, "OFPST_VENDOR reply",
-          sizeof(struct ofp_vendor_stats_msg), 1 },
-    };
-
-    static const struct ofputil_msg_category ofpst_reply_category = {
-        "OpenFlow statistics",
-        ofpst_replies, ARRAY_SIZE(ofpst_replies),
-        OFPERR_OFPBRC_BAD_STAT
-    };
-
-    const struct ofp_stats_msg *reply = (const struct ofp_stats_msg *) oh;
-    enum ofperr error;
-
-    error = check_stats_msg(oh, length);
-    if (error) {
-        return error;
-    }
-
-    error = ofputil_lookup_openflow_message(&ofpst_reply_category, oh->version,
-                                           ntohs(reply->type), typep);
-    if (!error && reply->type == htons(OFPST_VENDOR)) {
-        error = ofputil_decode_nxst_reply(oh, length, typep);
-    }
-    return error;
-}
-
-static enum ofperr
-ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
-                          const struct ofputil_msg_type **typep)
-{
-    static const struct ofputil_msg_type ofpt_messages[] = {
-        { OFPUTIL_OFPT_HELLO, OFP10_VERSION,
-          OFPT_HELLO, "OFPT_HELLO",
-          sizeof(struct ofp_hello), 1 },
-
-        { OFPUTIL_OFPT_ERROR, 0,
-          OFPT_ERROR, "OFPT_ERROR",
-          sizeof(struct ofp_error_msg), 1 },
-
-        { OFPUTIL_OFPT_ECHO_REQUEST, OFP10_VERSION,
-          OFPT_ECHO_REQUEST, "OFPT_ECHO_REQUEST",
-          sizeof(struct ofp_header), 1 },
-
-        { OFPUTIL_OFPT_ECHO_REPLY, OFP10_VERSION,
-          OFPT_ECHO_REPLY, "OFPT_ECHO_REPLY",
-          sizeof(struct ofp_header), 1 },
-
-        { OFPUTIL_OFPT_FEATURES_REQUEST, OFP10_VERSION,
-          OFPT_FEATURES_REQUEST, "OFPT_FEATURES_REQUEST",
-          sizeof(struct ofp_header), 0 },
-
-        { OFPUTIL_OFPT_FEATURES_REPLY, OFP10_VERSION,
-          OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
-          sizeof(struct ofp_switch_features), sizeof(struct ofp10_phy_port) },
-        { OFPUTIL_OFPT_FEATURES_REPLY, OFP11_VERSION,
-          OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
-          sizeof(struct ofp_switch_features), sizeof(struct ofp11_port) },
-
-        { OFPUTIL_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION,
-          OFPT_GET_CONFIG_REQUEST, "OFPT_GET_CONFIG_REQUEST",
-          sizeof(struct ofp_header), 0 },
-
-        { OFPUTIL_OFPT_GET_CONFIG_REPLY, OFP10_VERSION,
-          OFPT_GET_CONFIG_REPLY, "OFPT_GET_CONFIG_REPLY",
-          sizeof(struct ofp_switch_config), 0 },
-
-        { OFPUTIL_OFPT_SET_CONFIG, OFP10_VERSION,
-          OFPT_SET_CONFIG, "OFPT_SET_CONFIG",
-          sizeof(struct ofp_switch_config), 0 },
-
-        { OFPUTIL_OFPT_PACKET_IN, OFP10_VERSION,
-          OFPT_PACKET_IN, "OFPT_PACKET_IN",
-          offsetof(struct ofp_packet_in, data), 1 },
-
-        { OFPUTIL_OFPT_FLOW_REMOVED, OFP10_VERSION,
-          OFPT_FLOW_REMOVED, "OFPT_FLOW_REMOVED",
-          sizeof(struct ofp_flow_removed), 0 },
-
-        { OFPUTIL_OFPT_PORT_STATUS, OFP10_VERSION,
-          OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
-          sizeof(struct ofp_port_status) + sizeof(struct ofp10_phy_port), 0 },
-        { OFPUTIL_OFPT_PORT_STATUS, OFP11_VERSION,
-          OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
-          sizeof(struct ofp_port_status) + sizeof(struct ofp11_port), 0 },
-
-        { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
-          OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
-          sizeof(struct ofp_packet_out), 1 },
-
-        { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION,
-          OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
-          sizeof(struct ofp_flow_mod), 1 },
-
-        { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
-          OFPT10_PORT_MOD, "OFPT_PORT_MOD",
-          sizeof(struct ofp10_port_mod), 0 },
-        { OFPUTIL_OFPT_PORT_MOD, OFP11_VERSION,
-          OFPT11_PORT_MOD, "OFPT_PORT_MOD",
-          sizeof(struct ofp11_port_mod), 0 },
-
-        { 0, OFP10_VERSION,
-          OFPT10_STATS_REQUEST, "OFPT_STATS_REQUEST",
-          sizeof(struct ofp_stats_msg), 1 },
-
-        { 0, OFP10_VERSION,
-          OFPT10_STATS_REPLY, "OFPT_STATS_REPLY",
-          sizeof(struct ofp_stats_msg), 1 },
-
-        { OFPUTIL_OFPT_BARRIER_REQUEST, OFP10_VERSION,
-          OFPT10_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
-          sizeof(struct ofp_header), 0 },
-
-        { OFPUTIL_OFPT_BARRIER_REPLY, OFP10_VERSION,
-          OFPT10_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
-          sizeof(struct ofp_header), 0 },
-
-        { 0, 0,
-          OFPT_VENDOR, "OFPT_VENDOR",
-          sizeof(struct ofp_vendor_header), 1 },
-    };
-
-    static const struct ofputil_msg_category ofpt_category = {
-        "OpenFlow message",
-        ofpt_messages, ARRAY_SIZE(ofpt_messages),
-        OFPERR_OFPBRC_BAD_TYPE
-    };
-
-    enum ofperr error;
-
-    error = ofputil_lookup_openflow_message(&ofpt_category, oh->version,
-                                            oh->type, typep);
-    if (!error) {
-        switch ((oh->version << 8) | oh->type) {
-        case (OFP10_VERSION << 8) | OFPT_VENDOR:
-        case (OFP11_VERSION << 8) | OFPT_VENDOR:
-            error = ofputil_decode_vendor(oh, length, typep);
-            break;
-
-        case (OFP10_VERSION << 8) | OFPT10_STATS_REQUEST:
-        case (OFP11_VERSION << 8) | OFPT11_STATS_REQUEST:
-            error = ofputil_decode_ofpst_request(oh, length, typep);
-            break;
-
-        case (OFP10_VERSION << 8) | OFPT10_STATS_REPLY:
-        case (OFP11_VERSION << 8) | OFPT11_STATS_REPLY:
-            error = ofputil_decode_ofpst_reply(oh, length, typep);
-
-        default:
-            break;
-        }
-    }
-    return error;
-}
-
-/* Decodes the message type represented by 'oh'.  Returns 0 if successful or an
- * OpenFlow error code on failure.  Either way, stores in '*typep' a type
- * structure that can be inspected with the ofputil_msg_type_*() functions.
- *
- * oh->length must indicate the correct length of the message (and must be at
- * least sizeof(struct ofp_header)).
- *
- * Success indicates that 'oh' is at least as long as the minimum-length
- * message of its type. */
-enum ofperr
-ofputil_decode_msg_type(const struct ofp_header *oh,
-                        const struct ofputil_msg_type **typep)
-{
-    size_t length = ntohs(oh->length);
-    enum ofperr error;
-
-    error = ofputil_decode_msg_type__(oh, length, typep);
-    if (!error) {
-        error = ofputil_check_length(*typep, length);
-    }
-    if (error) {
-        *typep = &ofputil_invalid_type;
-    }
-    return error;
-}
-
-/* Decodes the message type represented by 'oh', of which only the first
- * 'length' bytes are available.  Returns 0 if successful or an OpenFlow error
- * code on failure.  Either way, stores in '*typep' a type structure that can
- * be inspected with the ofputil_msg_type_*() functions.  */
-enum ofperr
-ofputil_decode_msg_type_partial(const struct ofp_header *oh, size_t length,
-                                const struct ofputil_msg_type **typep)
-{
-    enum ofperr error;
-
-    error = (length >= sizeof *oh
-             ? ofputil_decode_msg_type__(oh, length, typep)
-             : OFPERR_OFPBRC_BAD_LEN);
-    if (error) {
-        *typep = &ofputil_invalid_type;
-    }
-    return error;
-}
-
-/* Returns an OFPUTIL_* message type code for 'type'. */
-enum ofputil_msg_code
-ofputil_msg_type_code(const struct ofputil_msg_type *type)
-{
-    return type->code;
-}
 
 /* Protocols. */
 
@@ -1593,7 +987,8 @@ ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff)
 
     assert(ofputil_nx_flow_format_is_valid(nxff));
 
-    sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
+    msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0);
+    sff = ofpbuf_put_zeros(msg, sizeof *sff);
     sff->format = htonl(nxff);
 
     return msg;
@@ -1644,7 +1039,8 @@ ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format)
     struct nx_set_packet_in_format *spif;
     struct ofpbuf *msg;
 
-    spif = make_nxmsg(sizeof *spif, NXT_SET_PACKET_IN_FORMAT, &msg);
+    msg = ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION, 0);
+    spif = ofpbuf_put_zeros(msg, sizeof *spif);
     spif->format = htonl(packet_in_format);
 
     return msg;
@@ -1658,7 +1054,8 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
     struct nx_flow_mod_table_id *nfmti;
     struct ofpbuf *msg;
 
-    nfmti = make_nxmsg(sizeof *nfmti, NXT_FLOW_MOD_TABLE_ID, &msg);
+    msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD_TABLE_ID, OFP10_VERSION, 0);
+    nfmti = ofpbuf_put_zeros(msg, sizeof *nfmti);
     nfmti->set = flow_mod_table_id;
     return msg;
 }
@@ -1679,15 +1076,14 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
                         enum ofputil_protocol protocol,
                         struct ofpbuf *ofpacts)
 {
-    const struct ofputil_msg_type *type;
     uint16_t command;
     struct ofpbuf b;
+    enum ofpraw raw;
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
-    ofputil_decode_msg_type(oh, &type);
-    if (ofputil_msg_type_code(type) == OFPUTIL_OFPT_FLOW_MOD) {
-        /* Standard OpenFlow flow_mod. */
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+        /* Standard OpenFlow 1.1 flow_mod. */
         const struct ofp_flow_mod *ofm;
         uint16_t priority;
         enum ofperr error;
@@ -1724,7 +1120,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         fm->buffer_id = ntohl(ofm->buffer_id);
         fm->out_port = ntohs(ofm->out_port);
         fm->flags = ntohs(ofm->flags);
-    } else if (ofputil_msg_type_code(type) == OFPUTIL_NXT_FLOW_MOD) {
+    } else if (raw == OFPRAW_NXT_FLOW_MOD) {
         /* Nicira extended flow_mod. */
         const struct nx_flow_mod *nfm;
         enum ofperr error;
@@ -1790,8 +1186,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     switch (protocol) {
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID:
-        msg = ofpbuf_new(sizeof *ofm + fm->ofpacts_len);
-        ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
+        msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
+                           fm->ofpacts_len);
+        ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
         ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match);
         ofm->cookie = fm->new_cookie;
         ofm->command = htons(command);
@@ -1805,14 +1202,14 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
 
     case OFPUTIL_P_NXM:
     case OFPUTIL_P_NXM_TID:
-        msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + fm->ofpacts_len);
-        put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
-        nfm = msg->data;
+        msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
+                           NXM_TYPICAL_LEN + fm->ofpacts_len);
+        nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
         nfm->command = htons(command);
         nfm->cookie = fm->new_cookie;
         match_len = nx_put_match(msg, false, &fm->cr,
                                  fm->cookie, fm->cookie_mask);
-        nfm = msg->data;
+        nfm = msg->l3;
         nfm->idle_timeout = htons(fm->idle_timeout);
         nfm->hard_timeout = htons(fm->hard_timeout);
         nfm->priority = htons(fm->cr.priority);
@@ -1829,7 +1226,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     if (fm->ofpacts) {
         ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
     }
-    update_openflow_length(msg);
+    ofpmsg_update_length(msg);
     return msg;
 }
 
@@ -1866,12 +1263,9 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
 
 static enum ofperr
 ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
-                                  const struct ofp_header *oh,
+                                  const struct ofp_flow_stats_request *ofsr,
                                   bool aggregate)
 {
-    const struct ofp_flow_stats_request *ofsr =
-        (const struct ofp_flow_stats_request *) oh;
-
     fsr->aggregate = aggregate;
     ofputil_cls_rule_from_ofp10_match(&ofsr->match, 0, &fsr->match);
     fsr->out_port = ntohs(ofsr->out_port);
@@ -1883,22 +1277,18 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
 
 static enum ofperr
 ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
-                                 const struct ofp_header *oh,
-                                 bool aggregate)
+                                 struct ofpbuf *b, bool aggregate)
 {
     const struct nx_flow_stats_request *nfsr;
-    struct ofpbuf b;
     enum ofperr error;
 
-    ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
-    nfsr = ofpbuf_pull(&b, sizeof *nfsr);
-    error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match,
+    nfsr = ofpbuf_pull(b, sizeof *nfsr);
+    error = nx_pull_match(b, ntohs(nfsr->match_len), 0, &fsr->match,
                           &fsr->cookie, &fsr->cookie_mask);
     if (error) {
         return error;
     }
-    if (b.size) {
+    if (b->size) {
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -1916,26 +1306,23 @@ enum ofperr
 ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
                                   const struct ofp_header *oh)
 {
-    const struct ofputil_msg_type *type;
+    enum ofpraw raw;
     struct ofpbuf b;
-    int code;
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+    switch ((int) raw) {
+    case OFPRAW_OFPST_FLOW_REQUEST:
+        return ofputil_decode_ofpst_flow_request(fsr, b.data, false);
 
-    ofputil_decode_msg_type(oh, &type);
-    code = ofputil_msg_type_code(type);
-    switch (code) {
-    case OFPUTIL_OFPST_FLOW_REQUEST:
-        return ofputil_decode_ofpst_flow_request(fsr, oh, false);
-
-    case OFPUTIL_OFPST_AGGREGATE_REQUEST:
-        return ofputil_decode_ofpst_flow_request(fsr, oh, true);
+    case OFPRAW_OFPST_AGGREGATE_REQUEST:
+        return ofputil_decode_ofpst_flow_request(fsr, b.data, true);
 
-    case OFPUTIL_NXST_FLOW_REQUEST:
-        return ofputil_decode_nxst_flow_request(fsr, oh, false);
+    case OFPRAW_NXST_FLOW_REQUEST:
+        return ofputil_decode_nxst_flow_request(fsr, &b, false);
 
-    case OFPUTIL_NXST_AGGREGATE_REQUEST:
-        return ofputil_decode_nxst_flow_request(fsr, oh, true);
+    case OFPRAW_NXST_AGGREGATE_REQUEST:
+        return ofputil_decode_nxst_flow_request(fsr, &b, true);
 
     default:
         /* Hey, the caller lied. */
@@ -1951,15 +1338,18 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
                                   enum ofputil_protocol protocol)
 {
     struct ofpbuf *msg;
+    enum ofpraw raw;
 
     switch (protocol) {
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID: {
         struct ofp_flow_stats_request *ofsr;
-        int type;
 
-        type = fsr->aggregate ? OFPST_AGGREGATE : OFPST_FLOW;
-        ofsr = ofputil_make_stats_request(sizeof *ofsr, type, 0, &msg);
+        raw = (fsr->aggregate
+               ? OFPRAW_OFPST_AGGREGATE_REQUEST
+               : OFPRAW_OFPST_FLOW_REQUEST);
+        msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+        ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
         ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match);
         ofsr->table_id = fsr->table_id;
         ofsr->out_port = htons(fsr->out_port);
@@ -1970,14 +1360,16 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     case OFPUTIL_P_NXM_TID: {
         struct nx_flow_stats_request *nfsr;
         int match_len;
-        int subtype;
 
-        subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
-        ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
+        raw = (fsr->aggregate
+               ? OFPRAW_NXST_AGGREGATE_REQUEST
+               : OFPRAW_NXST_FLOW_REQUEST);
+        msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+        ofpbuf_put_zeros(msg, sizeof *nfsr);
         match_len = nx_put_match(msg, false, &fsr->match,
                                  fsr->cookie, fsr->cookie_mask);
 
-        nfsr = msg->data;
+        nfsr = msg->l3;
         nfsr->out_port = htons(fsr->out_port);
         nfsr->match_len = htons(match_len);
         nfsr->table_id = fsr->table_id;
@@ -2034,25 +1426,19 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
                                 bool flow_age_extension,
                                 struct ofpbuf *ofpacts)
 {
-    const struct ofputil_msg_type *type;
-    int code;
+    enum ofperr error;
+    enum ofpraw raw;
 
-    ofputil_decode_msg_type(msg->l2 ? msg->l2 : msg->data, &type);
-    code = ofputil_msg_type_code(type);
-    if (!msg->l2) {
-        msg->l2 = msg->data;
-        if (code == OFPUTIL_OFPST_FLOW_REPLY) {
-            ofpbuf_pull(msg, sizeof(struct ofp_stats_msg));
-        } else if (code == OFPUTIL_NXST_FLOW_REPLY) {
-            ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
-        } else {
-            NOT_REACHED();
-        }
+    error = (msg->l2
+             ? ofpraw_decode(&raw, msg->l2)
+             : ofpraw_pull(&raw, msg));
+    if (error) {
+        return error;
     }
 
     if (!msg->size) {
         return EOF;
-    } else if (code == OFPUTIL_OFPST_FLOW_REPLY) {
+    } else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
         const struct ofp_flow_stats *ofs;
         size_t length;
 
@@ -2086,7 +1472,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         fs->hard_age = -1;
         fs->packet_count = ntohll(get_32aligned_be64(&ofs->packet_count));
         fs->byte_count = ntohll(get_32aligned_be64(&ofs->byte_count));
-    } else if (code == OFPUTIL_NXST_FLOW_REPLY) {
+    } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
         const struct nx_flow_stats *nfs;
         size_t match_len, actions_len, length;
 
@@ -2160,10 +1546,11 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                                 struct list *replies)
 {
     struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
-    const struct ofp_stats_msg *osm = reply->data;
     size_t start_ofs = reply->size;
+    enum ofpraw raw;
 
-    if (osm->type == htons(OFPST_FLOW)) {
+    ofpraw_decode_partial(&raw, reply->data, reply->size);
+    if (raw == OFPRAW_OFPST_FLOW_REPLY) {
         struct ofp_flow_stats *ofs;
 
         ofpbuf_put_uninit(reply, sizeof *ofs);
@@ -2185,7 +1572,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                            htonll(unknown_to_zero(fs->packet_count)));
         put_32aligned_be64(&ofs->byte_count,
                            htonll(unknown_to_zero(fs->byte_count)));
-    } else if (osm->type == htons(OFPST_VENDOR)) {
+    } else if (raw == OFPRAW_NXST_FLOW_REPLY) {
         struct nx_flow_stats *nfs;
         int match_len;
 
@@ -2216,7 +1603,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         NOT_REACHED();
     }
 
-    ofputil_postappend_stats_reply(start_ofs, replies);
+    ofpmp_postappend(replies, start_ofs);
 }
 
 /* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
@@ -2224,24 +1611,27 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
 struct ofpbuf *
 ofputil_encode_aggregate_stats_reply(
     const struct ofputil_aggregate_stats *stats,
-    const struct ofp_stats_msg *request)
+    const struct ofp_header *request)
 {
     struct ofpbuf *msg;
+    enum ofpraw raw;
 
-    if (request->type == htons(OFPST_AGGREGATE)) {
+    ofpraw_decode(&raw, request);
+    if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) {
         struct ofp_aggregate_stats_reply *asr;
 
-        asr = ofputil_make_stats_reply(sizeof *asr, request, &msg);
+        msg = ofpraw_alloc_reply(OFPRAW_OFPST_AGGREGATE_REPLY, request, 0);
+        asr = ofpbuf_put_zeros(msg, sizeof *asr);
         put_32aligned_be64(&asr->packet_count,
                            htonll(unknown_to_zero(stats->packet_count)));
         put_32aligned_be64(&asr->byte_count,
                            htonll(unknown_to_zero(stats->byte_count)));
         asr->flow_count = htonl(stats->flow_count);
-    } else if (request->type == htons(OFPST_VENDOR)) {
+    } else if (raw == OFPRAW_NXST_AGGREGATE_REQUEST) {
         struct nx_aggregate_stats_reply *nasr;
 
-        nasr = ofputil_make_stats_reply(sizeof *nasr, request, &msg);
-        assert(nasr->nsm.subtype == htonl(NXST_AGGREGATE));
+        msg = ofpraw_alloc_reply(OFPRAW_NXST_AGGREGATE_REPLY, request, 0);
+        nasr = ofpbuf_put_zeros(msg, sizeof *nasr);
         nasr->packet_count = htonll(stats->packet_count);
         nasr->byte_count = htonll(stats->byte_count);
         nasr->flow_count = htonl(stats->flow_count);
@@ -2252,6 +1642,34 @@ ofputil_encode_aggregate_stats_reply(
     return msg;
 }
 
+enum ofperr
+ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats,
+                                     const struct ofp_header *reply)
+{
+    struct ofpbuf msg;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(&msg, reply, ntohs(reply->length));
+    raw = ofpraw_pull_assert(&msg);
+    if (raw == OFPRAW_OFPST_AGGREGATE_REPLY) {
+        struct ofp_aggregate_stats_reply *asr = msg.l3;
+
+        stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
+        stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
+        stats->flow_count = ntohl(asr->flow_count);
+    } else if (raw == OFPRAW_NXST_AGGREGATE_REPLY) {
+        struct nx_aggregate_stats_reply *nasr = msg.l3;
+
+        stats->packet_count = ntohll(nasr->packet_count);
+        stats->byte_count = ntohll(nasr->byte_count);
+        stats->flow_count = ntohl(nasr->flow_count);
+    } else {
+        NOT_REACHED();
+    }
+
+    return 0;
+}
+
 /* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh' into an
  * abstract ofputil_flow_removed in 'fr'.  Returns 0 if successful, otherwise
  * an OpenFlow error code. */
@@ -2259,15 +1677,16 @@ enum ofperr
 ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
                             const struct ofp_header *oh)
 {
-    const struct ofputil_msg_type *type;
-    enum ofputil_msg_code code;
+    enum ofpraw raw;
+    struct ofpbuf b;
 
-    ofputil_decode_msg_type(oh, &type);
-    code = ofputil_msg_type_code(type);
-    if (code == OFPUTIL_OFPT_FLOW_REMOVED) {
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
         const struct ofp_flow_removed *ofr;
 
-        ofr = (const struct ofp_flow_removed *) oh;
+        ofr = ofpbuf_pull(&b, sizeof *ofr);
+
         ofputil_cls_rule_from_ofp10_match(&ofr->match, ntohs(ofr->priority),
                                           &fr->rule);
         fr->cookie = ofr->cookie;
@@ -2277,13 +1696,10 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->idle_timeout = ntohs(ofr->idle_timeout);
         fr->packet_count = ntohll(ofr->packet_count);
         fr->byte_count = ntohll(ofr->byte_count);
-    } else if (code == OFPUTIL_NXT_FLOW_REMOVED) {
+    } else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
         struct nx_flow_removed *nfr;
-        struct ofpbuf b;
         int error;
 
-        ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
         nfr = ofpbuf_pull(&b, sizeof *nfr);
         error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
                               &fr->rule, NULL, NULL);
@@ -2322,8 +1738,9 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     case OFPUTIL_P_OF10_TID: {
         struct ofp_flow_removed *ofr;
 
-        ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0),
-                                &msg);
+        msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
+                               htonl(0), 0);
+        ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
         ofputil_cls_rule_to_ofp10_match(&fr->rule, &ofr->match);
         ofr->cookie = fr->cookie;
         ofr->priority = htons(fr->rule.priority);
@@ -2341,10 +1758,12 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         struct nx_flow_removed *nfr;
         int match_len;
 
-        make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
+        msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_REMOVED, OFP10_VERSION,
+                               htonl(0), NXM_TYPICAL_LEN);
+        nfr = ofpbuf_put_zeros(msg, sizeof *nfr);
         match_len = nx_put_match(msg, false, &fr->rule, 0, 0);
 
-        nfr = msg->data;
+        nfr = msg->l3;
         nfr->cookie = fr->cookie;
         nfr->priority = htons(fr->rule.priority);
         nfr->reason = fr->reason;
@@ -2368,32 +1787,30 @@ enum ofperr
 ofputil_decode_packet_in(struct ofputil_packet_in *pin,
                          const struct ofp_header *oh)
 {
-    const struct ofputil_msg_type *type;
-    enum ofputil_msg_code code;
+    enum ofpraw raw;
+    struct ofpbuf b;
 
-    ofputil_decode_msg_type(oh, &type);
-    code = ofputil_msg_type_code(type);
     memset(pin, 0, sizeof *pin);
 
-    if (code == OFPUTIL_OFPT_PACKET_IN) {
-        const struct ofp_packet_in *opi = (const struct ofp_packet_in *) oh;
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT10_PACKET_IN) {
+        const struct ofp_packet_in *opi;
+
+        opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data));
 
         pin->packet = opi->data;
-        pin->packet_len = ntohs(opi->header.length)
-            - offsetof(struct ofp_packet_in, data);
+        pin->packet_len = b.size;
 
         pin->fmd.in_port = ntohs(opi->in_port);
         pin->reason = opi->reason;
         pin->buffer_id = ntohl(opi->buffer_id);
         pin->total_len = ntohs(opi->total_len);
-    } else if (code == OFPUTIL_NXT_PACKET_IN) {
+    } else if (raw == OFPRAW_NXT_PACKET_IN) {
         const struct nx_packet_in *npi;
         struct cls_rule rule;
-        struct ofpbuf b;
         int error;
 
-        ofpbuf_use_const(&b, oh, ntohs(oh->length));
-
         npi = ofpbuf_pull(&b, sizeof *npi);
         error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
                                     NULL);
@@ -2443,13 +1860,11 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
 
     /* Add OFPT_PACKET_IN. */
     if (packet_in_format == NXPIF_OPENFLOW10) {
-        size_t header_len = offsetof(struct ofp_packet_in, data);
         struct ofp_packet_in *opi;
 
-        packet = ofpbuf_new(send_len + header_len);
-        opi = ofpbuf_put_zeros(packet, header_len);
-        opi->header.version = OFP10_VERSION;
-        opi->header.type = OFPT_PACKET_IN;
+        packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
+                                  htonl(0), send_len);
+        opi = ofpbuf_put_zeros(packet, offsetof(struct ofp_packet_in, data));
         opi->total_len = htons(pin->total_len);
         opi->in_port = htons(pin->fmd.in_port);
         opi->reason = pin->reason;
@@ -2462,12 +1877,6 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
         size_t match_len;
         size_t i;
 
-        /* Estimate of required PACKET_IN length includes the NPI header, space
-         * for the match (2 times sizeof the metadata seems like enough), 2
-         * bytes for padding, and the packet length. */
-        packet = ofpbuf_new(sizeof *npi + sizeof(struct flow_metadata) * 2
-                            + 2 + send_len);
-
         cls_rule_init_catchall(&rule, 0);
         cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
                                    pin->fmd.tun_id_mask);
@@ -2482,17 +1891,16 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
 
         cls_rule_set_in_port(&rule, pin->fmd.in_port);
 
+        /* The final argument is just an estimate of the space required. */
+        packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
+                                  htonl(0), (sizeof(struct flow_metadata) * 2
+                                             + 2 + send_len));
         ofpbuf_put_zeros(packet, sizeof *npi);
         match_len = nx_put_match(packet, false, &rule, 0, 0);
         ofpbuf_put_zeros(packet, 2);
         ofpbuf_put(packet, pin->packet, send_len);
 
-        npi = packet->data;
-        npi->nxh.header.version = OFP10_VERSION;
-        npi->nxh.header.type = OFPT_VENDOR;
-        npi->nxh.vendor = htonl(NX_VENDOR_ID);
-        npi->nxh.subtype = htonl(NXT_PACKET_IN);
-
+        npi = packet->l3;
         npi->buffer_id = htonl(pin->buffer_id);
         npi->total_len = htons(pin->total_len);
         npi->reason = pin->reason;
@@ -2502,7 +1910,7 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
     } else {
         NOT_REACHED();
     }
-    update_openflow_length(packet);
+    ofpmsg_update_length(packet);
 
     return packet;
 }
@@ -2552,12 +1960,19 @@ ofputil_packet_in_reason_from_string(const char *s,
  * Returns 0 if successful, otherwise an OFPERR_* value. */
 enum ofperr
 ofputil_decode_packet_out(struct ofputil_packet_out *po,
-                          const struct ofp_packet_out *opo,
+                          const struct ofp_header *oh,
                           struct ofpbuf *ofpacts)
 {
+    const struct ofp_packet_out *opo;
     enum ofperr error;
+    enum ofpraw raw;
     struct ofpbuf b;
 
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+    assert(raw == OFPRAW_OFPT10_PACKET_OUT);
+
+    opo = ofpbuf_pull(&b, sizeof *opo);
     po->buffer_id = ntohl(opo->buffer_id);
     po->in_port = ntohs(opo->in_port);
     if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL
@@ -2567,9 +1982,6 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
         return OFPERR_NXBRC_BAD_IN_PORT;
     }
 
-    ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
-    ofpbuf_pull(&b, sizeof *opo);
-
     error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
     if (error) {
         return error;
@@ -2776,12 +2188,12 @@ ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
     if (ofp_version == OFP10_VERSION) {
         struct ofp10_phy_port *opp;
 
-        opp = ofputil_append_stats_reply(sizeof *opp, replies);
+        opp = ofpmp_append(replies, sizeof *opp);
         ofputil_encode_ofp10_phy_port(pp, opp);
     } else {
         struct ofp11_port *op;
 
-        op = ofputil_append_stats_reply(sizeof *op, replies);
+        op = ofpmp_append(replies, sizeof *op);
         ofputil_encode_ofp11_port(pp, op);
     }
 }
@@ -2868,29 +2280,33 @@ decode_action_bits(ovs_be32 of_actions,
  * ofputil_pull_phy_port().  Returns 0 if successful, otherwise an
  * OFPERR_* value.  */
 enum ofperr
-ofputil_decode_switch_features(const struct ofp_switch_features *osf,
+ofputil_decode_switch_features(const struct ofp_header *oh,
                                struct ofputil_switch_features *features,
                                struct ofpbuf *b)
 {
-    ofpbuf_use_const(b, osf, ntohs(osf->header.length));
-    ofpbuf_pull(b, sizeof *osf);
+    const struct ofp_switch_features *osf;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(b);
 
+    osf = ofpbuf_pull(b, sizeof *osf);
     features->datapath_id = ntohll(osf->datapath_id);
     features->n_buffers = ntohl(osf->n_buffers);
     features->n_tables = osf->n_tables;
 
     features->capabilities = ntohl(osf->capabilities) & OFPC_COMMON;
 
-    if (b->size % ofputil_get_phy_port_size(osf->header.version)) {
+    if (b->size % ofputil_get_phy_port_size(oh->version)) {
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
-    if (osf->header.version == OFP10_VERSION) {
+    if (raw == OFPRAW_OFPT10_FEATURES_REPLY) {
         if (osf->capabilities & htonl(OFPC10_STP)) {
             features->capabilities |= OFPUTIL_C_STP;
         }
         features->actions = decode_action_bits(osf->actions, of10_action_bits);
-    } else if (osf->header.version == OFP11_VERSION) {
+    } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY) {
         if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
             features->capabilities |= OFPUTIL_C_GROUP_STATS;
         }
@@ -2902,12 +2318,12 @@ ofputil_decode_switch_features(const struct ofp_switch_features *osf,
     return 0;
 }
 
-/* Returns true if the maximum number of ports are in 'osf'. */
+/* Returns true if the maximum number of ports are in 'oh'. */
 static bool
-max_ports_in_features(const struct ofp_switch_features *osf)
+max_ports_in_features(const struct ofp_header *oh)
 {
-    size_t pp_size = ofputil_get_phy_port_size(osf->header.version);
-    return ntohs(osf->header.length) + pp_size > UINT16_MAX;
+    size_t pp_size = ofputil_get_phy_port_size(oh->version);
+    return ntohs(oh->length) + pp_size > UINT16_MAX;
 }
 
 /* Given a buffer 'b' that contains a Features Reply message, checks if
@@ -2920,12 +2336,13 @@ max_ports_in_features(const struct ofp_switch_features *osf)
 bool
 ofputil_switch_features_ports_trunc(struct ofpbuf *b)
 {
-    struct ofp_switch_features *osf = b->data;
+    struct ofp_header *oh = b->data;
 
-    if (max_ports_in_features(osf)) {
+    if (max_ports_in_features(oh)) {
         /* Remove all the ports. */
-        b->size = sizeof(*osf);
-        update_openflow_length(b);
+        b->size = (sizeof(struct ofp_header)
+                   + sizeof(struct ofp_switch_features));
+        ofpmsg_update_length(b);
 
         return true;
     }
@@ -2958,15 +2375,20 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
 {
     struct ofp_switch_features *osf;
     struct ofpbuf *b;
-
-    osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, xid, &b);
-    osf->header.version = ofputil_protocol_to_ofp_version(protocol);
+    uint8_t version;
+
+    version = ofputil_protocol_to_ofp_version(protocol);
+    b = ofpraw_alloc_xid(version == OFP10_VERSION
+                         ? OFPRAW_OFPT10_FEATURES_REPLY
+                         : OFPRAW_OFPT11_FEATURES_REPLY,
+                         version, xid, 0);
+    osf = ofpbuf_put_zeros(b, sizeof *osf);
     osf->datapath_id = htonll(features->datapath_id);
     osf->n_buffers = htonl(features->n_buffers);
     osf->n_tables = features->n_tables;
 
     osf->capabilities = htonl(features->capabilities & OFPC_COMMON);
-    if (osf->header.version == OFP10_VERSION) {
+    if (version == OFP10_VERSION) {
         if (features->capabilities & OFPUTIL_C_STP) {
             osf->capabilities |= htonl(OFPC10_STP);
         }
@@ -2988,9 +2410,9 @@ void
 ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
                                  struct ofpbuf *b)
 {
-    const struct ofp_switch_features *osf = b->data;
+    const struct ofp_header *oh = b->data;
 
-    ofputil_put_phy_port(osf->header.version, pp, b);
+    ofputil_put_phy_port(oh->version, pp, b);
 }
 
 /* ofputil_port_status */
@@ -2998,12 +2420,17 @@ ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
 /* Decodes the OpenFlow "port status" message in '*ops' into an abstract form
  * in '*ps'.  Returns 0 if successful, otherwise an OFPERR_* value. */
 enum ofperr
-ofputil_decode_port_status(const struct ofp_port_status *ops,
+ofputil_decode_port_status(const struct ofp_header *oh,
                            struct ofputil_port_status *ps)
 {
+    const struct ofp_port_status *ops;
     struct ofpbuf b;
     int retval;
 
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+    ops = ofpbuf_pull(&b, sizeof *ops);
+
     if (ops->reason != OFPPR_ADD &&
         ops->reason != OFPPR_DELETE &&
         ops->reason != OFPPR_MODIFY) {
@@ -3011,9 +2438,7 @@ ofputil_decode_port_status(const struct ofp_port_status *ops,
     }
     ps->reason = ops->reason;
 
-    ofpbuf_use_const(&b, ops, ntohs(ops->header.length));
-    ofpbuf_pull(&b, sizeof *ops);
-    retval = ofputil_pull_phy_port(ops->header.version, &b, &ps->desc);
+    retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
     assert(retval != EOF);
     return retval;
 }
@@ -3027,13 +2452,17 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps,
 {
     struct ofp_port_status *ops;
     struct ofpbuf *b;
-
-    b = ofpbuf_new(sizeof *ops + sizeof(struct ofp11_port));
-    ops = put_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, htonl(0), b);
-    ops->header.version = ofputil_protocol_to_ofp_version(protocol);
+    uint8_t version;
+
+    version = ofputil_protocol_to_ofp_version(protocol);
+    b = ofpraw_alloc_xid(version == OFP10_VERSION
+                         ? OFPRAW_OFPT10_PORT_STATUS
+                         : OFPRAW_OFPT11_PORT_STATUS,
+                         version, htonl(0), 0);
+    ops = ofpbuf_put_zeros(b, sizeof *ops);
     ops->reason = ps->reason;
-    ofputil_put_phy_port(ops->header.version, &ps->desc, b);
-    update_openflow_length(b);
+    ofputil_put_phy_port(version, &ps->desc, b);
+    ofpmsg_update_length(b);
     return b;
 }
 
@@ -3045,26 +2474,24 @@ enum ofperr
 ofputil_decode_port_mod(const struct ofp_header *oh,
                         struct ofputil_port_mod *pm)
 {
-    if (oh->version == OFP10_VERSION) {
-        const struct ofp10_port_mod *opm = (const struct ofp10_port_mod *) oh;
+    enum ofpraw raw;
+    struct ofpbuf b;
 
-        if (oh->length != htons(sizeof *opm)) {
-            return OFPERR_OFPBRC_BAD_LEN;
-        }
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+
+    if (raw == OFPRAW_OFPT10_PORT_MOD) {
+        const struct ofp10_port_mod *opm = b.data;
 
         pm->port_no = ntohs(opm->port_no);
         memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
         pm->config = ntohl(opm->config) & OFPPC10_ALL;
         pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
         pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
-    } else if (oh->version == OFP11_VERSION) {
-        const struct ofp11_port_mod *opm = (const struct ofp11_port_mod *) oh;
+    } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
+        const struct ofp11_port_mod *opm = b.data;
         enum ofperr error;
 
-        if (oh->length != htons(sizeof *opm)) {
-            return OFPERR_OFPBRC_BAD_LEN;
-        }
-
         error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
         if (error) {
             return error;
@@ -3075,7 +2502,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
         pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
         pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
     } else {
-        return OFPERR_OFPBRC_BAD_VERSION;
+        return OFPERR_OFPBRC_BAD_TYPE;
     }
 
     pm->config &= pm->mask;
@@ -3095,7 +2522,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     if (ofp_version == OFP10_VERSION) {
         struct ofp10_port_mod *opm;
 
-        opm = make_openflow(sizeof *opm, OFPT10_PORT_MOD, &b);
+        b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
+        opm = ofpbuf_put_zeros(b, sizeof *opm);
         opm->port_no = htons(pm->port_no);
         memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
         opm->config = htonl(pm->config & OFPPC10_ALL);
@@ -3104,7 +2532,8 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     } else if (ofp_version == OFP11_VERSION) {
         struct ofp11_port_mod *opm;
 
-        opm = make_openflow(sizeof *opm, OFPT11_PORT_MOD, &b);
+        b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
+        opm = ofpbuf_put_zeros(b, sizeof *opm);
         opm->port_no = htonl(pm->port_no);
         memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
         opm->config = htonl(pm->config & OFPPC11_ALL);
@@ -3138,7 +2567,7 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
 
     if (!msg->l2) {
         msg->l2 = msg->data;
-        ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
+        ofpraw_pull_assert(msg);
     }
 
     if (!msg->size) {
@@ -3183,9 +2612,7 @@ ofputil_append_flow_monitor_request(
     int match_len;
 
     if (!msg->size) {
-        ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST,
-                                 htons(OFPST_VENDOR),
-                                 htonl(NXST_FLOW_MONITOR), msg);
+        ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg);
     }
 
     start_ofs = msg->size;
@@ -3225,7 +2652,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
 
     if (!msg->l2) {
         msg->l2 = msg->data;
-        ofpbuf_pull(msg, sizeof(struct nicira_stats_msg));
+        ofpraw_pull_assert(msg);
     }
 
     if (!msg->size) {
@@ -3308,7 +2735,9 @@ bad_len:
 uint32_t
 ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh)
 {
-    return ntohl(((const struct nx_flow_monitor_cancel *) oh)->id);
+    const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh);
+
+    return ntohl(cancel->id);
 }
 
 struct ofpbuf *
@@ -3317,7 +2746,8 @@ ofputil_encode_flow_monitor_cancel(uint32_t id)
     struct nx_flow_monitor_cancel *nfmc;
     struct ofpbuf *msg;
 
-    nfmc = make_nxmsg(sizeof *nfmc, NXT_FLOW_MONITOR_CANCEL, &msg);
+    msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, 0);
+    nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
     nfmc->id = htonl(id);
     return msg;
 }
@@ -3327,10 +2757,8 @@ ofputil_start_flow_update(struct list *replies)
 {
     struct ofpbuf *msg;
 
-    msg = ofpbuf_new(1024);
-    ofputil_put_stats_header(htonl(0), OFPT10_STATS_REPLY,
-                             htons(OFPST_VENDOR),
-                             htonl(NXST_FLOW_MONITOR), msg);
+    msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
+                           htonl(0), 1024);
 
     list_init(replies);
     list_push_back(replies, &msg->list_node);
@@ -3375,378 +2803,47 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
     nfuh->length = htons(msg->size - start_ofs);
     nfuh->event = htons(update->event);
 
-    ofputil_postappend_stats_reply(start_ofs, replies);
+    ofpmp_postappend(replies, start_ofs);
 }
 
 struct ofpbuf *
 ofputil_encode_packet_out(const struct ofputil_packet_out *po)
 {
     struct ofp_packet_out *opo;
+    size_t actions_ofs;
     struct ofpbuf *msg;
     size_t size;
 
-    size = sizeof *opo + po->ofpacts_len;
+    size = po->ofpacts_len;
     if (po->buffer_id == UINT32_MAX) {
         size += po->packet_len;
     }
 
-    msg = ofpbuf_new(size);
-    put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
+    msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
+    ofpbuf_put_zeros(msg, sizeof *opo);
+    actions_ofs = msg->size;
     ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
 
-    opo = msg->data;
+    opo = msg->l3;
     opo->buffer_id = htonl(po->buffer_id);
     opo->in_port = htons(po->in_port);
-    opo->actions_len = htons(msg->size - sizeof *opo);
+    opo->actions_len = htons(msg->size - actions_ofs);
 
     if (po->buffer_id == UINT32_MAX) {
         ofpbuf_put(msg, po->packet, po->packet_len);
     }
 
-    update_openflow_length(msg);
+    ofpmsg_update_length(msg);
 
     return msg;
 }
-
-/* Returns a string representing the message type of 'type'.  The string is the
- * enumeration constant for the type, e.g. "OFPT_HELLO".  For statistics
- * messages, the constant is followed by "request" or "reply",
- * e.g. "OFPST_AGGREGATE reply". */
-const char *
-ofputil_msg_type_name(const struct ofputil_msg_type *type)
-{
-    return type->name;
-}
 
-/* Allocates and stores in '*bufferp' a new ofpbuf with a size of
- * 'openflow_len', starting with an OpenFlow header with the given 'type' and
- * an arbitrary transaction id.  Allocated bytes beyond the header, if any, are
- * zeroed.
- *
- * The caller is responsible for freeing '*bufferp' when it is no longer
- * needed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp)
-{
-    *bufferp = ofpbuf_new(openflow_len);
-    return put_openflow_xid(openflow_len, type, alloc_xid(), *bufferp);
-}
-
-/* Similar to make_openflow() but creates a Nicira vendor extension message
- * with the specific 'subtype'.  'subtype' should be in host byte order. */
-void *
-make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **bufferp)
-{
-    return make_nxmsg_xid(openflow_len, subtype, alloc_xid(), bufferp);
-}
-
-/* Allocates and stores in '*bufferp' a new ofpbuf with a size of
- * 'openflow_len', starting with an OpenFlow header with the given 'type' and
- * transaction id 'xid'.  Allocated bytes beyond the header, if any, are
- * zeroed.
- *
- * The caller is responsible for freeing '*bufferp' when it is no longer
- * needed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-make_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
-                  struct ofpbuf **bufferp)
-{
-    *bufferp = ofpbuf_new(openflow_len);
-    return put_openflow_xid(openflow_len, type, xid, *bufferp);
-}
-
-/* Similar to make_openflow_xid() but creates a Nicira vendor extension message
- * with the specific 'subtype'.  'subtype' should be in host byte order. */
-void *
-make_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
-               struct ofpbuf **bufferp)
-{
-    *bufferp = ofpbuf_new(openflow_len);
-    return put_nxmsg_xid(openflow_len, subtype, xid, *bufferp);
-}
-
-/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header
- * with the given 'type' and an arbitrary transaction id.  Allocated bytes
- * beyond the header, if any, are zeroed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *buffer)
-{
-    return put_openflow_xid(openflow_len, type, alloc_xid(), buffer);
-}
-
-/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header
- * with the given 'type' and an transaction id 'xid'.  Allocated bytes beyond
- * the header, if any, are zeroed.
- *
- * The OpenFlow header length is initially set to 'openflow_len'; if the
- * message is later extended, the length should be updated with
- * update_openflow_length() before sending.
- *
- * Returns the header. */
-void *
-put_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
-                 struct ofpbuf *buffer)
-{
-    struct ofp_header *oh;
-
-    assert(openflow_len >= sizeof *oh);
-    assert(openflow_len <= UINT16_MAX);
-
-    oh = ofpbuf_put_uninit(buffer, openflow_len);
-    oh->version = OFP10_VERSION;
-    oh->type = type;
-    oh->length = htons(openflow_len);
-    oh->xid = xid;
-    memset(oh + 1, 0, openflow_len - sizeof *oh);
-    return oh;
-}
-
-/* Similar to put_openflow() but append a Nicira vendor extension message with
- * the specific 'subtype'.  'subtype' should be in host byte order. */
-void *
-put_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf *buffer)
-{
-    return put_nxmsg_xid(openflow_len, subtype, alloc_xid(), buffer);
-}
-
-/* Similar to put_openflow_xid() but append a Nicira vendor extension message
- * with the specific 'subtype'.  'subtype' should be in host byte order. */
-void *
-put_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
-              struct ofpbuf *buffer)
-{
-    struct nicira_header *nxh;
-
-    nxh = put_openflow_xid(openflow_len, OFPT_VENDOR, xid, buffer);
-    nxh->vendor = htonl(NX_VENDOR_ID);
-    nxh->subtype = htonl(subtype);
-    return nxh;
-}
-
-/* Updates the 'length' field of the OpenFlow message in 'buffer' to
- * 'buffer->size'. */
-void
-update_openflow_length(struct ofpbuf *buffer)
-{
-    struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
-    oh->length = htons(buffer->size);
-}
-
-void
-ofputil_put_stats_header(ovs_be32 xid, uint8_t ofp_type,
-                         ovs_be16 ofpst_type, ovs_be32 nxst_subtype,
-                         struct ofpbuf *msg)
-{
-    if (ofpst_type == htons(OFPST_VENDOR)) {
-        struct nicira_stats_msg *nsm;
-
-        nsm = put_openflow_xid(sizeof *nsm, ofp_type, xid, msg);
-        nsm->vsm.osm.type = ofpst_type;
-        nsm->vsm.vendor = htonl(NX_VENDOR_ID);
-        nsm->subtype = nxst_subtype;
-    } else {
-        struct ofp_stats_msg *osm;
-
-        osm = put_openflow_xid(sizeof *osm, ofp_type, xid, msg);
-        osm->type = ofpst_type;
-    }
-}
-
-/* Creates a statistics request message with total length 'openflow_len'
- * (including all headers) and the given 'ofpst_type', and stores the buffer
- * containing the new message in '*bufferp'.  If 'ofpst_type' is OFPST_VENDOR
- * then 'nxst_subtype' is used as the Nicira vendor extension statistics
- * subtype (otherwise 'nxst_subtype' is ignored).
- *
- * Initializes bytes following the headers to all-bits-zero.
- *
- * Returns the first byte of the new message. */
-void *
-ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type,
-                           uint32_t nxst_subtype, struct ofpbuf **bufferp)
-{
-    struct ofpbuf *msg;
-
-    msg = *bufferp = ofpbuf_new(openflow_len);
-    ofputil_put_stats_header(alloc_xid(), OFPT10_STATS_REQUEST,
-                             htons(ofpst_type), htonl(nxst_subtype), msg);
-    ofpbuf_padto(msg, openflow_len);
-
-    return msg->data;
-}
-
-static void
-put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg)
-{
-    ovs_be32 nxst_subtype;
-
-    assert(request->header.type == OFPT10_STATS_REQUEST ||
-           request->header.type == OFPT10_STATS_REPLY);
-
-    nxst_subtype = (request->type != htons(OFPST_VENDOR)
-                    ? htonl(0)
-                    : ((const struct nicira_stats_msg *) request)->subtype);
-    ofputil_put_stats_header(request->header.xid, OFPT10_STATS_REPLY,
-                             request->type, nxst_subtype, msg);
-}
-
-/* Creates a statistics reply message with total length 'openflow_len'
- * (including all headers) and the same type (either a standard OpenFlow
- * statistics type or a Nicira extension type and subtype) as 'request', and
- * stores the buffer containing the new message in '*bufferp'.
- *
- * Initializes bytes following the headers to all-bits-zero.
- *
- * Returns the first byte of the new message. */
-void *
-ofputil_make_stats_reply(size_t openflow_len,
-                         const struct ofp_stats_msg *request,
-                         struct ofpbuf **bufferp)
-{
-    struct ofpbuf *msg;
-
-    msg = *bufferp = ofpbuf_new(openflow_len);
-    put_stats_reply__(request, msg);
-    ofpbuf_padto(msg, openflow_len);
-
-    return msg->data;
-}
-
-/* Initializes 'replies' as a list of ofpbufs that will contain a series of
- * replies to 'request', which should be an OpenFlow or Nicira extension
- * statistics request.  Initially 'replies' will have a single reply message
- * that has only a header.  The functions ofputil_reserve_stats_reply() and
- * ofputil_append_stats_reply() may be used to add to the reply. */
-void
-ofputil_start_stats_reply(const struct ofp_stats_msg *request,
-                          struct list *replies)
-{
-    struct ofpbuf *msg;
-
-    msg = ofpbuf_new(1024);
-    put_stats_reply__(request, msg);
-
-    list_init(replies);
-    list_push_back(replies, &msg->list_node);
-}
-
-/* Prepares to append up to 'len' bytes to the series of statistics replies in
- * 'replies', which should have been initialized with
- * ofputil_start_stats_reply().  Returns an ofpbuf with at least 'len' bytes of
- * tailroom.  (The 'len' bytes have not actually be allocated; the caller must
- * do so with e.g. ofpbuf_put_uninit().) */
-struct ofpbuf *
-ofputil_reserve_stats_reply(size_t len, struct list *replies)
-{
-    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
-    struct ofp_stats_msg *osm = msg->data;
-
-    if (msg->size + len <= UINT16_MAX) {
-        ofpbuf_prealloc_tailroom(msg, len);
-    } else {
-        osm->flags |= htons(OFPSF_REPLY_MORE);
-
-        msg = ofpbuf_new(MAX(1024, sizeof(struct nicira_stats_msg) + len));
-        put_stats_reply__(osm, msg);
-        list_push_back(replies, &msg->list_node);
-    }
-    return msg;
-}
-
-/* Appends 'len' bytes to the series of statistics replies in 'replies', and
- * returns the first byte. */
-void *
-ofputil_append_stats_reply(size_t len, struct list *replies)
-{
-    return ofpbuf_put_uninit(ofputil_reserve_stats_reply(len, replies), len);
-}
-
-/* Sometimes, when composing stats replies, it's difficult to predict how long
- * an individual reply chunk will be before actually encoding it into the reply
- * buffer.  This function allows easy handling of this case: just encode the
- * reply, then use this function to break the message into two pieces if it
- * exceeds the OpenFlow message limit.
- *
- * In detail, if the final stats message in 'replies' is too long for OpenFlow,
- * this function breaks it into two separate stats replies, the first one with
- * the first 'start_ofs' bytes, the second one containing the bytes from that
- * offset onward. */
-void
-ofputil_postappend_stats_reply(size_t start_ofs, struct list *replies)
-{
-    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
-
-    assert(start_ofs <= UINT16_MAX);
-    if (msg->size > UINT16_MAX) {
-        size_t len = msg->size - start_ofs;
-        memcpy(ofputil_append_stats_reply(len, replies),
-               (const uint8_t *) msg->data + start_ofs, len);
-        msg->size = start_ofs;
-    }
-}
-
-/* Returns the first byte past the ofp_stats_msg header in 'oh'. */
-const void *
-ofputil_stats_body(const struct ofp_header *oh)
-{
-    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
-    return (const struct ofp_stats_msg *) oh + 1;
-}
-
-/* Returns the number of bytes past the ofp_stats_msg header in 'oh'. */
-size_t
-ofputil_stats_body_len(const struct ofp_header *oh)
-{
-    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
-    return ntohs(oh->length) - sizeof(struct ofp_stats_msg);
-}
-
-/* Returns the first byte past the nicira_stats_msg header in 'oh'. */
-const void *
-ofputil_nxstats_body(const struct ofp_header *oh)
-{
-    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
-    return ((const struct nicira_stats_msg *) oh) + 1;
-}
-
-/* Returns the number of bytes past the nicira_stats_msg header in 'oh'. */
-size_t
-ofputil_nxstats_body_len(const struct ofp_header *oh)
-{
-    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
-    return ntohs(oh->length) - sizeof(struct nicira_stats_msg);
-}
-
 /* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
 struct ofpbuf *
 make_echo_request(void)
 {
-    struct ofp_header *rq;
-    struct ofpbuf *out = ofpbuf_new(sizeof *rq);
-    rq = ofpbuf_put_uninit(out, sizeof *rq);
-    rq->version = OFP10_VERSION;
-    rq->type = OFPT_ECHO_REQUEST;
-    rq->length = htons(sizeof *rq);
-    rq->xid = htonl(0);
-    return out;
+    return ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                            htonl(0), 0);
 }
 
 /* Creates and returns an OFPT_ECHO_REPLY message matching the
@@ -3754,20 +2851,21 @@ make_echo_request(void)
 struct ofpbuf *
 make_echo_reply(const struct ofp_header *rq)
 {
-    size_t size = ntohs(rq->length);
-    struct ofpbuf *out = ofpbuf_new(size);
-    struct ofp_header *reply = ofpbuf_put(out, rq, size);
-    reply->type = OFPT_ECHO_REPLY;
-    return out;
+    struct ofpbuf rq_buf;
+    struct ofpbuf *reply;
+
+    ofpbuf_use_const(&rq_buf, rq, ntohs(rq->length));
+    ofpraw_pull_assert(&rq_buf);
+
+    reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, rq_buf.size);
+    ofpbuf_put(reply, rq_buf.data, rq_buf.size);
+    return reply;
 }
 
 struct ofpbuf *
 ofputil_encode_barrier_request(void)
 {
-    struct ofpbuf *msg;
-
-    make_openflow(sizeof(struct ofp_header), OFPT10_BARRIER_REQUEST, &msg);
-    return msg;
+    return ofpraw_alloc(OFPRAW_OFPT10_BARRIER_REQUEST, OFP10_VERSION, 0);
 }
 
 const char *
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index f7d3307..c1f5e6a 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -31,85 +31,6 @@
 struct cls_rule;
 struct ofpbuf;
 
-/* Basic decoding and length validation of OpenFlow messages. */
-enum ofputil_msg_code {
-    OFPUTIL_MSG_INVALID,
-
-    /* OFPT_* messages. */
-    OFPUTIL_OFPT_HELLO,
-    OFPUTIL_OFPT_ERROR,
-    OFPUTIL_OFPT_ECHO_REQUEST,
-    OFPUTIL_OFPT_ECHO_REPLY,
-    OFPUTIL_OFPT_FEATURES_REQUEST,
-    OFPUTIL_OFPT_FEATURES_REPLY,
-    OFPUTIL_OFPT_GET_CONFIG_REQUEST,
-    OFPUTIL_OFPT_GET_CONFIG_REPLY,
-    OFPUTIL_OFPT_SET_CONFIG,
-    OFPUTIL_OFPT_PACKET_IN,
-    OFPUTIL_OFPT_FLOW_REMOVED,
-    OFPUTIL_OFPT_PORT_STATUS,
-    OFPUTIL_OFPT_PACKET_OUT,
-    OFPUTIL_OFPT_FLOW_MOD,
-    OFPUTIL_OFPT_PORT_MOD,
-    OFPUTIL_OFPT_BARRIER_REQUEST,
-    OFPUTIL_OFPT_BARRIER_REPLY,
-    OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST,
-    OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY,
-
-    /* OFPST_* stat requests. */
-    OFPUTIL_OFPST_DESC_REQUEST,
-    OFPUTIL_OFPST_FLOW_REQUEST,
-    OFPUTIL_OFPST_AGGREGATE_REQUEST,
-    OFPUTIL_OFPST_TABLE_REQUEST,
-    OFPUTIL_OFPST_PORT_REQUEST,
-    OFPUTIL_OFPST_QUEUE_REQUEST,
-    OFPUTIL_OFPST_PORT_DESC_REQUEST,
-
-    /* OFPST_* stat replies. */
-    OFPUTIL_OFPST_DESC_REPLY,
-    OFPUTIL_OFPST_FLOW_REPLY,
-    OFPUTIL_OFPST_QUEUE_REPLY,
-    OFPUTIL_OFPST_PORT_REPLY,
-    OFPUTIL_OFPST_TABLE_REPLY,
-    OFPUTIL_OFPST_AGGREGATE_REPLY,
-    OFPUTIL_OFPST_PORT_DESC_REPLY,
-
-    /* NXT_* messages. */
-    OFPUTIL_NXT_ROLE_REQUEST,
-    OFPUTIL_NXT_ROLE_REPLY,
-    OFPUTIL_NXT_SET_FLOW_FORMAT,
-    OFPUTIL_NXT_FLOW_MOD_TABLE_ID,
-    OFPUTIL_NXT_FLOW_MOD,
-    OFPUTIL_NXT_FLOW_REMOVED,
-    OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
-    OFPUTIL_NXT_PACKET_IN,
-    OFPUTIL_NXT_FLOW_AGE,
-    OFPUTIL_NXT_SET_ASYNC_CONFIG,
-    OFPUTIL_NXT_SET_CONTROLLER_ID,
-    OFPUTIL_NXT_FLOW_MONITOR_CANCEL,
-    OFPUTIL_NXT_FLOW_MONITOR_PAUSED,
-    OFPUTIL_NXT_FLOW_MONITOR_RESUMED,
-
-    /* NXST_* stat requests. */
-    OFPUTIL_NXST_FLOW_REQUEST,
-    OFPUTIL_NXST_AGGREGATE_REQUEST,
-    OFPUTIL_NXST_FLOW_MONITOR_REQUEST,
-
-    /* NXST_* stat replies. */
-    OFPUTIL_NXST_FLOW_REPLY,
-    OFPUTIL_NXST_AGGREGATE_REPLY,
-    OFPUTIL_NXST_FLOW_MONITOR_REPLY,
-};
-
-struct ofputil_msg_type;
-enum ofperr ofputil_decode_msg_type(const struct ofp_header *,
-                                    const struct ofputil_msg_type **);
-enum ofperr ofputil_decode_msg_type_partial(const struct ofp_header *,
-                                            size_t length,
-                                            const struct ofputil_msg_type **);
-enum ofputil_msg_code ofputil_msg_type_code(const struct ofputil_msg_type *);
-const char *ofputil_msg_type_name(const struct ofputil_msg_type *);
-
 /* Port numbers. */
 enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port, uint16_t *ofp10_port);
 ovs_be32 ofputil_port_to_ofp11(uint16_t ofp10_port);
@@ -306,7 +227,10 @@ struct ofputil_aggregate_stats {
 
 struct ofpbuf *ofputil_encode_aggregate_stats_reply(
     const struct ofputil_aggregate_stats *stats,
-    const struct ofp_stats_msg *request);
+    const struct ofp_header *request);
+enum ofperr ofputil_decode_aggregate_stats_reply(
+    struct ofputil_aggregate_stats *,
+    const struct ofp_header *reply);
 
 /* Flow removed message, independent of protocol. */
 struct ofputil_flow_removed {
@@ -365,7 +289,7 @@ struct ofputil_packet_out {
 };
 
 enum ofperr ofputil_decode_packet_out(struct ofputil_packet_out *,
-                                      const struct ofp_packet_out *,
+                                      const struct ofp_header *,
                                       struct ofpbuf *ofpacts);
 struct ofpbuf *ofputil_encode_packet_out(const struct ofputil_packet_out *);
 
@@ -470,7 +394,7 @@ struct ofputil_switch_features {
     enum ofputil_action_bitmap actions;
 };
 
-enum ofperr ofputil_decode_switch_features(const struct ofp_switch_features *,
+enum ofperr ofputil_decode_switch_features(const struct ofp_header *,
                                            struct ofputil_switch_features *,
                                            struct ofpbuf *);
 
@@ -492,7 +416,7 @@ struct ofputil_port_status {
     struct ofputil_phy_port desc;
 };
 
-enum ofperr ofputil_decode_port_status(const struct ofp_port_status *,
+enum ofperr ofputil_decode_port_status(const struct ofp_header *,
                                        struct ofputil_port_status *);
 struct ofpbuf *ofputil_encode_port_status(const struct ofputil_port_status *,
                                           enum ofputil_protocol);
@@ -553,52 +477,12 @@ void ofputil_append_flow_update(const struct ofputil_flow_update *,
 uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
 struct ofpbuf *ofputil_encode_flow_monitor_cancel(uint32_t id);
 
-/* OpenFlow protocol utility functions. */
-void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
-void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
-
-void *make_openflow_xid(size_t openflow_len, uint8_t type,
-                        ovs_be32 xid, struct ofpbuf **);
-void *make_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
-                     struct ofpbuf **);
-
-void *put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *);
-void *put_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
-                       struct ofpbuf *);
-
-void *put_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf *);
-void *put_nxmsg_xid(size_t openflow_len, uint32_t subtype, ovs_be32 xid,
-                    struct ofpbuf *);
-
-void update_openflow_length(struct ofpbuf *);
-
-void *ofputil_make_stats_request(size_t openflow_len, uint16_t type,
-                                 uint32_t subtype, struct ofpbuf **);
-void *ofputil_make_stats_reply(size_t openflow_len,
-                               const struct ofp_stats_msg *request,
-                               struct ofpbuf **);
-
-void ofputil_put_stats_header(ovs_be32 xid, uint8_t ofp_type,
-                              ovs_be16 ofpst_type, ovs_be32 nxst_subtype,
-                              struct ofpbuf *);
-
-void ofputil_start_stats_reply(const struct ofp_stats_msg *request,
-                               struct list *);
-struct ofpbuf *ofputil_reserve_stats_reply(size_t len, struct list *);
-void *ofputil_append_stats_reply(size_t len, struct list *);
-void ofputil_postappend_stats_reply(size_t start_ofs, struct list *);
-
+/* Encoding OpenFlow stats messages. */
 void ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
                                           const struct ofputil_phy_port *pp,
                                           struct list *replies);
 
-const void *ofputil_stats_body(const struct ofp_header *);
-size_t ofputil_stats_body_len(const struct ofp_header *);
-
-const void *ofputil_nxstats_body(const struct ofp_header *);
-size_t ofputil_nxstats_body_len(const struct ofp_header *);
-
-/*  */
+/* Encoding simple OpenFlow messages. */
 struct ofpbuf *make_echo_request(void);
 struct ofpbuf *make_echo_reply(const struct ofp_header *rq);
 
diff --git a/lib/rconn.c b/lib/rconn.c
index 1129a3b..b84cda6 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include "coverage.h"
+#include "ofp-msgs.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
@@ -1121,19 +1122,64 @@ is_connected_state(enum state state)
 static bool
 is_admitted_msg(const struct ofpbuf *b)
 {
-    struct ofp_header *oh = b->data;
-    uint8_t type = oh->type;
-    return !(type < 32
-             && (1u << type) & ((1u << OFPT_HELLO) |
-                                (1u << OFPT_ERROR) |
-                                (1u << OFPT_ECHO_REQUEST) |
-                                (1u << OFPT_ECHO_REPLY) |
-                                (1u << OFPT_VENDOR) |
-                                (1u << OFPT_FEATURES_REQUEST) |
-                                (1u << OFPT_FEATURES_REPLY) |
-                                (1u << OFPT_GET_CONFIG_REQUEST) |
-                                (1u << OFPT_GET_CONFIG_REPLY) |
-                                (1u << OFPT_SET_CONFIG)));
+    enum ofptype type;
+    enum ofperr error;
+
+    error = ofptype_decode(&type, b->data);
+    if (error) {
+        return false;
+    }
+
+    switch (type) {
+    case OFPTYPE_HELLO:
+    case OFPTYPE_ERROR:
+    case OFPTYPE_ECHO_REQUEST:
+    case OFPTYPE_ECHO_REPLY:
+    case OFPTYPE_FEATURES_REQUEST:
+    case OFPTYPE_FEATURES_REPLY:
+    case OFPTYPE_GET_CONFIG_REQUEST:
+    case OFPTYPE_GET_CONFIG_REPLY:
+    case OFPTYPE_SET_CONFIG:
+        return false;
+
+    case OFPTYPE_PACKET_IN:
+    case OFPTYPE_FLOW_REMOVED:
+    case OFPTYPE_PORT_STATUS:
+    case OFPTYPE_PACKET_OUT:
+    case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_PORT_MOD:
+    case OFPTYPE_BARRIER_REQUEST:
+    case OFPTYPE_BARRIER_REPLY:
+    case OFPTYPE_DESC_STATS_REQUEST:
+    case OFPTYPE_DESC_STATS_REPLY:
+    case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_AGGREGATE_STATS_REQUEST:
+    case OFPTYPE_AGGREGATE_STATS_REPLY:
+    case OFPTYPE_TABLE_STATS_REQUEST:
+    case OFPTYPE_TABLE_STATS_REPLY:
+    case OFPTYPE_PORT_STATS_REQUEST:
+    case OFPTYPE_PORT_STATS_REPLY:
+    case OFPTYPE_QUEUE_STATS_REQUEST:
+    case OFPTYPE_QUEUE_STATS_REPLY:
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
+    case OFPTYPE_PORT_DESC_STATS_REPLY:
+    case OFPTYPE_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REPLY:
+    case OFPTYPE_SET_FLOW_FORMAT:
+    case OFPTYPE_FLOW_MOD_TABLE_ID:
+    case OFPTYPE_SET_PACKET_IN_FORMAT:
+    case OFPTYPE_FLOW_AGE:
+    case OFPTYPE_SET_ASYNC_CONFIG:
+    case OFPTYPE_SET_CONTROLLER_ID:
+    case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+    case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+    case OFPTYPE_FLOW_MONITOR_CANCEL:
+    case OFPTYPE_FLOW_MONITOR_PAUSED:
+    case OFPTYPE_FLOW_MONITOR_RESUMED:
+    default:
+        return true;
+    }
 }
 
 /* Returns true if 'rc' is currently logging information about connection
diff --git a/lib/stream.c b/lib/stream.c
index 271f16b..2c7bfc3 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -778,7 +778,7 @@ stream_guess_content(const uint8_t *data, ssize_t size)
             return STREAM_SSL;
         case PAIR('{', '"'):
             return STREAM_JSONRPC;
-        case PAIR(OFP10_VERSION, OFPT_HELLO):
+        case PAIR(OFP10_VERSION, 0 /* OFPT_HELLO */):
             return STREAM_OPENFLOW;
         }
     }
diff --git a/lib/vconn.c b/lib/vconn.c
index 5cd708d..8f4052c 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -28,6 +28,7 @@
 #include "fatal-signal.h"
 #include "flow.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
@@ -385,7 +386,7 @@ vcs_send_hello(struct vconn *vconn)
     struct ofpbuf *b;
     int retval;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_HELLO, &b);
+    b = ofpraw_alloc(OFPRAW_OFPT_HELLO, OFP10_VERSION, 0);
     retval = do_send(vconn, b);
     if (!retval) {
         vconn->state = VCS_RECV_HELLO;
@@ -406,9 +407,12 @@ vcs_recv_hello(struct vconn *vconn)
 
     retval = do_recv(vconn, &b);
     if (!retval) {
-        struct ofp_header *oh = b->data;
+        const struct ofp_header *oh = b->data;
+        enum ofptype type;
+        enum ofperr error;
 
-        if (oh->type == OFPT_HELLO) {
+        error = ofptype_decode(&type, b->data);
+        if (!error && type == OFPTYPE_HELLO) {
             if (b->size > sizeof *oh) {
                 struct ds msg = DS_EMPTY_INITIALIZER;
                 ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name);
@@ -529,10 +533,33 @@ vconn_connect(struct vconn *vconn)
 int
 vconn_recv(struct vconn *vconn, struct ofpbuf **msgp)
 {
-    int retval = vconn_connect(vconn);
+    struct ofpbuf *msg;
+    int retval;
+
+    retval = vconn_connect(vconn);
+    if (!retval) {
+        retval = do_recv(vconn, &msg);
+    }
     if (!retval) {
-        retval = do_recv(vconn, msgp);
+        const struct ofp_header *oh = msg->data;
+        if (oh->version != vconn->version) {
+            enum ofptype type;
+
+            if (ofptype_decode(&type, msg->data)
+                || (type != OFPTYPE_HELLO &&
+                    type != OFPTYPE_ERROR &&
+                    type != OFPTYPE_ECHO_REQUEST &&
+                    type != OFPTYPE_ECHO_REPLY)) {
+                VLOG_ERR_RL(&bad_ofmsg_rl, "%s: received OpenFlow version "
+                            "0x%02"PRIx8" != expected %02x",
+                            vconn->name, oh->version, vconn->version);
+                ofpbuf_delete(msg);
+                retval = EPROTO;
+            }
+        }
     }
+
+    *msgp = retval ? NULL : msg;
     return retval;
 }
 
@@ -541,40 +568,12 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp)
 {
     int retval = (vconn->class->recv)(vconn, msgp);
     if (!retval) {
-        struct ofp_header *oh;
-
         COVERAGE_INC(vconn_received);
         if (VLOG_IS_DBG_ENABLED()) {
             char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
             VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
             free(s);
         }
-
-        oh = ofpbuf_at_assert(*msgp, 0, sizeof *oh);
-        if ((oh->version != vconn->version || oh->version == 0)
-            && oh->type != OFPT_HELLO
-            && oh->type != OFPT_ERROR
-            && oh->type != OFPT_ECHO_REQUEST
-            && oh->type != OFPT_ECHO_REPLY
-            && oh->type != OFPT_VENDOR)
-        {
-            if (vconn->version == 0) {
-                VLOG_ERR_RL(&bad_ofmsg_rl,
-                            "%s: received OpenFlow message type %"PRIu8" "
-                            "before version negotiation complete",
-                            vconn->name, oh->type);
-            } else {
-                VLOG_ERR_RL(&bad_ofmsg_rl,
-                            "%s: received OpenFlow version 0x%02"PRIx8" "
-                            "!= expected %02x",
-                            vconn->name, oh->version, vconn->version);
-            }
-            ofpbuf_delete(*msgp);
-            retval = EPROTO;
-        }
-    }
-    if (retval) {
-        *msgp = NULL;
     }
     return retval;
 }
@@ -605,7 +604,8 @@ do_send(struct vconn *vconn, struct ofpbuf *msg)
     int retval;
 
     assert(msg->size >= sizeof(struct ofp_header));
-    assert(((struct ofp_header *) msg->data)->length == htons(msg->size));
+
+    ofpmsg_update_length(msg);
     if (!VLOG_IS_DBG_ENABLED()) {
         COVERAGE_INC(vconn_sent);
         retval = (vconn->class->send)(vconn, msg);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index b70b070..5ce77c0 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -26,6 +26,7 @@
 #include "in-band.h"
 #include "odp-util.h"
 #include "ofp-actions.h"
+#include "ofp-msgs.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "ofproto-provider.h"
@@ -941,15 +942,14 @@ ofconn_send_error(const struct ofconn *ofconn,
         static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(10, 10);
 
         if (!VLOG_DROP_INFO(&err_rl)) {
-            const struct ofputil_msg_type *type;
             const char *type_name;
             size_t request_len;
+            enum ofpraw raw;
 
             request_len = ntohs(request->length);
-            type_name = (!ofputil_decode_msg_type_partial(request,
-                                                          MIN(64, request_len),
-                                                          &type)
-                         ? ofputil_msg_type_name(type)
+            type_name = (!ofpraw_decode_partial(&raw, request,
+                                                MIN(64, request_len))
+                         ? ofpraw_get_name(raw)
                          : "invalid");
 
             VLOG_INFO("%s: sending %s error reply to %s message",
@@ -1289,7 +1289,7 @@ static void
 ofconn_send(const struct ofconn *ofconn, struct ofpbuf *msg,
             struct rconn_packet_counter *counter)
 {
-    update_openflow_length(msg);
+    ofpmsg_update_length(msg);
     rconn_send(ofconn->rconn, msg, counter);
 }
 
@@ -1850,8 +1850,8 @@ ofmonitor_flush(struct connmgr *mgr)
 
                 COVERAGE_INC(ofmonitor_pause);
                 ofconn->monitor_paused = monitor_seqno++;
-                make_nxmsg_xid(sizeof(struct nicira_header),
-                               NXT_FLOW_MONITOR_PAUSED, htonl(0), &pause);
+                pause = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_PAUSED,
+                                         OFP10_VERSION, htonl(0), 0);
                 ofconn_send(ofconn, pause, ofconn->monitor_counter);
             }
         }
@@ -1861,7 +1861,7 @@ ofmonitor_flush(struct connmgr *mgr)
 static void
 ofmonitor_resume(struct ofconn *ofconn)
 {
-    struct ofpbuf *resume;
+    struct ofpbuf *resumed;
     struct ofmonitor *m;
     struct list rules;
     struct list msgs;
@@ -1874,9 +1874,9 @@ ofmonitor_resume(struct ofconn *ofconn)
     list_init(&msgs);
     ofmonitor_compose_refresh_updates(&rules, &msgs);
 
-    make_nxmsg_xid(sizeof(struct nicira_header),
-                   NXT_FLOW_MONITOR_RESUMED, htonl(0), &resume);
-    list_push_back(&msgs, &resume->list_node);
+    resumed = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_MONITOR_RESUMED, OFP10_VERSION,
+                               htonl(0), 0);
+    list_push_back(&msgs, &resumed->list_node);
     ofconn_send_replies(ofconn, &msgs);
 
     ofconn->monitor_paused = 0;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 4daa0cd..f614096 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -34,6 +34,7 @@
 #include "nx-match.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
@@ -2018,7 +2019,8 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
     struct ofpbuf *buf;
 
     /* Send reply. */
-    osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
+    buf = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY, oh, 0);
+    osc = ofpbuf_put_uninit(buf, sizeof *osc);
     flags = ofproto->frag_handling;
     if (ofconn_get_invalid_ttl_to_controller(ofconn)) {
         flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
@@ -2031,8 +2033,9 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
 }
 
 static enum ofperr
-handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
+handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
 {
+    const struct ofp_switch_config *osc = ofpmsg_body(oh);
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     uint16_t flags = ntohs(osc->flags);
 
@@ -2077,7 +2080,7 @@ reject_slave_controller(struct ofconn *ofconn)
 }
 
 static enum ofperr
-handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
+handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
     struct ofputil_packet_out po;
@@ -2096,7 +2099,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
 
     /* Decode message. */
     ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
-    error = ofputil_decode_packet_out(&po, opo, &ofpacts);
+    error = ofputil_decode_packet_out(&po, oh, &ofpacts);
     if (error) {
         goto exit_free_ofpacts;
     }
@@ -2182,13 +2185,14 @@ handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
 
 static enum ofperr
 handle_desc_stats_request(struct ofconn *ofconn,
-                          const struct ofp_stats_msg *request)
+                          const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
     struct ofp_desc_stats *ods;
     struct ofpbuf *msg;
 
-    ods = ofputil_make_stats_reply(sizeof *ods, request, &msg);
+    msg = ofpraw_alloc_stats_reply(request, 0);
+    ods = ofpbuf_put_zeros(msg, sizeof *ods);
     ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
     ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
     ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
@@ -2201,15 +2205,14 @@ handle_desc_stats_request(struct ofconn *ofconn,
 
 static enum ofperr
 handle_table_stats_request(struct ofconn *ofconn,
-                           const struct ofp_stats_msg *request)
+                           const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
     struct ofp_table_stats *ots;
     struct ofpbuf *msg;
     size_t i;
 
-    ofputil_make_stats_reply(sizeof(struct ofp_stats_msg), request, &msg);
-
+    msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables);
     ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables);
     for (i = 0; i < p->n_tables; i++) {
         ots[i].table_id = i;
@@ -2248,7 +2251,7 @@ append_port_stat(struct ofport *port, struct list *replies)
      * netdev_get_stats() will log errors. */
     ofproto_port_get_stats(port, &stats);
 
-    ops = ofputil_append_stats_reply(sizeof *ops, replies);
+    ops = ofpmp_append(replies, sizeof *ops);
     ops->port_no = htons(port->pp.port_no);
     memset(ops->pad, 0, sizeof ops->pad);
     put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets));
@@ -2267,13 +2270,14 @@ append_port_stat(struct ofport *port, struct list *replies)
 
 static enum ofperr
 handle_port_stats_request(struct ofconn *ofconn,
-                          const struct ofp_port_stats_request *psr)
+                          const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
+    const struct ofp_port_stats_request *psr = ofpmsg_body(request);
     struct ofport *port;
     struct list replies;
 
-    ofputil_start_stats_reply(&psr->osm, &replies);
+    ofpmp_init(&replies, request);
     if (psr->port_no != htons(OFPP_NONE)) {
         port = ofproto_get_port(p, ntohs(psr->port_no));
         if (port) {
@@ -2291,13 +2295,13 @@ handle_port_stats_request(struct ofconn *ofconn,
 
 static enum ofperr
 handle_port_desc_stats_request(struct ofconn *ofconn,
-                               const struct ofp_stats_msg *osm)
+                               const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
     struct ofport *port;
     struct list replies;
 
-    ofputil_start_stats_reply(osm, &replies);
+    ofpmp_init(&replies, request);
 
     HMAP_FOR_EACH (port, hmap_node, &p->ports) {
         ofputil_append_port_desc_stats_reply(ofconn_get_protocol(ofconn),
@@ -2487,7 +2491,7 @@ age_secs(long long int age_ms)
 
 static enum ofperr
 handle_flow_stats_request(struct ofconn *ofconn,
-                          const struct ofp_stats_msg *osm)
+                          const struct ofp_header *request)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofputil_flow_stats_request fsr;
@@ -2496,7 +2500,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
     struct rule *rule;
     enum ofperr error;
 
-    error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
+    error = ofputil_decode_flow_stats_request(&fsr, request);
     if (error) {
         return error;
     }
@@ -2508,7 +2512,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
         return error;
     }
 
-    ofputil_start_stats_reply(osm, &replies);
+    ofpmp_init(&replies, request);
     LIST_FOR_EACH (rule, ofproto_node, &rules) {
         long long int now = time_msec();
         struct ofputil_flow_stats fs;
@@ -2633,7 +2637,7 @@ ofproto_port_get_cfm_health(const struct ofproto *ofproto, uint16_t ofp_port)
 
 static enum ofperr
 handle_aggregate_stats_request(struct ofconn *ofconn,
-                               const struct ofp_stats_msg *osm)
+                               const struct ofp_header *oh)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofputil_flow_stats_request request;
@@ -2644,7 +2648,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
     struct rule *rule;
     enum ofperr error;
 
-    error = ofputil_decode_flow_stats_request(&request, &osm->header);
+    error = ofputil_decode_flow_stats_request(&request, oh);
     if (error) {
         return error;
     }
@@ -2686,7 +2690,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
         stats.byte_count = UINT64_MAX;
     }
 
-    reply = ofputil_encode_aggregate_stats_reply(&stats, osm);
+    reply = ofputil_encode_aggregate_stats_reply(&stats, oh);
     ofconn_send_reply(ofconn, reply);
 
     return 0;
@@ -2703,7 +2707,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
 {
     struct ofp_queue_stats *reply;
 
-    reply = ofputil_append_stats_reply(sizeof *reply, &cbdata->replies);
+    reply = ofpmp_append(&cbdata->replies, sizeof *reply);
     reply->port_no = htons(cbdata->ofport->pp.port_no);
     memset(reply->pad, 0, sizeof reply->pad);
     reply->queue_id = htonl(queue_id);
@@ -2744,9 +2748,10 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
 
 static enum ofperr
 handle_queue_stats_request(struct ofconn *ofconn,
-                           const struct ofp_queue_stats_request *qsr)
+                           const struct ofp_header *rq)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    const struct ofp_queue_stats_request *qsr = ofpmsg_body(rq);
     struct queue_stats_cbdata cbdata;
     unsigned int port_no;
     struct ofport *port;
@@ -2755,7 +2760,7 @@ handle_queue_stats_request(struct ofconn *ofconn,
 
     COVERAGE_INC(ofproto_queue_req);
 
-    ofputil_start_stats_reply(&qsr->osm, &cbdata.replies);
+    ofpmp_init(&cbdata.replies, rq);
 
     port_no = ntohs(qsr->port_no);
     queue_id = ntohl(qsr->queue_id);
@@ -3289,7 +3294,7 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    struct nx_role_request *nrr = (struct nx_role_request *) oh;
+    const struct nx_role_request *nrr = ofpmsg_body(oh);
     struct nx_role_request *reply;
     struct ofpbuf *buf;
     uint32_t role;
@@ -3307,7 +3312,8 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 
     ofconn_set_role(ofconn, role);
 
-    reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf);
+    buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, oh, 0);
+    reply = ofpbuf_put_zeros(buf, sizeof *reply);
     reply->role = htonl(role);
     ofconn_send_reply(ofconn, buf);
 
@@ -3318,8 +3324,7 @@ static enum ofperr
 handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
                              const struct ofp_header *oh)
 {
-    const struct nx_flow_mod_table_id *msg
-        = (const struct nx_flow_mod_table_id *) oh;
+    const struct nx_flow_mod_table_id *msg = ofpmsg_body(oh);
     enum ofputil_protocol cur, next;
 
     cur = ofconn_get_protocol(ofconn);
@@ -3332,8 +3337,7 @@ handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
 static enum ofperr
 handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    const struct nx_set_flow_format *msg
-        = (const struct nx_set_flow_format *) oh;
+    const struct nx_set_flow_format *msg = ofpmsg_body(oh);
     enum ofputil_protocol cur, next;
     enum ofputil_protocol next_base;
 
@@ -3357,10 +3361,9 @@ static enum ofperr
 handle_nxt_set_packet_in_format(struct ofconn *ofconn,
                                 const struct ofp_header *oh)
 {
-    const struct nx_set_packet_in_format *msg;
+    const struct nx_set_packet_in_format *msg = ofpmsg_body(oh);
     uint32_t format;
 
-    msg = (const struct nx_set_packet_in_format *) oh;
     format = ntohl(msg->format);
     if (format != NXPIF_OPENFLOW10 && format != NXPIF_NXM) {
         return OFPERR_OFPBRC_EPERM;
@@ -3379,7 +3382,7 @@ handle_nxt_set_packet_in_format(struct ofconn *ofconn,
 static enum ofperr
 handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    const struct nx_async_config *msg = (const struct nx_async_config *) oh;
+    const struct nx_async_config *msg = ofpmsg_body(oh);
     uint32_t master[OAM_N_TYPES];
     uint32_t slave[OAM_N_TYPES];
 
@@ -3404,9 +3407,8 @@ static enum ofperr
 handle_nxt_set_controller_id(struct ofconn *ofconn,
                              const struct ofp_header *oh)
 {
-    const struct nx_controller_id *nci;
+    const struct nx_controller_id *nci = ofpmsg_body(oh);
 
-    nci = (const struct nx_controller_id *) oh;
     if (!is_all_zeros(nci->zero, sizeof nci->zero)) {
         return OFPERR_NXBRC_MUST_BE_ZERO;
     }
@@ -3424,7 +3426,9 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
         return OFPROTO_POSTPONE;
     }
 
-    make_openflow_xid(sizeof *oh, OFPT10_BARRIER_REPLY, oh->xid, &buf);
+    buf = ofpraw_alloc_reply((oh->version == OFP10_VERSION
+                              ? OFPRAW_OFPT10_BARRIER_REPLY
+                              : OFPRAW_OFPT11_BARRIER_REPLY), oh, 0);
     ofconn_send_reply(ofconn, buf);
     return 0;
 }
@@ -3594,8 +3598,7 @@ ofmonitor_collect_resume_rules(struct ofmonitor *m,
 }
 
 static enum ofperr
-handle_flow_monitor_request(struct ofconn *ofconn,
-                            const struct ofp_stats_msg *osm)
+handle_flow_monitor_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofmonitor **monitors;
@@ -3607,7 +3610,7 @@ handle_flow_monitor_request(struct ofconn *ofconn,
     size_t i;
 
     error = 0;
-    ofpbuf_use_const(&b, osm, ntohs(osm->header.length));
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
     monitors = NULL;
     n_monitors = allocated_monitors = 0;
     for (;;) {
@@ -3646,7 +3649,7 @@ handle_flow_monitor_request(struct ofconn *ofconn,
         ofproto_collect_ofmonitor_initial_rules(monitors[i], &rules);
     }
 
-    ofputil_start_stats_reply(osm, &replies);
+    ofpmp_init(&replies, oh);
     ofmonitor_compose_refresh_updates(&rules, &replies);
     ofconn_send_replies(ofconn, &replies);
 
@@ -3682,131 +3685,116 @@ static enum ofperr
 handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
 {
     const struct ofp_header *oh = msg->data;
-    const struct ofputil_msg_type *type;
+    enum ofptype type;
     enum ofperr error;
 
-    error = ofputil_decode_msg_type(oh, &type);
+    error = ofptype_decode(&type, oh);
     if (error) {
         return error;
     }
 
-    switch (ofputil_msg_type_code(type)) {
+    switch (type) {
         /* OpenFlow requests. */
-    case OFPUTIL_OFPT_ECHO_REQUEST:
+    case OFPTYPE_ECHO_REQUEST:
         return handle_echo_request(ofconn, oh);
 
-    case OFPUTIL_OFPT_FEATURES_REQUEST:
+    case OFPTYPE_FEATURES_REQUEST:
         return handle_features_request(ofconn, oh);
 
-    case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+    case OFPTYPE_GET_CONFIG_REQUEST:
         return handle_get_config_request(ofconn, oh);
 
-    case OFPUTIL_OFPT_SET_CONFIG:
-        return handle_set_config(ofconn, msg->data);
+    case OFPTYPE_SET_CONFIG:
+        return handle_set_config(ofconn, oh);
 
-    case OFPUTIL_OFPT_PACKET_OUT:
-        return handle_packet_out(ofconn, msg->data);
+    case OFPTYPE_PACKET_OUT:
+        return handle_packet_out(ofconn, oh);
 
-    case OFPUTIL_OFPT_PORT_MOD:
+    case OFPTYPE_PORT_MOD:
         return handle_port_mod(ofconn, oh);
 
-    case OFPUTIL_OFPT_FLOW_MOD:
+    case OFPTYPE_FLOW_MOD:
         return handle_flow_mod(ofconn, oh);
 
-    case OFPUTIL_OFPT_BARRIER_REQUEST:
+    case OFPTYPE_BARRIER_REQUEST:
         return handle_barrier_request(ofconn, oh);
 
         /* OpenFlow replies. */
-    case OFPUTIL_OFPT_ECHO_REPLY:
+    case OFPTYPE_ECHO_REPLY:
         return 0;
 
         /* Nicira extension requests. */
-    case OFPUTIL_NXT_ROLE_REQUEST:
+    case OFPTYPE_ROLE_REQUEST:
         return handle_role_request(ofconn, oh);
 
-    case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
+    case OFPTYPE_FLOW_MOD_TABLE_ID:
         return handle_nxt_flow_mod_table_id(ofconn, oh);
 
-    case OFPUTIL_NXT_SET_FLOW_FORMAT:
+    case OFPTYPE_SET_FLOW_FORMAT:
         return handle_nxt_set_flow_format(ofconn, oh);
 
-    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+    case OFPTYPE_SET_PACKET_IN_FORMAT:
         return handle_nxt_set_packet_in_format(ofconn, oh);
 
-    case OFPUTIL_NXT_SET_CONTROLLER_ID:
+    case OFPTYPE_SET_CONTROLLER_ID:
         return handle_nxt_set_controller_id(ofconn, oh);
 
-    case OFPUTIL_NXT_FLOW_MOD:
-        return handle_flow_mod(ofconn, oh);
-
-    case OFPUTIL_NXT_FLOW_AGE:
+    case OFPTYPE_FLOW_AGE:
         /* Nothing to do. */
         return 0;
 
-    case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
+    case OFPTYPE_FLOW_MONITOR_CANCEL:
         return handle_flow_monitor_cancel(ofconn, oh);
 
-    case OFPUTIL_NXT_SET_ASYNC_CONFIG:
+    case OFPTYPE_SET_ASYNC_CONFIG:
         return handle_nxt_set_async_config(ofconn, oh);
 
         /* Statistics requests. */
-    case OFPUTIL_OFPST_DESC_REQUEST:
-        return handle_desc_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_FLOW_REQUEST:
-    case OFPUTIL_NXST_FLOW_REQUEST:
-        return handle_flow_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_AGGREGATE_REQUEST:
-    case OFPUTIL_NXST_AGGREGATE_REQUEST:
-        return handle_aggregate_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_TABLE_REQUEST:
-        return handle_table_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_PORT_REQUEST:
-        return handle_port_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_QUEUE_REQUEST:
-        return handle_queue_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_OFPST_PORT_DESC_REQUEST:
-        return handle_port_desc_stats_request(ofconn, msg->data);
-
-    case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
-        return handle_flow_monitor_request(ofconn, msg->data);
-
-    case OFPUTIL_MSG_INVALID:
-    case OFPUTIL_OFPT_HELLO:
-    case OFPUTIL_OFPT_ERROR:
-    case OFPUTIL_OFPT_FEATURES_REPLY:
-    case OFPUTIL_OFPT_GET_CONFIG_REPLY:
-    case OFPUTIL_OFPT_PACKET_IN:
-    case OFPUTIL_OFPT_FLOW_REMOVED:
-    case OFPUTIL_OFPT_PORT_STATUS:
-    case OFPUTIL_OFPT_BARRIER_REPLY:
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
-    case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
-    case OFPUTIL_OFPST_DESC_REPLY:
-    case OFPUTIL_OFPST_FLOW_REPLY:
-    case OFPUTIL_OFPST_QUEUE_REPLY:
-    case OFPUTIL_OFPST_PORT_REPLY:
-    case OFPUTIL_OFPST_TABLE_REPLY:
-    case OFPUTIL_OFPST_AGGREGATE_REPLY:
-    case OFPUTIL_OFPST_PORT_DESC_REPLY:
-    case OFPUTIL_NXT_ROLE_REPLY:
-    case OFPUTIL_NXT_FLOW_REMOVED:
-    case OFPUTIL_NXT_PACKET_IN:
-    case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
-    case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
-    case OFPUTIL_NXST_FLOW_REPLY:
-    case OFPUTIL_NXST_AGGREGATE_REPLY:
-    case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+    case OFPTYPE_DESC_STATS_REQUEST:
+        return handle_desc_stats_request(ofconn, oh);
+
+    case OFPTYPE_FLOW_STATS_REQUEST:
+        return handle_flow_stats_request(ofconn, oh);
+
+    case OFPTYPE_AGGREGATE_STATS_REQUEST:
+        return handle_aggregate_stats_request(ofconn, oh);
+
+    case OFPTYPE_TABLE_STATS_REQUEST:
+        return handle_table_stats_request(ofconn, oh);
+
+    case OFPTYPE_PORT_STATS_REQUEST:
+        return handle_port_stats_request(ofconn, oh);
+
+    case OFPTYPE_QUEUE_STATS_REQUEST:
+        return handle_queue_stats_request(ofconn, oh);
+
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
+        return handle_port_desc_stats_request(ofconn, oh);
+
+    case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
+        return handle_flow_monitor_request(ofconn, oh);
+
+    case OFPTYPE_HELLO:
+    case OFPTYPE_ERROR:
+    case OFPTYPE_FEATURES_REPLY:
+    case OFPTYPE_GET_CONFIG_REPLY:
+    case OFPTYPE_PACKET_IN:
+    case OFPTYPE_FLOW_REMOVED:
+    case OFPTYPE_PORT_STATUS:
+    case OFPTYPE_BARRIER_REPLY:
+    case OFPTYPE_DESC_STATS_REPLY:
+    case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_QUEUE_STATS_REPLY:
+    case OFPTYPE_PORT_STATS_REPLY:
+    case OFPTYPE_TABLE_STATS_REPLY:
+    case OFPTYPE_AGGREGATE_STATS_REPLY:
+    case OFPTYPE_PORT_DESC_STATS_REPLY:
+    case OFPTYPE_ROLE_REPLY:
+    case OFPTYPE_FLOW_MONITOR_PAUSED:
+    case OFPTYPE_FLOW_MONITOR_RESUMED:
+    case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
     default:
-        return (oh->type == OFPT10_STATS_REQUEST ||
-                oh->type == OFPT10_STATS_REPLY
-                ? OFPERR_OFPBRC_BAD_STAT
-                : OFPERR_OFPBRC_BAD_TYPE);
+        return OFPERR_OFPBRC_BAD_TYPE;
     }
 }
 
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 1fe54f1..ebbb76e 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -20,7 +20,7 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print 00bb0008eeff0011],
   [0], [dnl
 ***decode error: OFPBRC_BAD_TYPE***
 00000000  00 bb 00 08 ee ff 00 11-                        |........        |
-], [ofp_util|WARN|received OpenFlow message of unknown type 187
+], [ofp_msgs|WARN|unknown OpenFlow message (version 0, type 187)
 ])
 AT_CLEANUP
 
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 924e97a..c7cb839 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -92,6 +92,7 @@ AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4
 ])
 
+AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --pidfile 2> ofctl_monitor.log])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
index e7d6da4..658f30e 100644
--- a/tests/ofproto-macros.at
+++ b/tests/ofproto-macros.at
@@ -50,7 +50,7 @@ m4_define([OVS_VSWITCHD_START],
    AT_CHECK([ovs-vsctl --no-wait init])
 
    dnl Start ovs-vswitchd.
-   AT_CHECK([ovs-vswitchd --detach --pidfile --enable-dummy --disable-system --log-file], [0], [], [stderr])
+   AT_CHECK([ovs-vswitchd --detach --pidfile --enable-dummy --disable-system --log-file -vvconn], [0], [], [stderr])
    AT_CAPTURE_FILE([ovs-vswitchd.log])
    AT_CHECK([[sed < stderr '
 /vlog|INFO|opened log file/d
diff --git a/tests/test-vconn.c b/tests/test-vconn.c
index 3398c4a..74ebd6e 100644
--- a/tests/test-vconn.c
+++ b/tests/test-vconn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,9 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include "command-line.h"
+#include "ofp-msgs.h"
+#include "ofp-util.h"
+#include "ofpbuf.h"
 #include "openflow/openflow.h"
 #include "poll-loop.h"
 #include "socket-util.h"
@@ -206,8 +209,11 @@ test_read_hello(int argc OVS_UNUSED, char *argv[])
 
        retval = stream_recv(stream, &hello, sizeof hello);
        if (retval == sizeof hello) {
+           enum ofpraw raw;
+
            CHECK(hello.version, OFP10_VERSION);
-           CHECK(hello.type, OFPT_HELLO);
+           CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
+           CHECK(raw, OFPRAW_OFPT_HELLO);
            CHECK(ntohs(hello.length), sizeof hello);
            break;
        } else {
@@ -273,8 +279,11 @@ test_send_hello(const char *type, const void *out, size_t out_size,
            struct ofp_header hello;
            int retval = stream_recv(stream, &hello, sizeof hello);
            if (retval == sizeof hello) {
+               enum ofpraw raw;
+
                CHECK(hello.version, OFP10_VERSION);
-               CHECK(hello.type, OFPT_HELLO);
+               CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
+               CHECK(raw, OFPRAW_OFPT_HELLO);
                CHECK(ntohs(hello.length), sizeof hello);
                read_hello = true;
            } else {
@@ -321,13 +330,12 @@ static void
 test_send_plain_hello(int argc OVS_UNUSED, char *argv[])
 {
     const char *type = argv[1];
-    struct ofp_header hello;
+    struct ofpbuf *hello;
 
-    hello.version = OFP10_VERSION;
-    hello.type = OFPT_HELLO;
-    hello.length = htons(sizeof hello);
-    hello.xid = htonl(0x12345678);
-    test_send_hello(type, &hello, sizeof hello, 0);
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+                             htonl(0x12345678), 0);
+    test_send_hello(type, hello->data, hello->size, 0);
+    ofpbuf_delete(hello);
 }
 
 /* Try connecting and sending an extra-long hello, which should succeed (since
@@ -337,16 +345,15 @@ static void
 test_send_long_hello(int argc OVS_UNUSED, char *argv[])
 {
     const char *type = argv[1];
-    struct ofp_header hello;
-    char buffer[sizeof hello * 2];
-
-    hello.version = OFP10_VERSION;
-    hello.type = OFPT_HELLO;
-    hello.length = htons(sizeof buffer);
-    hello.xid = htonl(0x12345678);
-    memset(buffer, 0, sizeof buffer);
-    memcpy(buffer, &hello, sizeof hello);
-    test_send_hello(type, buffer, sizeof buffer, 0);
+    struct ofpbuf *hello;
+    enum { EXTRA_BYTES = 8 };
+
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+                             htonl(0x12345678), EXTRA_BYTES);
+    ofpbuf_put_zeros(hello, EXTRA_BYTES);
+    ofpmsg_update_length(hello);
+    test_send_hello(type, hello->data, hello->size, 0);
+    ofpbuf_delete(hello);
 }
 
 /* Try connecting and sending an echo request instead of a hello, which should
@@ -355,13 +362,12 @@ static void
 test_send_echo_hello(int argc OVS_UNUSED, char *argv[])
 {
     const char *type = argv[1];
-    struct ofp_header echo;
+    struct ofpbuf *echo;
 
-    echo.version = OFP10_VERSION;
-    echo.type = OFPT_ECHO_REQUEST;
-    echo.length = htons(sizeof echo);
-    echo.xid = htonl(0x89abcdef);
-    test_send_hello(type, &echo, sizeof echo, EPROTO);
+    echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                             htonl(0x12345678), 0);
+    test_send_hello(type, echo->data, echo->size, EPROTO);
+    ofpbuf_delete(echo);
 }
 
 /* Try connecting and sending a hello packet that has its length field as 0,
@@ -382,13 +388,13 @@ static void
 test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[])
 {
     const char *type = argv[1];
-    struct ofp_header hello;
+    struct ofpbuf *hello;
 
-    hello.version = OFP10_VERSION - 1;
-    hello.type = OFPT_HELLO;
-    hello.length = htons(sizeof hello);
-    hello.xid = htonl(0x12345678);
-    test_send_hello(type, &hello, sizeof hello, EPROTO);
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+                             htonl(0x12345678), 0);
+    ((struct ofp_header *) hello->data)->version = 0;
+    test_send_hello(type, hello->data, hello->size, EPROTO);
+    ofpbuf_delete(hello);
 }
 
 static const struct command commands[] = {
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index e5c5255..2eee16b 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -40,6 +40,7 @@
 #include "odp-util.h"
 #include "ofp-actions.h"
 #include "ofp-errors.h"
+#include "ofp-msgs.h"
 #include "ofp-parse.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
@@ -393,21 +394,10 @@ open_vconn(const char *name, struct vconn **vconnp)
     return open_vconn__(name, "mgmt", vconnp);
 }
 
-static void *
-alloc_stats_request(size_t rq_len, uint16_t type, struct ofpbuf **bufferp)
-{
-    struct ofp_stats_msg *rq;
-
-    rq = make_openflow(rq_len, OFPT10_STATS_REQUEST, bufferp);
-    rq->type = htons(type);
-    rq->flags = htons(0);
-    return rq;
-}
-
 static void
 send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
 {
-    update_openflow_length(buffer);
+    ofpmsg_update_length(buffer);
     run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
 }
 
@@ -417,7 +407,7 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request)
     struct vconn *vconn;
     struct ofpbuf *reply;
 
-    update_openflow_length(request);
+    ofpmsg_update_length(request);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     ofp_print(stdout, reply->data, reply->size, verbosity + 1);
@@ -426,20 +416,26 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request)
 }
 
 static void
-dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
+dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
 {
     struct ofpbuf *request;
-    make_openflow(sizeof(struct ofp_header), request_type, &request);
+    request = ofpraw_alloc(raw, OFP10_VERSION, 0);
     dump_transaction(vconn_name, request);
 }
 
 static void
 dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request)
 {
-    ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
-    ovs_be16 stats_type = ((struct ofp_stats_msg *) request->data)->type;
+    const struct ofp_header *request_oh = request->data;
+    ovs_be32 send_xid = request_oh->xid;
+    enum ofpraw request_raw;
+    enum ofpraw reply_raw;
     bool done = false;
 
+    ofpraw_decode_partial(&request_raw, request->data, request->size);
+    reply_raw = ofpraw_stats_request_to_reply(request_raw,
+                                              request_oh->version);
+
     send_openflow_buffer(vconn, request);
     while (!done) {
         ovs_be32 recv_xid;
@@ -448,16 +444,15 @@ dump_stats_transaction__(struct vconn *vconn, struct ofpbuf *request)
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
         recv_xid = ((struct ofp_header *) reply->data)->xid;
         if (send_xid == recv_xid) {
-            const struct ofp_stats_msg *osm = reply->data;
-            const struct ofp_header *oh = reply->data;
+            enum ofpraw raw;
 
             ofp_print(stdout, reply->data, reply->size, verbosity + 1);
 
-            if (oh->type == OFPT_ERROR) {
+            ofpraw_decode(&raw, reply->data);
+            if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
                 done = true;
-            } else if (oh->type == OFPT10_STATS_REPLY
-                       && osm->type == stats_type) {
-                done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+            } else if (raw == reply_raw) {
+                done = !ofpmp_more(reply->data);
             } else {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
@@ -482,10 +477,11 @@ dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
 }
 
 static void
-dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
+dump_trivial_stats_transaction(const char *vconn_name, enum ofpraw raw)
 {
     struct ofpbuf *request;
-    alloc_stats_request(sizeof(struct ofp_stats_msg), stats_type, &request);
+
+    request = ofpraw_alloc(raw, OFP10_VERSION, 0);
     dump_stats_transaction(vconn_name, request);
 }
 
@@ -500,7 +496,7 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests)
     struct ofpbuf *request, *reply;
 
     LIST_FOR_EACH (request, list_node, requests) {
-        update_openflow_length(request);
+        ofpmsg_update_length(request);
     }
 
     run(vconn_transact_multiple_noreply(vconn, requests, &reply),
@@ -531,38 +527,31 @@ static void
 fetch_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
 {
     struct ofp_switch_config *config;
-    struct ofp_header *header;
     struct ofpbuf *request;
     struct ofpbuf *reply;
+    enum ofptype type;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_GET_CONFIG_REQUEST,
-                  &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION, 0);
     run(vconn_transact(vconn, request, &reply),
         "talking to %s", vconn_get_name(vconn));
 
-    header = reply->data;
-    if (header->type != OFPT_GET_CONFIG_REPLY ||
-        header->length != htons(sizeof *config)) {
+    if (ofptype_pull(&type, reply) || type != OFPTYPE_GET_CONFIG_REPLY) {
         ovs_fatal(0, "%s: bad reply to config request", vconn_get_name(vconn));
     }
 
-    config = reply->data;
+    config = ofpbuf_pull(reply, sizeof *config);
     *config_ = *config;
 
     ofpbuf_delete(reply);
 }
 
 static void
-set_switch_config(struct vconn *vconn, struct ofp_switch_config *config_)
+set_switch_config(struct vconn *vconn, const struct ofp_switch_config *config)
 {
-    struct ofp_switch_config *config;
-    struct ofp_header save_header;
     struct ofpbuf *request;
 
-    config = make_openflow(sizeof *config, OFPT_SET_CONFIG, &request);
-    save_header = config->header;
-    *config = *config_;
-    config->header = save_header;
+    request = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, OFP10_VERSION, 0);
+    ofpbuf_put(request, config, sizeof *config);
 
     transact_noreply(vconn, request);
 }
@@ -576,8 +565,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
     struct ofpbuf *reply;
     bool trunc;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST,
-                  &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
 
@@ -591,21 +579,22 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
         /* The Features Reply may not contain all the ports, so send a
          * Port Description stats request, which doesn't have size
          * constraints. */
-        dump_trivial_stats_transaction(vconn_name, OFPST_PORT_DESC);
+        dump_trivial_stats_transaction(vconn_name,
+                                       OFPRAW_OFPST_PORT_DESC_REQUEST);
     }
-    dump_trivial_transaction(vconn_name, OFPT_GET_CONFIG_REQUEST);
+    dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
 }
 
 static void
 ofctl_dump_desc(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_DESC);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_DESC_REQUEST);
 }
 
 static void
 ofctl_dump_tables(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST);
 }
 
 static bool
@@ -614,23 +603,24 @@ fetch_port_by_features(const char *vconn_name,
                        struct ofputil_phy_port *pp, bool *trunc)
 {
     struct ofputil_switch_features features;
-    const struct ofp_switch_features *osf;
+    const struct ofp_header *oh;
     struct ofpbuf *request, *reply;
     struct vconn *vconn;
     enum ofperr error;
+    enum ofptype type;
     struct ofpbuf b;
     bool found = false;
 
     /* Fetch the switch's ofp_switch_features. */
-    make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+    request = ofpraw_alloc(OFPRAW_OFPT_FEATURES_REQUEST, OFP10_VERSION, 0);
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     vconn_close(vconn);
 
-    osf = reply->data;
-    if (reply->size < sizeof *osf) {
-        ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
-                  vconn_name, reply->size);
+    oh = reply->data;
+    if (ofptype_decode(&type, reply->data)
+        || type != OFPTYPE_FEATURES_REPLY) {
+        ovs_fatal(0, "%s: received bad features reply", vconn_name);
     }
 
     *trunc = false;
@@ -639,13 +629,13 @@ fetch_port_by_features(const char *vconn_name,
         goto exit;
     }
 
-    error = ofputil_decode_switch_features(osf, &features, &b);
+    error = ofputil_decode_switch_features(oh, &features, &b);
     if (error) {
         ovs_fatal(0, "%s: failed to decode features reply (%s)",
                   vconn_name, ofperr_to_string(error));
     }
 
-    while (!ofputil_pull_phy_port(osf->header.version, &b, pp)) {
+    while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
         if (port_no != UINT_MAX
             ? port_no == pp->port_no
             : !strcmp(pp->name, port_name)) {
@@ -667,12 +657,10 @@ fetch_port_by_stats(const char *vconn_name,
     struct ofpbuf *request;
     struct vconn *vconn;
     ovs_be32 send_xid;
-    struct ofpbuf b;
     bool done = false;
     bool found = false;
 
-    alloc_stats_request(sizeof(struct ofp_stats_msg), OFPST_PORT_DESC,
-                        &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0);
     send_xid = ((struct ofp_header *) request->data)->xid;
 
     open_vconn(vconn_name, &vconn);
@@ -684,18 +672,21 @@ fetch_port_by_stats(const char *vconn_name,
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
         recv_xid = ((struct ofp_header *) reply->data)->xid;
         if (send_xid == recv_xid) {
-            const struct ofputil_msg_type *type;
-            struct ofp_stats_msg *osm;
-
-            ofputil_decode_msg_type(reply->data, &type);
-            if (ofputil_msg_type_code(type) != OFPUTIL_OFPST_PORT_DESC_REPLY) {
+            struct ofp_header *oh = reply->data;
+            enum ofptype type;
+            struct ofpbuf b;
+            uint16_t flags;
+
+            ofpbuf_use_const(&b, oh, ntohs(oh->length));
+            if (ofptype_pull(&type, &b)
+                || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
                                         verbosity + 1));
             }
 
-            osm = ofpbuf_at_assert(reply, 0, sizeof *osm);
-            done = !(ntohs(osm->flags) & OFPSF_REPLY_MORE);
+            flags = ofpmp_flags(oh);
+            done = !(flags & OFPSF_REPLY_MORE);
 
             if (found) {
                 /* We've already found the port, but we need to drain
@@ -703,10 +694,7 @@ fetch_port_by_stats(const char *vconn_name,
                 continue;
             }
 
-            ofpbuf_use_const(&b, &osm->header, ntohs(osm->header.length));
-            ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
-
-            while (!ofputil_pull_phy_port(osm->header.version, &b, pp)) {
+            while (!ofputil_pull_phy_port(oh->version, &b, pp)) {
                 if (port_no != UINT_MAX ? port_no == pp->port_no
                                         : !strcmp(pp->name, port_name)) {
                     found = true;
@@ -969,7 +957,8 @@ ofctl_queue_stats(int argc, char *argv[])
     struct ofp_queue_stats_request *req;
     struct ofpbuf *request;
 
-    req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST, OFP10_VERSION, 0);
+    req = ofpbuf_put_zeros(request, sizeof *req);
 
     if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
         req->port_no = htons(str_to_port_no(argv[1], argv[2]));
@@ -1318,8 +1307,9 @@ monitor_vconn(struct vconn *vconn)
         int retval;
 
         unixctl_server_run(server);
+
         while (!blocked) {
-            uint8_t msg_type;
+            enum ofptype type;
 
             retval = vconn_recv(vconn, &b);
             if (retval == EAGAIN) {
@@ -1335,11 +1325,11 @@ monitor_vconn(struct vconn *vconn)
                 fputs(s, stderr);
             }
 
-            msg_type = ((const struct ofp_header *) b->data)->type;
+            ofptype_decode(&type, b->data);
             ofp_print(stderr, b->data, b->size, verbosity + 2);
             ofpbuf_delete(b);
 
-            if (barrier_aux.conn && msg_type == OFPT10_BARRIER_REPLY) {
+            if (barrier_aux.conn && type == OFPTYPE_BARRIER_REPLY) {
                 unixctl_command_reply(barrier_aux.conn, NULL);
                 barrier_aux.conn = NULL;
             }
@@ -1430,7 +1420,8 @@ ofctl_dump_ports(int argc, char *argv[])
     struct ofpbuf *request;
     uint16_t port;
 
-    req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
+    request = ofpraw_alloc(OFPRAW_OFPST_PORT_REQUEST, OFP10_VERSION, 0);
+    req = ofpbuf_put_zeros(request, sizeof *req);
     port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
     req->port_no = htons(port);
     dump_stats_transaction(argv[1], request);
@@ -1439,7 +1430,7 @@ ofctl_dump_ports(int argc, char *argv[])
 static void
 ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_PORT_DESC);
+    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_PORT_DESC_REQUEST);
 }
 
 static void
@@ -1449,7 +1440,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[])
     struct vconn *vconn;
     struct ofpbuf *reply;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
+    request = make_echo_request();
     open_vconn(argv[1], &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
     if (reply->size != sizeof(struct ofp_header)) {
@@ -1619,28 +1610,29 @@ ofctl_ping(int argc, char *argv[])
     for (i = 0; i < 10; i++) {
         struct timeval start, end;
         struct ofpbuf *request, *reply;
-        struct ofp_header *rq_hdr, *rpy_hdr;
+        const struct ofp_header *rpy_hdr;
+        enum ofptype type;
 
-        rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
-                               OFPT_ECHO_REQUEST, &request);
-        random_bytes(rq_hdr + 1, payload);
+        request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                               payload);
+        random_bytes(ofpbuf_put_uninit(request, payload), payload);
 
         xgettimeofday(&start);
         run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
         xgettimeofday(&end);
 
         rpy_hdr = reply->data;
-        if (reply->size != request->size
-            || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
-            || rpy_hdr->xid != rq_hdr->xid
-            || rpy_hdr->type != OFPT_ECHO_REPLY) {
+        if (ofptype_pull(&type, reply)
+            || type != OFPTYPE_ECHO_REPLY
+            || reply->size != payload
+            || memcmp(request->l3, reply->l3, payload)) {
             printf("Reply does not match request.  Request:\n");
             ofp_print(stdout, request, request->size, verbosity + 2);
             printf("Reply:\n");
             ofp_print(stdout, reply, reply->size, verbosity + 2);
         }
         printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
-               reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid),
+               reply->size, argv[1], ntohl(rpy_hdr->xid),
                    (1000*(double)(end.tv_sec - start.tv_sec))
                    + (.001*(end.tv_usec - start.tv_usec)));
         ofpbuf_delete(request);
@@ -1675,10 +1667,10 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[])
     xgettimeofday(&start);
     for (i = 0; i < count; i++) {
         struct ofpbuf *request, *reply;
-        struct ofp_header *rq_hdr;
 
-        rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
-        memset(rq_hdr + 1, 0, payload_size);
+        request = ofpraw_alloc(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+                               payload_size);
+        ofpbuf_put_zeros(request, payload_size);
         run(vconn_transact(vconn, request, &reply), "transact");
         ofpbuf_delete(reply);
     }
@@ -1875,18 +1867,16 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
 
         /* Get a flow stats reply message, if we don't already have one. */
         if (!reply) {
-            const struct ofputil_msg_type *type;
-            enum ofputil_msg_code code;
+            enum ofptype type;
+            enum ofperr error;
 
             do {
                 run(vconn_recv_block(vconn, &reply),
                     "OpenFlow packet receive failed");
             } while (((struct ofp_header *) reply->data)->xid != send_xid);
 
-            ofputil_decode_msg_type(reply->data, &type);
-            code = ofputil_msg_type_code(type);
-            if (code != OFPUTIL_OFPST_FLOW_REPLY &&
-                code != OFPUTIL_NXST_FLOW_REPLY) {
+            error = ofptype_decode(&type, reply->data);
+            if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
                           ofp_to_string(reply->data, reply->size,
                                         verbosity + 1));
-- 
1.7.2.5




More information about the dev mailing list