Merge remote-tracking branch 'upstream/master'

Conflicts:
	c_gen/c_test_gen.py
	java_gen/java_type.py
	java_gen/pre-written/pom.xml
	java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
	java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
	loxi_ir/ir_offset.py
diff --git a/.build/push-artifacts.sh b/.build/push-artifacts.sh
index 8c7b60b..ec81d62 100755
--- a/.build/push-artifacts.sh
+++ b/.build/push-artifacts.sh
@@ -9,9 +9,11 @@
     exit 1
 fi
 
+ARTIFACT_REPO_BRANCH=${2-master}
+
 ARTIFACT_REPO=$(mktemp -d --tmpdir "push-artifacts-repo.XXXXXXX")
 
-git clone ${ARTIFACT_REPO_URL} ${ARTIFACT_REPO}
+git clone ${ARTIFACT_REPO_URL} ${ARTIFACT_REPO} -b ${ARTIFACT_REPO_BRANCH}
 find ${ARTIFACT_REPO} -mindepth 1 -maxdepth 1 -type d \! -name '.*' -print0 | xargs -0 rm -r
 make LOXI_OUTPUT_DIR=${ARTIFACT_REPO} clean all
 
@@ -55,7 +57,7 @@
 
     git tag -a -f "loxi/${loxi_head}" -m "Tag Loxigen Revision ${loxi_head}"
     git push --tags
-    git push
+    git push origin HEAD
 )
 
 rm -rf ${ARTIFACT_REPO}
diff --git a/Makefile b/Makefile
index 018db0b..5f3d8e5 100644
--- a/Makefile
+++ b/Makefile
@@ -131,6 +131,7 @@
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of11.py
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of12.py
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of13.py
+	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of14.py
 
 check-c: c
 	make -j4 -C ${LOXI_OUTPUT_DIR}/locitest
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 9b19af6..ace386d 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -119,135 +119,6 @@
         if not m_name in of_g.ordered_members[cls]:
             of_g.ordered_members[cls].append(m_name)
 
-def update_offset(cls, wire_version, name, offset, m_type):
-    """
-    Update (and return) the offset based on type.
-    @param cls The parent class
-    @param wire_version The wire version being processed
-    @param name The name of the data member
-    @param offset The current offset
-    @param m_type The type declaration being processed
-    @returns A pair (next_offset, len_update)  next_offset is the new offset
-    of the next object or -1 if this is a var-length object.  len_update
-    is the increment that should be added to the length.  Note that (for
-    of_match_v3) it is variable length, but it adds 8 bytes to the fixed
-    length of the object
-    If offset is already -1, do not update
-    Otherwise map to base type and count and update (if possible)
-    """
-    if offset < 0:    # Don't update offset once set to -1
-        return offset, 0
-
-    count, base_type = loxi_utils.type_dec_to_count_base(m_type)
-
-    len_update = 0
-    if base_type in of_g.of_mixed_types:
-        base_type = of_g.of_mixed_types[base_type][wire_version]
-
-    base_class = base_type[:-2]
-    if (base_class, wire_version) in of_g.is_fixed_length:
-        bytes = of_g.base_length[(base_class, wire_version)]
-    else:
-        if base_type == "of_match_v3_t":
-            # This is a special case: it has non-zero min length
-            # but is variable length
-            bytes = -1
-            len_update = 8
-        elif base_type == "of_oxm_header_t":
-            # This is a special case: it has non-zero min length
-            # but is variable length
-            bytes = -1
-            len_update = 4
-        elif base_type == "of_bsn_vport_header_t":
-            # This is a special case: it has non-zero min length
-            # but is variable length
-            bytes = -1
-            len_update = 4
-        elif base_type in of_g.of_base_types:
-            bytes = of_g.of_base_types[base_type]["bytes"]
-        else:
-            print "UNKNOWN TYPE for %s %s: %s" % (cls, name, base_type)
-            log("UNKNOWN TYPE for %s %s: %s" % (cls, name, base_type))
-            bytes = -1
-
-    # If bytes
-    if bytes > 0:
-        len_update = count * bytes
-
-    if bytes == -1:
-        return -1, len_update
-
-    return offset + (count * bytes), len_update
-
-def calculate_offsets_and_lengths(ordered_classes, classes, wire_version):
-    """
-    Generate the offsets for fixed offset class members
-    Also calculate the class_sizes when possible.
-
-    @param classes The classes to process
-    @param wire_version The wire version for this set of classes
-
-    Updates global variables
-    """
-
-    lists = set()
-
-    # Generate offsets
-    for cls in ordered_classes:
-        fixed_offset = 0 # The last "good" offset seen
-        offset = 0
-        last_offset = 0
-        last_name = "-"
-        for member in classes[cls]:
-            m_type = member["m_type"]
-            name = member["name"]
-            if last_offset == -1:
-                if name == "pad":
-                    log("Skipping pad for special offset for %s" % cls)
-                else:
-                    log("SPECIAL OFS: Member %s (prev %s), class %s ver %d" %
-                          (name, last_name, cls, wire_version))
-                    if (((cls, name) in of_g.special_offsets) and
-                        (of_g.special_offsets[(cls, name)] != last_name)):
-                        debug("ERROR: special offset prev name changed")
-                        debug("  cls %s. name %s. version %d. was %s. now %s" %
-                              cls, name, wire_version,
-                              of_g.special_offsets[(cls, name)], last_name)
-                        sys.exit(1)
-                    of_g.special_offsets[(cls, name)] = last_name
-
-            member["offset"] = offset
-            if m_type.find("list(") == 0:
-                (list_name, base_type) = loxi_utils.list_name_extract(m_type)
-                lists.add(list_name)
-                member["m_type"] = list_name + "_t"
-                offset = -1
-            elif m_type.find("struct") == 0:
-                debug("ERROR found struct: %s.%s " % (cls, name))
-                sys.exit(1)
-            elif m_type == "octets":
-                log("offset gen skipping octets: %s.%s " % (cls, name))
-                offset = -1
-            else:
-                offset, len_update = update_offset(cls, wire_version, name,
-                                                  offset, m_type)
-                if offset != -1:
-                    fixed_offset = offset
-                else:
-                    fixed_offset += len_update
-                    log("offset is -1 for %s.%s version %d " %
-                        (cls, name, wire_version))
-            last_offset = offset
-            last_name = name
-        of_g.base_length[(cls, wire_version)] = fixed_offset
-        if (offset != -1):
-            of_g.is_fixed_length.add((cls, wire_version))
-
-    for list_type in lists:
-        classes[list_type] = []
-        of_g.ordered_classes[wire_version].append(list_type)
-        of_g.base_length[(list_type, wire_version)] = 0
-
 def order_and_assign_object_ids():
     """
     Order all classes and assign object ids to all classes.
@@ -329,27 +200,30 @@
             pad_count = 0
             for m in ofclass.members:
                 if type(m) == OFPadMember:
-                    m_name = 'pad%d' % pad_count
-                    if m_name == 'pad0': m_name = 'pad'
-                    legacy_members.append(dict(m_type='uint8_t[%d]' % m.length,
-                                               name=m_name))
-                    pad_count += 1
+                    continue
                 else:
-                    # HACK the C backend does not yet support of_oxm_t
-                    if m.oftype == 'of_oxm_t':
-                        m_type = 'of_oxm_header_t'
-                    # HACK the C backend does not yet support of_bsn_vport_t
-                    elif m.oftype == 'of_bsn_vport_t':
-                        m_type = 'of_bsn_vport_header_t'
+                    if m.oftype.find("list(") == 0:
+                        (list_name, base_type) = loxi_utils.list_name_extract(m.oftype)
+                        m_type = list_name + "_t"
                     else:
                         enum = find(lambda e: e.name == m.oftype, protocol.enums)
                         if enum and "wire_type" in enum.params:
                             m_type = enum.params["wire_type"]
                         else:
                             m_type = m.oftype
-                    legacy_members.append(dict(m_type=m_type, name=m.name))
+
+                    if m.offset is None:
+                        m_offset = -1
+                    else:
+                        m_offset = m.offset
+
+                    legacy_members.append(dict(m_type=m_type, name=m.name, offset=m_offset))
             versions[version_name]['classes'][ofclass.name] = legacy_members
 
+            of_g.base_length[(ofclass.name, version.wire_version)] = ofclass.base_length
+            if ofclass.is_fixed_length:
+                of_g.is_fixed_length.add((ofclass.name, version.wire_version))
+
         for enum in protocol.enums:
             for entry in enum.entries:
                 identifiers.add_identifier(
@@ -361,81 +235,6 @@
     """
     Use the type members in the IR to fill out the legacy type_maps.
     """
-
-    def split_inherited_cls(cls):
-        if cls == 'of_meter_band_stats': # HACK not a subtype of of_meter_band
-            return None, None
-        for parent in sorted(type_maps.inheritance_data.keys(), reverse=True):
-            if cls.startswith(parent):
-                return (parent, cls[len(parent)+1:])
-        return None, None
-
-    def find_experimenter(parent, cls):
-        for experimenter in sorted(of_g.experimenter_name_to_id.keys(), reverse=True):
-            prefix = parent + '_' + experimenter
-            if cls.startswith(prefix) and cls != prefix:
-                return experimenter
-        return None
-
-    def find_type_value(ofclass, m_name):
-        for m in ofclass.members:
-            if isinstance(m, OFTypeMember) and m.name == m_name:
-                return m.value
-        raise KeyError("ver=%d, cls=%s, m_name=%s" % (wire_version, cls, m_name))
-
-    # Most inheritance classes: actions, instructions, etc
-    for version, protocol in loxi_globals.ir.items():
-        wire_version = version.wire_version
-        for ofclass in protocol.classes:
-            cls = ofclass.name
-            parent, subcls = split_inherited_cls(cls)
-            if not (parent and subcls):
-                continue
-            if parent == 'of_oxm':
-                type_len = find_type_value(ofclass, 'type_len')
-                oxm_class = (type_len >> 16) & 0xffff
-                if oxm_class != 0x8000:
-                    # Do not include experimenter OXMs in the main table
-                    val = type_maps.invalid_type
-                else:
-                    val = (type_len >> 8) & 0xff
-            else:
-                val = find_type_value(ofclass, 'type')
-            type_maps.inheritance_data[parent][wire_version][subcls] = val
-
-            # Extensions (only actions for now)
-            experimenter = find_experimenter(parent, cls)
-            if parent == 'of_action' and experimenter:
-                val = find_type_value(ofclass, 'subtype')
-                type_maps.extension_action_subtype[wire_version][experimenter][cls] = val
-                if wire_version >= of_g.VERSION_1_3:
-                    cls2 = parent + "_id" + cls[len(parent):]
-                    type_maps.extension_action_id_subtype[wire_version][experimenter][cls2] = val
-            elif parent == 'of_instruction' and experimenter:
-                val = find_type_value(ofclass, 'subtype')
-                type_maps.extension_instruction_subtype[wire_version][experimenter][cls] = val
-
-    # Messages
-    for version, protocol in loxi_globals.ir.items():
-        wire_version = version.wire_version
-        for ofclass in protocol.classes:
-            cls = ofclass.name
-            # HACK (though this is what loxi_utils.class_is_message() does)
-            if not [x for x in ofclass.members if isinstance(x, OFDataMember) and x.name == 'xid']:
-                continue
-            if type_maps.class_is_virtual(cls):
-                continue
-            subcls = cls[3:]
-            val = find_type_value(ofclass, 'type')
-            if not val in type_maps.message_types[wire_version].values():
-                type_maps.message_types[wire_version][subcls] = val
-
-            # Extensions
-            experimenter = find_experimenter('of', cls)
-            if experimenter and ofclass.is_subclassof("of_experimenter"):
-                val = find_type_value(ofclass, 'subtype')
-                type_maps.extension_message_subtype[wire_version][experimenter][cls] = val
-
     type_maps.generate_maps()
 
 def analyze_input():
@@ -443,22 +242,38 @@
     Add information computed from the input, including offsets and
     lengths of struct members and the set of list and action_id types.
     """
+    # Create lists
+    for version, protocol in loxi_globals.ir.items():
+        lists = set()
+        classes = versions[of_g.of_version_wire2name[version.wire_version]]['classes']
 
-    # Generate header classes for inheritance parents
-    for wire_version, ordered_classes in of_g.ordered_classes.items():
-        classes = versions[of_g.of_version_wire2name[wire_version]]['classes']
-        for cls in ordered_classes:
-            if cls in type_maps.inheritance_map:
-                new_cls = cls + '_header'
-                of_g.ordered_classes[wire_version].append(new_cls)
-                classes[new_cls] = classes[cls]
+        for ofclass in protocol.classes:
+            for m in ofclass.members:
+                if isinstance(m, OFDataMember) and m.oftype.find("list(") == 0:
+                    (list_name, base_type) = loxi_utils.list_name_extract(m.oftype)
+                    lists.add(list_name)
 
-    for wire_version in of_g.wire_ver_map.keys():
-        version_name = of_g.of_version_wire2name[wire_version]
-        calculate_offsets_and_lengths(
-            of_g.ordered_classes[wire_version],
-            versions[version_name]['classes'],
-            wire_version)
+        for list_type in lists:
+            classes[list_type] = []
+            of_g.ordered_classes[version.wire_version].append(list_type)
+            of_g.base_length[(list_type, version.wire_version)] = 0
+
+    # Find special offsets
+    # These are defined as members (except padding) that don't have a fixed
+    # offset. The special_offsets map stores the name of the previous member.
+    for version, protocol in loxi_globals.ir.items():
+        for ofclass in protocol.classes:
+            prev_member = None
+            for m in ofclass.members:
+                if isinstance(m, OFPadMember):
+                    continue
+                if m.offset == None:
+                    old = of_g.special_offsets.get((ofclass.name, m.name))
+                    if old and old != prev_member.name:
+                        raise Exception("Error: special offset changed: version=%s cls=%s member=%s old=%s new=%s" %
+                                        (version, ofclass.name, m.name, old, prev_member.name))
+                    of_g.special_offsets[(ofclass.name, m.name)] = prev_member.name
+                prev_member = m
 
 def unify_input():
     """
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 484e941..896e9ad 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -403,7 +403,6 @@
 int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
 
 extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];
-extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];
 """)
     c_type_maps.gen_type_data_header(out)
     c_match.gen_declarations(out)
@@ -530,7 +529,7 @@
 /**
  * Check if a version is supported
  */
-#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_3)
+#define OF_VERSION_OKAY(v) ((v) >= OF_VERSION_1_0 && (v) <= OF_VERSION_1_4)
 
 """)
     gen_version_enum(out)
@@ -617,19 +616,26 @@
    uint8_t addr[OF_IPV6_BYTES];
 } of_ipv6_t;
 
+typedef struct of_bitmap_512_s {
+    uint64_t words[8];
+} of_bitmap_512_t;
+
 extern const of_mac_addr_t of_mac_addr_all_ones;
 extern const of_mac_addr_t of_mac_addr_all_zeros;
 
 extern const of_ipv6_t of_ipv6_all_ones;
 extern const of_ipv6_t of_ipv6_all_zeros;
 
+extern const of_bitmap_512_t of_bitmap_512_all_ones;
+extern const of_bitmap_512_t of_bitmap_512_all_zeroes;
+
 /**
  * Generic zero and all-ones values of size 16 bytes.
  *
- * IPv6 is longest data type we worry about for comparisons
+ * bitmap_512 is longest data type we worry about for comparisons
  */
-#define of_all_zero_value of_ipv6_all_zeros
-#define of_all_ones_value of_ipv6_all_ones
+#define of_all_zero_value of_bitmap_512_all_zeroes
+#define of_all_ones_value of_bitmap_512_all_ones
 
 /**
  * Non-zero/all ones check for arbitrary type of size <= 16 bytes
@@ -726,24 +732,6 @@
 #define U64_HTON(val) U64_NTOH(val)
 #define IPV6_HTON(dst, src) /* NOTE different syntax; currently no-op */
 #endif
-
-/****************************************************************
- *
- * The following are internal definitions used by the automatically
- * generated code.  Users should not reference these definitions
- * as they may change between versions of this code
- *
- ****************************************************************/
-
-#define OF_MESSAGE_IN_MATCH_POINTER(obj)                            \\
-    (WIRE_BUF_POINTER(&((obj)->wire_buffer), OF_MESSAGE_IN_MATCH_OFFSET))
-#define OF_MESSAGE_IN_MATCH_LEN(ptr) BUF_U16_GET(&ptr[2])
-#define OF_MESSAGE_IN_DATA_OFFSET(obj) \\
-    (FIXED_LEN + OF_MESSAGE_IN_MATCH_LEN(OF_MESSAGE_IN_MATCH_POINTER(obj)) + 2)
-
-#define OF_MESSAGE_OUT_DATA_OFFSET(obj) \\
-    (FIXED_LEN + of_message_out_actions_len_get(obj))
-
 """)
 
 def external_h_top_matter(out, name):
@@ -773,7 +761,6 @@
  * Per-class static delete functions
  * Per-class, per-member accessor declarations
  * Per-class structure definitions
- * Generic union (inheritance) definitions
  * Pointer set function declarations
  * Some special case macros
  *
@@ -875,61 +862,6 @@
 #define OF_MESSAGE_OBJECT_COUNT %d
 """ % ((last + 1), msg_count))
 
-    # Generate object type range checking for inheritance classes
-
-    # @fixme These should be determined algorithmicly
-    out.write("""
-/*
- * Macros to check if an object ID is within an inheritance class range
- */
-""")
-    # Alphabetical order for 'last'
-    last_ids = dict(of_action="OF_ACTION_STRIP_VLAN",
-                    of_oxm="OF_OXM_VLAN_VID_MASKED",
-                    of_instruction="OF_INSTRUCTION_WRITE_METADATA",
-                    of_queue_prop="OF_QUEUE_PROP_MIN_RATE",
-                    of_table_feature_prop="OF_TABLE_FEATURE_PROP_WRITE_SETFIELD_MISS",
-                    # @FIXME add meter_band ?
-                    )
-    for cls, last in last_ids.items():
-        out.write("""
-#define %(enum)s_FIRST_ID      (%(enum)s + 1)
-#define %(enum)s_LAST_ID       %(last)s
-#define %(enum)s_VALID_ID(id) \\
-    ((id) >= %(enum)s_FIRST_ID && \\
-     (id) <= %(enum)s_LAST_ID)
-""" % dict(enum=enum_name(cls), last=last))
-    out.write("""
-/**
- * Function to check a wire ID
- * @param object_id The ID to check
- * @param base_object_id The inheritance parent, if applicable
- * @returns boolean: If base_object_id is an inheritance class, check if
- * object_id is valid as a subclass.  Otherwise return 1.
- *
- * Note: Could check that object_id == base_object_id in the
- * second case.
- */
-static inline int
-of_wire_id_valid(int object_id, int base_object_id) {
-    switch (base_object_id) {
-    case OF_ACTION:
-        return OF_ACTION_VALID_ID(object_id);
-    case OF_OXM:
-        return OF_OXM_VALID_ID(object_id);
-    case OF_QUEUE_PROP:
-        return OF_QUEUE_PROP_VALID_ID(object_id);
-    case OF_TABLE_FEATURE_PROP:
-        return OF_TABLE_FEATURE_PROP_VALID_ID(object_id);
-    case OF_INSTRUCTION:
-        return OF_INSTRUCTION_VALID_ID(object_id);
-    default:
-        break;
-    }
-    return 1;
-}
-""")
-
 ################################################################
 #
 # Internal Utility Functions
@@ -1041,37 +973,14 @@
 #
 ################################################################
 
-def gen_generics(out):
-    for (cls, subclasses) in type_maps.inheritance_map.items():
-        out.write("""
-/**
- * Inheritance super class for %(cls)s
- *
- * This class is the union of %(cls)s classes.  You can refer
- * to it untyped by refering to the member 'header' whose structure
- * is common across all sub-classes.
- */
-
-union %(cls)s_u {
-    %(cls)s_header_t header; /* Generic instance */
-""" % dict(cls=cls))
-        for subcls in sorted(subclasses):
-            out.write("    %s_%s_t %s;\n" % (cls, subcls, subcls))
-        out.write("};\n")
-
 def gen_struct_typedefs(out):
     """
     Generate typedefs for all struct objects
     @param out The file for output, already open
     """
 
-    out.write("\n/* LOCI inheritance parent typedefs */\n")
-    for cls in type_maps.inheritance_map:
-        out.write("typedef union %(cls)s_u %(cls)s_t;\n" % dict(cls=cls))
     out.write("\n/* LOCI object typedefs */\n")
     for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            continue
         template = "typedef of_object_t %(cls)s_t;\n"
         out.write(template % dict(cls=cls))
 
@@ -1110,7 +1019,7 @@
  ****************************************************************/
 """)
     for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
+        if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
             continue
         out.write("\n/* Unified accessor functions for %s */\n" % cls)
         for m_name in of_g.ordered_members[cls]:
@@ -1150,13 +1059,13 @@
             e_type = loxi_utils.list_to_entry_type(cls)
             out.write("""
 extern int %(cls)s_first(
-    %(cls)s_t *list, %(e_type)s_t *obj);
+    %(cls)s_t *list, of_object_t *iter);
 extern int %(cls)s_next(
-    %(cls)s_t *list, %(e_type)s_t *obj);
+    %(cls)s_t *list, of_object_t *iter);
 extern int %(cls)s_append_bind(
-    %(cls)s_t *list, %(e_type)s_t *obj);
+    %(cls)s_t *list, of_object_t *iter);
 extern int %(cls)s_append(
-    %(cls)s_t *list, %(e_type)s_t *obj);
+    %(cls)s_t *list, of_object_t *iter);
 
 /**
  * Iteration macro for list of type %(cls)s
@@ -1298,7 +1207,7 @@
     LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
     OF_TRY(of_match_deserialize(ver, %(m_name)s, obj, offset, cur_len));
 """ % dict(m_name=m_name))
-    elif m_type == "of_oxm_header_t":
+    elif m_type == "of_oxm_t":
         out.write("""
     /* Initialize child */
     %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
@@ -1306,7 +1215,7 @@
     of_object_attach(obj, %(m_name)s, offset, cur_len);
     of_object_wire_init(%(m_name)s, OF_OXM, 0);
 """ % dict(m_type=m_type[:-2], m_name=m_name))
-    elif m_type == "of_bsn_vport_header_t":
+    elif m_type == "of_bsn_vport_t":
         out.write("""
     /* Initialize child */
     %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
@@ -1630,10 +1539,6 @@
     @param cls The class name for the function
     @param out The file to which to write
     """
-    if cls in type_maps.inheritance_map:
-        param = "obj_p"
-    else:
-        param = "obj"
 
     out.write("""
 /**
@@ -1654,33 +1559,20 @@
  */
 
 void
-%(cls)s_init(%(cls)s_t *%(param)s,
+%(cls)s_init(of_object_t *obj,
     of_version_t version, int bytes, int clean_wire)
 {
-""" % dict(cls=cls, param=param))
-
-    # Use an extra pointer to deal with inheritance classes
-    if cls in type_maps.inheritance_map:
-        out.write("""\
-    %s_header_t *obj;
-
-    obj = &obj_p->header;  /* Need instantiable subclass */
-""" % cls)
-
-    out.write("""
     LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
     if (clean_wire) {
         MEMSET(obj, 0, sizeof(*obj));
     }
     if (bytes < 0) {
-        bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
+        bytes = of_object_fixed_len[version][%(enum)s];
     }
     obj->version = version;
     obj->length = bytes;
     obj->object_id = %(enum)s;
-""" % dict(cls=cls, enum=enum_name(cls)))
 
-    out.write("""
     /* Grow the wire buffer */
     if (obj->wbuf != NULL) {
         int tot_bytes;
@@ -1689,66 +1581,7 @@
         of_wire_buffer_grow(obj->wbuf, tot_bytes);
     }
 }
-
-""")
-
-## @fixme This should also be updated once there is a map from
-# class instance to wire length/type accessors
-def gen_wire_push_fn(cls, out):
-    """
-    Generate the calls to push values into the wire buffer
-    """
-    if type_maps.class_is_virtual(cls):
-        print "Push fn gen called for virtual class " + cls
-        return
-
-    out.write("""
-/**
- * Helper function to push values into the wire buffer
- */
-static inline int
-%(cls)s_push_wire_values(%(cls)s_t *obj)
-{
-""" % dict(cls=cls))
-
-    import loxi_globals
-    uclass = loxi_globals.unified.class_by_name(cls)
-    if uclass and not uclass.virtual and uclass.has_type_members:
-        out.write("""
-    %(cls)s_push_wire_types(obj);
-""" % dict(cls=cls))
-
-    if loxi_utils.class_is_message(cls):
-        out.write("""
-    /* Message obj; set length */
-    of_message_t msg;
-
-    if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
-        of_message_length_set(msg, obj->length);
-    }
-""" % dict(name = enum_name(cls)))
-
-    else: # Not a message
-        if loxi_utils.class_is_tlv16(cls):
-            out.write("""
-    /* TLV obj; set length */
-    of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
-""" % dict(enum=enum_name(cls)))
-
-        if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
-            out.write("""
-    of_object_wire_length_set((of_object_t *)obj, obj->length);
-""")
-
-        if cls == "of_meter_stats":
-            out.write("""
-    of_meter_stats_wire_length_set((of_object_t *)obj, obj->length);
-""" % dict(enum=enum_name(cls)))
-
-    out.write("""
-    return OF_ERROR_NONE;
-}
-""")
+""" % dict(cls=cls, enum=enum_name(cls)))
 
 def gen_new_fn_body(cls, out):
     """
@@ -1763,9 +1596,6 @@
  */
 """ % dict(cls=cls))
 
-    if not type_maps.class_is_virtual(cls):
-        gen_wire_push_fn(cls, out)
-
     uclass = loxi_globals.unified.class_by_name(cls)
     is_fixed_length = uclass and uclass.is_fixed_length
     max_length = is_fixed_length and "bytes" or "OF_WIRE_BUFFER_MAX_LENGTH"
@@ -1783,35 +1613,40 @@
  * \\ingroup %(cls)s
  */
 
-%(cls)s_t *
+of_object_t *
 %(cls)s_new(of_version_t version)
 {
-    %(cls)s_t *obj;
+    of_object_t *obj;
     int bytes;
 
-    bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
+    bytes = of_object_fixed_len[version][%(enum)s];
 
-    if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
+    if ((obj = of_object_new(%(max_length)s)) == NULL) {
         return NULL;
     }
 
     %(cls)s_init(obj, version, bytes, 0);
 """ % dict(cls=cls, enum=enum_name(cls), max_length=max_length))
     if not type_maps.class_is_virtual(cls):
-        out.write("""
-    if (%(cls)s_push_wire_values(obj) < 0) {
-        FREE(obj);
-        return NULL;
-    }
-""" % dict(cls=cls))
+        from codegen import class_metadata_dict
+        metadata = class_metadata_dict[cls]
+
+        if metadata.wire_type_set != 'NULL':
+            out.write("""\
+    %s(obj);
+""" % metadata.wire_type_set)
+
+        if metadata.wire_length_set != 'NULL':
+            out.write("""\
+    %s(obj, obj->length);
+""" % metadata.wire_length_set)
 
     match_offset = v3_match_offset_get(cls)
     if match_offset >= 0:
         # Init length field for match object
         out.write("""
     /* Initialize match TLV for 1.2 */
-    /* FIXME: Check 1.3 below */
-    if ((version == OF_VERSION_1_2) || (version == OF_VERSION_1_3)) {
+    if ((version >= OF_VERSION_1_2)) {
         of_object_u16_set((of_object_t *)obj, %(match_offset)d + 2, 4);
     }
 """ % dict(match_offset=match_offset))
@@ -1847,11 +1682,11 @@
 
     for cls in of_g.standard_class_order:
         out.write("""
-extern %(cls)s_t *
+extern of_object_t *
     %(cls)s_new(of_version_t version);
 """ % dict(cls=cls))
         out.write("""extern void %(cls)s_init(
-    %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
+    of_object_t *obj, of_version_t version, int bytes, int clean_wire);
 """ % dict(cls=cls))
 
     out.write("""
@@ -1863,8 +1698,6 @@
  ****************************************************************/
 """)
     for cls in of_g.standard_class_order:
-#        if cls in type_maps.inheritance_map:
-#            continue
         out.write("""
 /**
  * Delete an object of type %(cls)s_t
@@ -1873,8 +1706,8 @@
  * \ingroup %(cls)s
  */
 static inline void
-%(cls)s_delete(%(cls)s_t *obj) {
-    of_object_delete((of_object_t *)(obj));
+%(cls)s_delete(of_object_t *obj) {
+    of_object_delete(obj);
 }
 """ % dict(cls=cls))
 
@@ -1922,8 +1755,8 @@
     out.write("/* DOCUMENTATION ONLY */\n")
 
     for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            pass # Check this
+        if type_maps.class_is_virtual(cls):
+            pass
 
         out.write("""
 /**
diff --git a/c_gen/c_dump_gen.py b/c_gen/c_dump_gen.py
index d4a016c..799dc09 100644
--- a/c_gen/c_dump_gen.py
+++ b/c_gen/c_dump_gen.py
@@ -90,10 +90,10 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             out.write("""\
-int %(cls)s_%(ver_name)s_dump(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
+int %(cls)s_%(ver_name)s_dump(loci_writer_f writer, void* cookie, of_object_t *obj);
 """ % dict(cls=cls, ver_name=loxi_utils.version_to_name(version)))
 
     out.write("""
@@ -129,11 +129,11 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             out.write("""
 int
-%(cls)s_%(ver_name)s_dump(loci_writer_f writer, void* cookie, %(cls)s_t *obj)
+%(cls)s_%(ver_name)s_dump(loci_writer_f writer, void* cookie, of_object_t *obj)
 {
     int out = 0;
 """ % dict(cls=cls, ver_name=ver_name))
@@ -150,7 +150,7 @@
 """  % dict(m_type=m_type, v_name=var_name_map(m_type)))
                     if loxi_utils.class_is_list(m_type):
                         base_type = loxi_utils.list_to_entry_type(m_type)
-                        out.write("    %s elt;\n    int rv;\n" % base_type)
+                        out.write("    of_object_t elt;\n    int rv;\n")
             out.write("""
     out += writer(cookie, "Object of type %(cls)s\\n");
 """ % dict(cls=cls))
@@ -184,7 +184,7 @@
                     sub_cls = m_type[:-2] # Trim _t
                     out.write("""
     %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
-    out += %(sub_cls)s_%(ver_name)s_dump(writer, cookie, &%(v_name)s);
+    out += of_object_dump(writer, cookie, &%(v_name)s);
 """ % dict(cls=cls, sub_cls=sub_cls, m_name=m_name,
            v_name=var_name_map(m_type), ver_name=ver_name))
 
@@ -234,7 +234,7 @@
                 comma = ","
 
             if (not loxi_utils.class_in_version(cls, version) or
-                    cls in type_maps.inheritance_map):
+                    type_maps.class_is_virtual(cls)):
                 out.write("    unknown_dump%s\n" % comma);
             else:
                 out.write("    %s_%s_dump%s\n" %
@@ -242,20 +242,20 @@
         out.write("};\n\n")
 
     out.write("""
-static const loci_obj_dump_f *const dump_funs[5] = {
-    NULL,
-    dump_funs_v1,
-    dump_funs_v2,
-    dump_funs_v3,
-    dump_funs_v4
+static const loci_obj_dump_f *const dump_funs[] = {
+""")
+
+    for version in of_g.of_version_range:
+        out.write("    [%(v)d] = dump_funs_v%(v)d,\n" % dict(v=version))
+
+    out.write("""\
 };
 
 int
 of_object_dump(loci_writer_f writer, void* cookie, of_object_t *obj)
 {
     if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) {
-        if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_3)) {
-            /* @fixme VERSION */
+        if (OF_VERSION_OKAY(obj->version)) {
             return dump_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj);
         } else {
             return writer(cookie, "Bad version %d\\n", obj->version);
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index 3afc99c..ccc503d 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -104,6 +104,13 @@
 #define of_match_v4_to_match of_match_v3_to_match
 #define of_match_to_wire_match_v4 of_match_to_wire_match_v3
 #define of_match_v4_delete of_match_v3_delete
+
+#define of_match_v5_t of_match_v3_t
+#define of_match_v5_init of_match_v3_init
+#define of_match_v5_new of_match_v3_new
+#define of_match_v5_to_match of_match_v3_to_match
+#define of_match_to_wire_match_v5 of_match_to_wire_match_v3
+#define of_match_v5_delete of_match_v3_delete
 """)
 
 def gen_match_macros(out):
@@ -451,7 +458,7 @@
 static int
 populate_oxm_list(of_match_t *src, of_list_oxm_t *oxm_list)
 {
-    of_oxm_t oxm_entry;
+    of_object_t elt;
 
     /* For each active member, add an OXM entry to the list */
 """)
@@ -459,23 +466,18 @@
         out.write("""\
     if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(src)) {
         if (!OF_MATCH_MASK_%(ku)s_EXACT_TEST(src)) {
-            of_oxm_%(key)s_masked_t *elt;
-            elt = &oxm_entry.%(key)s_masked;
-
-            of_oxm_%(key)s_masked_init(elt,
+            of_oxm_%(key)s_masked_init(&elt,
                 oxm_list->version, -1, 1);
-            of_list_oxm_append_bind(oxm_list, &oxm_entry);
-            of_oxm_%(key)s_masked_value_set(elt,
+            of_list_oxm_append_bind(oxm_list, &elt);
+            of_oxm_%(key)s_masked_value_set(&elt,
                    src->fields.%(key)s);
-            of_oxm_%(key)s_masked_value_mask_set(elt,
+            of_oxm_%(key)s_masked_value_mask_set(&elt,
                    src->masks.%(key)s);
         } else {  /* Active, but not masked */
-            of_oxm_%(key)s_t *elt;
-            elt = &oxm_entry.%(key)s;
-            of_oxm_%(key)s_init(elt,
+            of_oxm_%(key)s_init(&elt,
                 oxm_list->version, -1, 1);
-            of_list_oxm_append_bind(oxm_list, &oxm_entry);
-            of_oxm_%(key)s_value_set(elt, src->fields.%(key)s);
+            of_list_oxm_append_bind(oxm_list, &elt);
+            of_oxm_%(key)s_value_set(&elt, src->fields.%(key)s);
         }
     }
 """ % dict(key=key, ku=key.upper()))
@@ -622,7 +624,7 @@
 {
     int rv;
     of_list_oxm_t oxm_list;
-    of_oxm_t oxm_entry;
+    of_object_t oxm_entry;
 """)
 #    for key in match.of_match_members:
 #        out.write("    of_oxm_%s_t *%s;\n" % (key, key))
@@ -636,23 +638,23 @@
     rv = of_list_oxm_first(&oxm_list, &oxm_entry);
 
     while (rv == OF_ERROR_NONE) {
-        switch (oxm_entry.header.object_id) { /* What kind of entry is this */
+        switch (oxm_entry.object_id) { /* What kind of entry is this */
 """)
     for key in match.of_match_members:
         out.write("""
         case OF_OXM_%(ku)s_MASKED:
             of_oxm_%(key)s_masked_value_mask_get(
-                &oxm_entry.%(key)s_masked,
+                &oxm_entry,
                 &dst->masks.%(key)s);
             of_oxm_%(key)s_masked_value_get(
-                &oxm_entry.%(key)s,
+                &oxm_entry,
                 &dst->fields.%(key)s);
             of_memmask(&dst->fields.%(key)s, &dst->masks.%(key)s, sizeof(&dst->fields.%(key)s));
             break;
         case OF_OXM_%(ku)s:
             OF_MATCH_MASK_%(ku)s_EXACT_SET(dst);
             of_oxm_%(key)s_value_get(
-                &oxm_entry.%(key)s,
+                &oxm_entry,
                 &dst->fields.%(key)s);
             break;
 """ % (dict(ku=key.upper(), key=key)))
@@ -961,55 +963,31 @@
  */
 
 static inline int
-of_match_more_specific(of_match_t *entry, of_match_t *query)
+of_match_more_specific(const of_match_t *entry, const of_match_t *query)
 {
-    of_match_fields_t *q_m, *e_m;  /* Short hand for masks, fields */
-    of_match_fields_t *q_f, *e_f;
+    LOCI_ASSERT(sizeof(of_match_fields_t) % sizeof(uint8_t) == 0);
 
-    q_m = &query->masks;
-    e_m = &entry->masks;
-    q_f = &query->fields;
-    e_f = &entry->fields;
-""")
-    for key, entry in match.of_match_members.items():
-        q_m = "&q_m->%s" % key
-        e_m = "&e_m->%s" % key
-        q_f = "&q_f->%s" % key
-        e_f = "&e_f->%s" % key
-        if entry["m_type"] == "of_ipv6_t":
-            comp = "OF_MORE_SPECIFIC_IPV6"
-            match_type = "OF_RESTRICTED_MATCH_IPV6"
-        elif entry["m_type"] == "of_mac_addr_t":
-            comp = "OF_MORE_SPECIFIC_MAC_ADDR"
-            match_type = "OF_RESTRICTED_MATCH_MAC_ADDR"
-        elif entry["m_type"] == "of_bitmap_128_t":
-            comp = "OF_MORE_SPECIFIC_BITMAP_128"
-            match_type = "OF_RESTRICTED_MATCH_BITMAP_128"
-        else: # Integer
-            comp = "OF_MORE_SPECIFIC_INT"
-            match_type = "OF_RESTRICTED_MATCH_INT"
-            q_m = "q_m->%s" % key
-            e_m = "e_m->%s" % key
-            q_f = "q_f->%s" % key
-            e_f = "e_f->%s" % key
-        out.write("""
-    /* Mask and values for %(key)s */
-    if (!%(comp)s(%(e_m)s, %(q_m)s)) {
-        return 0;
-    }
-    if (!%(match_type)s(%(e_f)s, %(q_f)s,
-            %(q_m)s)) {
-        return 0;
-    }
-""" % dict(match_type=match_type, comp=comp, q_f=q_f, e_f=e_f,
-           q_m=q_m, e_m=e_m, key=key))
+    /* Short hand for masks, fields */
+    const uint8_t *qm = (const uint8_t *)&query->masks;
+    const uint8_t *em = (const uint8_t *)&entry->masks;
+    const uint8_t *qf = (const uint8_t *)&query->fields;
+    const uint8_t *ef = (const uint8_t *)&entry->fields;
 
-    out.write("""
+    int i;
+    for (i = 0; i < sizeof(of_match_fields_t)/sizeof(uint8_t); i++) {
+        if (qm[i] & ~em[i]) {
+            /* Query mask has a bit set that isn't set in the entry mask */
+            return 0;
+        }
+
+        if ((qf[i] ^ ef[i]) & qm[i]) {
+            /* Query and entry disagree on a field bit */
+            return 0;
+        }
+    }
+
     return 1;
 }
-""")
-
-    out.write("""
 
 /**
  * Do two entries overlap?
@@ -1020,42 +998,24 @@
  */
 
 static inline int
-of_match_overlap(of_match_t *match1, of_match_t *match2)
+of_match_overlap(const of_match_t *match1, const of_match_t *match2)
 {
-    of_match_fields_t *m1, *m2;  /* Short hand for masks, fields */
-    of_match_fields_t *f1, *f2;
+    LOCI_ASSERT(sizeof(of_match_fields_t) % sizeof(uint8_t) == 0);
 
-    m1 = &match1->masks;
-    m2 = &match2->masks;
-    f1 = &match1->fields;
-    f2 = &match2->fields;
-""")
-    for key, entry in match.of_match_members.items():
-        m1 = "&m1->%s" % key
-        m2 = "&m2->%s" % key
-        f1 = "&f1->%s" % key
-        f2 = "&f2->%s" % key
-        if entry["m_type"] == "of_ipv6_t":
-            check = "OF_OVERLAP_IPV6"
-        elif entry["m_type"] == "of_mac_addr_t":
-            check = "OF_OVERLAP_MAC_ADDR"
-        elif entry["m_type"] == "of_bitmap_128_t":
-            check = "OF_OVERLAP_BITMAP_128"
-        else: # Integer
-            check = "OF_OVERLAP_INT"
-            m1 = "m1->%s" % key
-            m2 = "m2->%s" % key
-            f1 = "f1->%s" % key
-            f2 = "f2->%s" % key
-        out.write("""
-    /* Check overlap for %(key)s */
-    if (!%(check)s(%(f1)s, %(f2)s,
-        %(m2)s, %(m1)s)) {
-        return 0; /* This field differentiates; all done */
+    /* Short hand for masks, fields */
+    const uint8_t *m1 = (const uint8_t *)&match1->masks;
+    const uint8_t *m2 = (const uint8_t *)&match2->masks;
+    const uint8_t *f1 = (const uint8_t *)&match1->fields;
+    const uint8_t *f2 = (const uint8_t *)&match2->fields;
+
+    int i;
+    for (i = 0; i < sizeof(of_match_fields_t)/sizeof(uint8_t); i++) {
+        if ((f1[i] ^ f2[i]) & (m1[i] & m2[i])) {
+            /* Matches disagree on a field bit they both qualify on */
+            return 0;
+        }
     }
-""" % dict(check=check, f1=f1, f2=f2, m1=m1, m2=m2, key=key))
 
-    out.write("""
     return 1; /* No field differentiates matches */
 }
 """)
diff --git a/c_gen/c_show_gen.py b/c_gen/c_show_gen.py
index 9d84477..d1cbbdb 100644
--- a/c_gen/c_show_gen.py
+++ b/c_gen/c_show_gen.py
@@ -43,6 +43,78 @@
 import c_gen.identifiers as identifiers
 from c_test_gen import var_name_map
 
+show_override = {
+    ('uint32_t', 'arp_tpa'): 'ipv4',
+    ('uint32_t', 'arp_spa'): 'ipv4',
+    ('uint32_t', 'nw_addr'): 'ipv4',
+    ('uint32_t', 'dst'): 'ipv4',
+}
+
+show_hex = set([
+    ('uint8_t', 'icmpv6_code'),
+    ('uint8_t', 'mpls_tc'),
+    ('uint16_t', 'eth_type'),
+    ('uint8_t', 'ip_dscp'),
+    ('uint64_t', 'metadata'),
+    ('uint16_t', 'ingress_tpid'),
+    ('uint16_t', 'egress_tpid'),
+    ('uint32_t', 'xid'),
+    ('uint16_t', 'flags'),
+    ('uint32_t', 'experimenter'),
+    ('uint32_t', 'mask'),
+    ('uint8_t', 'report_mirror_ports'),
+    ('uint64_t', 'datapath_id'),
+    ('uint32_t', 'capabilities'),
+    ('uint32_t', 'actions'),
+    ('uint64_t', 'cookie'),
+    ('uint8_t', 'reason'),
+    ('uint32_t', 'role'),
+    ('uint32_t', 'config'),
+    ('uint32_t', 'advertise'),
+    ('uint32_t', 'advertised'),
+    ('uint32_t', 'supported'),
+    ('uint32_t', 'peer'),
+    ('uint64_t', 'cookie_mask'),
+    ('uint32_t', 'reserved'),
+    ('uint16_t', 'ethertype'),
+    ('uint64_t', 'metadata_mask'),
+    ('uint32_t', 'instructions'),
+    ('uint32_t', 'write_actions'),
+    ('uint32_t', 'apply_actions'),
+    ('uint32_t', 'types'),
+    ('uint32_t', 'actions_all'),
+    ('uint32_t', 'actions_select'),
+    ('uint32_t', 'actions_indirect'),
+    ('uint32_t', 'actions_ff'),
+    ('uint64_t', 'generation_id'),
+    ('uint16_t', 'value_mask'),
+    ('uint32_t', 'value_mask'),
+    ('uint8_t', 'value_mask'),
+    ('uint64_t', 'value_mask'),
+    ('uint64_t', 'write_setfields'),
+    ('uint64_t', 'apply_setfields'),
+    ('uint64_t', 'metadata_match'),
+    ('uint64_t', 'metadata_write'),
+    ('uint32_t', 'packet_in_mask_equal_master'),
+    ('uint32_t', 'packet_in_mask_slave'),
+    ('uint32_t', 'port_status_mask_equal_master'),
+    ('uint32_t', 'port_status_mask_slave'),
+    ('uint32_t', 'flow_removed_mask_equal_master'),
+    ('uint32_t', 'flow_removed_mask_slave'),
+    ('uint32_t', 'band_types'),
+    ('uint16_t', 'bsn_tcp_flags'),
+    ('uint8_t', 'bsn_l2_cache_hit'),
+])
+
+def gen_emitter(cls, m_name, m_type):
+    if (m_type, m_name) in show_override:
+        short_type = show_override[(m_type, m_name)]
+    elif (m_type, m_name) in show_hex:
+        short_type = loxi_utils.type_to_short_name(m_type).replace('u', 'x')
+    else:
+        short_type = loxi_utils.type_to_short_name(m_type)
+    return "LOCI_SHOW_" + short_type;
+
 def gen_obj_show_h(out, name):
     loxi_utils.gen_c_copy_license(out)
     out.write("""
@@ -91,10 +163,10 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             out.write("""\
-int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj);
+int %(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, of_object_t *obj);
 """ % dict(cls=cls, ver_name=loxi_utils.version_to_name(version)))
 
     out.write("""
@@ -130,11 +202,11 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             out.write("""
 int
-%(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, %(cls)s_t *obj)
+%(cls)s_%(ver_name)s_show(loci_writer_f writer, void* cookie, of_object_t *obj)
 {
     int out = 0;
 """ % dict(cls=cls, ver_name=ver_name))
@@ -150,13 +222,11 @@
     %(m_type)s %(v_name)s;
 """  % dict(m_type=m_type, v_name=var_name_map(m_type)))
                     if loxi_utils.class_is_list(m_type):
-                        base_type = loxi_utils.list_to_entry_type(m_type)
-                        out.write("    %s elt;\n    int rv;\n" % base_type)
+                        out.write("    of_object_t elt;\n    int rv;\n")
             for member in members:
                 m_type = member["m_type"]
                 m_name = member["name"]
-                #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type)
-                emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + m_name;
+                emitter = gen_emitter(cls, m_name, m_type)
                 if loxi_utils.skip_member_name(m_name):
                     continue
                 if (loxi_utils.type_is_scalar(m_type) or
@@ -184,7 +254,7 @@
                     sub_cls = m_type[:-2] # Trim _t
                     out.write("""
     %(cls)s_%(m_name)s_bind(obj, &%(v_name)s);
-    out += %(sub_cls)s_%(ver_name)s_show(writer, cookie, &%(v_name)s);
+    out += of_object_show(writer, cookie, &%(v_name)s);
 """ % dict(cls=cls, sub_cls=sub_cls, m_name=m_name,
            v_name=var_name_map(m_type), ver_name=ver_name))
 
@@ -204,8 +274,7 @@
 
     for key, entry in match.of_match_members.items():
         m_type = entry["m_type"]
-        #emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type)
-        emitter = "LOCI_SHOW_" + loxi_utils.type_to_short_name(m_type) + "_" + key;
+        emitter = gen_emitter('of_match', key, m_type)
         out.write("""
     if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(match)) {
         out += writer(cookie, "%(key)s active=");
@@ -233,7 +302,7 @@
                 comma = ","
 
             if (not loxi_utils.class_in_version(cls, version) or
-                    cls in type_maps.inheritance_map):
+                    type_maps.class_is_virtual(cls)):
                 out.write("    unknown_show%s\n" % comma);
             else:
                 out.write("    %s_%s_show%s\n" %
@@ -241,20 +310,20 @@
         out.write("};\n\n")
 
     out.write("""
-static const loci_obj_show_f *const show_funs[5] = {
-    NULL,
-    show_funs_v1,
-    show_funs_v2,
-    show_funs_v3,
-    show_funs_v4
+static const loci_obj_show_f *const show_funs[] = {
+""")
+
+    for version in of_g.of_version_range:
+        out.write("    [%(v)d] = show_funs_v%(v)d,\n" % dict(v=version))
+
+    out.write("""\
 };
 
 int
 of_object_show(loci_writer_f writer, void* cookie, of_object_t *obj)
 {
     if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) {
-        if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_2)) {
-            /* @fixme VERSION */
+        if (OF_VERSION_OKAY(obj->version)) {
             return show_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj);
         } else {
             return writer(cookie, "Bad version %d\\n", obj->version);
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 2f93536..05ff8e2 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -99,11 +99,13 @@
         of_octets_t="octets",
         of_meter_features_t="features",
         of_match_t="match",
-        of_oxm_header_t="oxm",
-        of_bsn_vport_header_t="bsn_vport",
+        of_oxm_t="oxm",
+        of_bsn_vport_t="bsn_vport",
+        of_table_desc_t="table_desc",
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
+        of_bitmap_512_t="bitmap_512",
         of_checksum_128_t="checksum_128",
 	#Circuit extensions
         of_app_code_t="app_code",
@@ -123,10 +125,18 @@
                 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
                 "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t",
                 "of_str64_t","of_app_code_t"]
+                "of_str64_t", "of_bitmap_512_t"]
 
 scalar_types = integer_types[:]
 scalar_types.extend(string_types)
 
+# When embedding an object inside of another object we have to pick a single
+# subclass to use, unlike lists where we use all subclasses.
+embedded_subclasses = {
+    'of_oxm_t': 'of_oxm_eth_type',
+    'of_bsn_vport_t': 'of_bsn_vport_q_in_q',
+}
+
 def ignore_member(cls, version, m_name, m_type):
     """
     Filter out names or types that either don't have accessors
@@ -375,7 +385,7 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls) and not loxi_utils.class_is_list(cls):
                 continue
             out.write("""
 extern int %(cls)s_%(v_name)s_populate(
@@ -388,24 +398,6 @@
     %(cls)s_t *obj, int value);
 """ % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
 
-    out.write("""
-/*
- * Declarations for list population and check primitives
- */
-""")
-
-    for version in of_g.of_version_range:
-        for cls in of_g.ordered_list_objects:
-            if version in of_g.unified[cls]:
-               out.write("""
-extern int
-    list_setup_%(cls)s_%(v_name)s(
-    %(cls)s_t *list, int value);
-extern int
-    list_check_%(cls)s_%(v_name)s(
-    %(cls)s_t *list, int value);
-""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
-
     out.write("\n#endif /* _TEST_COMMON_H_ */\n")
 
 def gen_common_test(out, name):
@@ -480,7 +472,6 @@
 
     gen_fill_string(out)
     gen_scalar_set_check_funs(out)
-    gen_list_set_check_funs(out)
     gen_unified_accessor_funs(out)
 
     gen_ident_tests(out)
@@ -510,7 +501,7 @@
  */
 """ % v_name)
         for cls in of_g.standard_class_order:
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             if version in of_g.unified[cls]:
                 message_scalar_test(out, version, cls)
@@ -523,7 +514,7 @@
     for version in of_g.of_version_range:
         v_name = loxi_utils.version_to_name(version)
         for cls in of_g.standard_class_order:
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             if version in of_g.unified[cls]:
                 test_name = "%s_%s" % (cls, v_name)
@@ -537,7 +528,7 @@
     """
 
     members, member_types = scalar_member_types_get(cls, version)
-    length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
+    length = of_g.base_length[(cls, version)]
     v_name = loxi_utils.version_to_name(version)
 
     out.write("""
@@ -696,6 +687,8 @@
     """
     for version in of_g.of_version_range:
         for cls in of_g.standard_class_order:
+            if type_maps.class_is_virtual(cls):
+                continue
             (members, member_types) = scalar_member_types_get(cls, version)
             scalar_funs_instance(out, cls, version, members, member_types)
 
@@ -705,8 +698,7 @@
     base_type = loxi_utils.list_to_entry_type(cls)
     setup_template = """
     %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
-    %(cls)s_append_bind(list,
-            (%(base_type)s_t *)%(inst)s);
+    %(cls)s_append_bind(list, %(inst)s);
     value = %(subcls)s_%(v_name)s_populate(
         %(inst)s, value);
     cur_len += %(inst)s->length;
@@ -751,110 +743,6 @@
     TEST_OK(%(cls)s_next(list, &elt));
 """ % dict(cls=cls))
 
-def setup_list_fn(out, version, cls):
-    """
-    Generate a helper function that populates a list with two
-    of each type of subclass it supports
-    """
-    out.write("""
-/**
- * Set up a list of type %(cls)s with two of each type of subclass
- */
-int
-list_setup_%(cls)s_%(v_name)s(
-    %(cls)s_t *list, int value)
-{
-""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
-    base_type = loxi_utils.list_to_entry_type(cls)
-    out.write("""
-    %(base_type)s_t elt;
-    int cur_len = 0;
-""" % dict(cls=cls, base_type=base_type))
-
-    sub_classes =  type_maps.sub_class_map(base_type, version)
-    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
-    v_name = loxi_utils.version_to_name(version)
-
-    if len(sub_classes) == 0:
-        out.write("    /* No subclasses for %s */\n"% base_type)
-        out.write("    %s_t *elt_p;\n" % base_type)
-        out.write("\n    elt_p = &elt;\n")
-    else:
-        out.write("    /* Declare pointers for each subclass */\n")
-        for instance, subcls in sub_classes:
-            out.write("    %s_t *%s;\n" % (subcls, instance))
-        out.write("\n    /* Instantiate pointers for each subclass */\n")
-        for instance, subcls in sub_classes:
-            out.write("    %s = &elt.%s;\n" % (instance, instance))
-
-    if len(sub_classes) == 0: # No inheritance case
-        setup_instance(out, cls, base_type, "elt_p", v_name, version)
-    else:
-        for instance, subcls in sub_classes:
-            setup_instance(out, cls, subcls, instance, v_name, version)
-    out.write("""
-
-    return value;
-}
-""")
-
-def check_list_fn(out, version, cls):
-    """
-    Generate a helper function that checks a list populated by above fn
-    """
-    out.write("""
-/**
- * Check a list of type %(cls)s generated by
- * list_setup_%(cls)s_%(v_name)s
- */
-int
-list_check_%(cls)s_%(v_name)s(
-    %(cls)s_t *list, int value)
-{
-""" % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
-    base_type = loxi_utils.list_to_entry_type(cls)
-    out.write("""
-    %(base_type)s_t elt;
-""" % dict(cls=cls, base_type=base_type))
-
-    sub_classes =  type_maps.sub_class_map(base_type, version)
-    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
-    v_name = loxi_utils.version_to_name(version)
-
-    if len(sub_classes) == 0:
-        out.write("    /* No subclasses for %s */\n"% base_type)
-        out.write("    %s_t *elt_p;\n" % base_type)
-        out.write("\n    elt_p = &elt;\n")
-    else:
-        out.write("    /* Declare pointers for each subclass */\n")
-        for instance, subcls in sub_classes:
-            out.write("    %s_t *%s;\n" % (subcls, instance))
-        out.write("\n    /* Instantiate pointers for each subclass */\n")
-        for instance, subcls in sub_classes:
-            out.write("    %s = &elt.%s;\n" % (instance, instance))
-
-    out.write("    TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
-    if len(sub_classes) == 0: # No inheritance case
-        check_instance(out, cls, base_type, "elt_p", v_name, version, True)
-    else:
-        count = 0
-        for instance, subcls in sub_classes:
-            count += 1
-            check_instance(out, cls, subcls, instance, v_name,
-                           version, count==len(sub_classes))
-
-    out.write("""
-    return value;
-}
-""" % dict(base_type=base_type))
-
-def gen_list_set_check_funs(out):
-    for version in of_g.of_version_range:
-        for cls in of_g.ordered_list_objects:
-            if version in of_g.unified[cls]:
-                setup_list_fn(out, version, cls)
-                check_list_fn(out, version, cls)
-
 # Maybe: Get a map from list class to parent, mem_name of container
 
 def list_test(out, version, cls):
@@ -877,7 +765,7 @@
     TEST_ASSERT(list->parent == NULL);
     TEST_ASSERT(list->object_id == %(enum_cls)s);
 
-    value = list_setup_%(cls)s_%(v_name)s(list, value);
+    value = %(cls)s_%(v_name)s_populate(list, value);
     TEST_ASSERT(value != 0);
 """ % dict(cls=cls, base_type=base_type, v_name=loxi_utils.version_to_name(version),
            enum_cls=loxi_utils.enum_name(cls)))
@@ -885,7 +773,7 @@
     out.write("""
     /* Now check values */
     value = 1;
-    value = list_check_%(cls)s_%(v_name)s(list, value);
+    value = %(cls)s_%(v_name)s_check(list, value);
     TEST_ASSERT(value != 0);
 """ % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
 
@@ -959,10 +847,12 @@
 static int
 test_match_1(void)
 {
-    of_match_v1_t *m_v1;
-    of_match_v2_t *m_v2;
-    of_match_v3_t *m_v3;
-    of_match_v4_t *m_v4;
+""")
+
+    for version in of_g.of_version_range:
+        out.write("    of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
+
+    out.write("""\
     of_match_t match;
     int value = 1;
     int idx;
@@ -997,10 +887,12 @@
 static int
 test_match_2(void)
 {
-    of_match_v1_t *m_v1;
-    of_match_v2_t *m_v2;
-    of_match_v3_t *m_v3;
-    of_match_v3_t *m_v4;
+""")
+
+    for version in of_g.of_version_range:
+        out.write("    of_match_v%(v)d_t *m_v%(v)d;\n" % dict(v=version))
+
+    out.write("""\
     of_match_t match1;
     of_match_t match2;
     int value = 1;
@@ -1084,7 +976,7 @@
                 continue
             if type_maps.class_is_virtual(cls):
                 continue
-            bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
+            bytes = of_g.base_length[(cls, version)]
             out.write("""
 static int
 test_%(cls)s_create_%(v_name)s(void)
@@ -1167,15 +1059,24 @@
 """ % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
     base_type = loxi_utils.list_to_entry_type(cls)
     out.write("""
-    %(base_type)s_t elt;
+    of_object_t elt;
     int cur_len = 0;
+    static int recursion;
+    (void) elt;
+    (void) cur_len;
+
+    if (recursion > 0) {
+        return value;
+    }
+
+    recursion++;
 """ % dict(cls=cls, base_type=base_type))
 
     sub_classes =  type_maps.sub_class_map(base_type, version)
     sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
-    if len(sub_classes) == 0:
+    if not type_maps.class_is_virtual(base_type):
         out.write("    /* No subclasses for %s */\n"% base_type)
         out.write("    %s_t *elt_p;\n" % base_type)
         out.write("\n    elt_p = &elt;\n")
@@ -1185,14 +1086,15 @@
             out.write("    %s_t *%s;\n" % (subcls, instance))
         out.write("\n    /* Instantiate pointers for each subclass */\n")
         for instance, subcls in sub_classes:
-            out.write("    %s = &elt.%s;\n" % (instance, instance))
+            out.write("    %s = &elt;\n" % (instance))
 
-    if len(sub_classes) == 0: # No inheritance case
+    if not type_maps.class_is_virtual(base_type): # No inheritance case
         setup_instance(out, cls, base_type, "elt_p", v_name, version)
     else:
         for instance, subcls in sub_classes:
             setup_instance(out, cls, subcls, instance, v_name, version)
     out.write("""
+    recursion--;
     return value;
 }
 """)
@@ -1211,9 +1113,16 @@
 """ % dict(cls=cls, v_name=loxi_utils.version_to_name(version)))
     base_type = loxi_utils.list_to_entry_type(cls)
     out.write("""
-    %(base_type)s_t elt;
+    of_object_t elt;
     int count = 0;
     int rv;
+    static int recursion;
+
+    if (recursion > 0) {
+        return value;
+    }
+
+    recursion++;
 """ % dict(cls=cls, base_type=base_type))
 
 
@@ -1221,7 +1130,7 @@
     sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
-    if len(sub_classes) == 0:
+    if not type_maps.class_is_virtual(base_type):
         entry_count = 2
         out.write("    /* No subclasses for %s */\n"% base_type)
         out.write("    %s_t *elt_p;\n" % base_type)
@@ -1233,10 +1142,12 @@
             out.write("    %s_t *%s;\n" % (subcls, instance))
         out.write("\n    /* Instantiate pointers for each subclass */\n")
         for instance, subcls in sub_classes:
-            out.write("    %s = &elt.%s;\n" % (instance, instance))
+            out.write("    %s = &elt;\n" % (instance))
 
-    out.write("    TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
-    if len(sub_classes) == 0: # No inheritance case
+    if not type_maps.class_is_virtual(base_type) or sub_classes:
+        out.write("    TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
+
+    if not type_maps.class_is_virtual(base_type): # No inheritance case
         check_instance(out, cls, base_type, "elt_p", v_name,
                        version, True)
     else:
@@ -1280,6 +1191,7 @@
         of_object_delete((of_object_t *)dup);
     }
 
+    recursion--;
     return value;
 }
 """ % dict(cls=cls, u_cls=cls.upper(), entry_count=entry_count))
@@ -1304,8 +1216,9 @@
     for m_type in member_types:
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
-        elif m_type == "of_bsn_vport_header_t":
-            out.write("    of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
+        elif m_type in embedded_subclasses:
+            subcls = embedded_subclasses[m_type]
+            out.write("    %s_t *%s;\n" % (subcls, var_name_map(m_type)))
         else:
             out.write("    %s *%s;\n" % (m_type, var_name_map(m_type)))
     out.write("""
@@ -1316,7 +1229,7 @@
         m_name = member["name"]
         if loxi_utils.skip_member_name(m_name):
             continue
-        if m_type == "of_bsn_vport_header_t":
+        if m_type in embedded_subclasses:
             continue
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             out.write("""\
@@ -1366,8 +1279,8 @@
         FREE(octets.data);
     }
 """ % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
-        elif m_type == "of_bsn_vport_header_t": # test q_in_q
-            sub_cls = "of_bsn_vport_q_in_q"
+        elif m_type in embedded_subclasses:
+            sub_cls = embedded_subclasses[m_type]
             out.write("""\
     %(var_name)s = %(sub_cls)s_new(%(v_name)s);
     TEST_ASSERT(%(var_name)s != NULL);
@@ -1446,8 +1359,8 @@
     value = of_octets_check(&%(var_name)s, value);
 """ % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
            v_name=loxi_utils.version_to_name(version)))
-        elif m_type == "of_bsn_vport_header_t": # tests only q_in_q
-            sub_cls = "of_bsn_vport_q_in_q"
+        elif m_type in embedded_subclasses:
+            sub_cls = embedded_subclasses[m_type]
             out.write("""
     { /* Use get/delete to access on check */
         %(sub_cls)s_t *%(m_name)s_ptr;
@@ -1513,7 +1426,7 @@
     """
 
     members, member_types = scalar_member_types_get(cls, version)
-    length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
+    length = of_g.base_length[(cls, version)]
     v_name = loxi_utils.version_to_name(version)
 
     out.write("""
@@ -1568,11 +1481,9 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
-                continue
             elif loxi_utils.class_is_list(cls):
                 gen_list_setup_check(out, cls, version)
-            else:
+            elif not type_maps.class_is_virtual(cls):
                 gen_class_setup_check(out, cls, version)
 
 def gen_unified_accessor_tests(out, name):
@@ -1591,7 +1502,7 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             unified_accessor_test_case(out, cls, version)
 
@@ -1605,7 +1516,7 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             test_name = "%s_%s" % (cls, v_name)
             out.write("    RUN_TEST(%s);\n" % test_name)
@@ -1642,8 +1553,8 @@
 %(cls)s_%(ver_name)s_dup(
     %(cls)s_t *src)
 {
-    %(elt_type)s_t src_elt;
-    %(elt_type)s_t *dst_elt;
+    of_object_t src_elt;
+    of_object_t *dst_elt;
     int rv;
     %(cls)s_t *dst;
 
@@ -1678,20 +1589,21 @@
  *
  * The caller is responsible for deleting the returned value
  */
-%(cls)s_t *
+of_object_t *
 %(cls)s_%(ver_name)s_dup(
-    %(cls)s_t *src)
+    of_object_t *src)
 {
 """ % dict(cls=cls, ver_name=ver_name))
 
     # For each subclass, check if this is an instance of that subclass
-    version_classes = type_maps.inheritance_data[cls][version]
-    for sub_cls in version_classes:
-        sub_enum = (cls + "_" + sub_cls).upper()
+    sub_classes = type_maps.sub_class_map(cls, version)
+    for (_, sub_cls) in sub_classes:
+        sub_enum = sub_cls.upper()
+        if type_maps.class_is_virtual(sub_cls):
+            continue
         out.write("""
-    if (src->header.object_id == %(sub_enum)s) {
-        return (%(cls)s_t *)%(cls)s_%(sub_cls)s_%(ver_name)s_dup(
-            &src->%(sub_cls)s);
+    if (src->object_id == %(sub_enum)s) {
+        return %(sub_cls)s_%(ver_name)s_dup(src);
     }
 """ % dict(sub_cls=sub_cls, ver_name=ver_name, sub_enum=sub_enum, cls=cls))
 
@@ -1731,11 +1643,12 @@
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             # Declare instance of these
             out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
-        elif m_type == "of_bsn_vport_header_t": # test q_in_q
+        elif m_type in embedded_subclasses:
+            sub_cls = embedded_subclasses[m_type]
             out.write("""
-    of_bsn_vport_q_in_q_t src_%(v_name)s;
-    of_bsn_vport_q_in_q_t *dst_%(v_name)s;
-""" % dict(v_name=var_name_map(m_type)))
+    %(sub_cls)s_t src_%(v_name)s;
+    %(sub_cls)s_t *dst_%(v_name)s;
+""" % dict(v_name=var_name_map(m_type), sub_cls=sub_cls))
         else:
             out.write("""
     %(m_type)s src_%(v_name)s;
@@ -1763,8 +1676,8 @@
     %(cls)s_%(m_name)s_get(src, &%(v_name)s);
     %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
 """ % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
-        elif m_type == "of_bsn_vport_header_t": # test q_in_q
-            sub_cls = "of_bsn_vport_q_in_q"
+        elif m_type in embedded_subclasses:
+            sub_cls = embedded_subclasses[m_type]
             out.write("""
     %(cls)s_%(m_name)s_bind(
         src, &src_%(v_name)s);
@@ -1817,11 +1730,11 @@
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_inheritance_root(cls):
                 gen_dup_inheritance(out, cls, version)
             elif loxi_utils.class_is_list(cls):
                 gen_dup_list(out, cls, version)
-            else:
+            elif not type_maps.class_is_virtual(cls):
                 gen_dup_cls(out, cls, version)
 
 def gen_dup(out=sys.stdout):
@@ -1831,22 +1744,26 @@
 
     for cls in of_g.standard_class_order:
         out.write("""
-%(cls)s_t *
+of_object_t *
 %(cls)s_dup(
-    %(cls)s_t *src)
+    of_object_t *src)
 {
 """ % dict(cls=cls))
         for version in of_g.of_version_range:
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            hdr = "header." if cls in type_maps.inheritance_map else ""
-
+            elif type_maps.class_is_inheritance_root(cls):
+                pass
+            elif loxi_utils.class_is_list(cls):
+                pass
+            elif type_maps.class_is_virtual(cls):
+                continue
             ver_name = loxi_utils.version_to_name(version)
             out.write("""
-    if (src->%(hdr)sversion == %(ver_name)s) {
+    if (src->version == %(ver_name)s) {
         return %(cls)s_%(ver_name)s_dup(src);
     }
-""" % dict(cls=cls, ver_name=ver_name, hdr=hdr))
+""" % dict(cls=cls, ver_name=ver_name))
 
         out.write("""
     /* Class not supported in given version */
@@ -1900,20 +1817,26 @@
 
     for cls in of_g.standard_class_order:
         out.write("""
-extern %(cls)s_t *
+extern of_object_t *
     %(cls)s_dup(
-        %(cls)s_t *src);
+        of_object_t *src);
 """ % dict(cls=cls))
 
     for version in of_g.of_version_range:
         for cls in of_g.standard_class_order:
             if not loxi_utils.class_in_version(cls, version):
                 continue
+            elif type_maps.class_is_inheritance_root(cls):
+                pass
+            elif loxi_utils.class_is_list(cls):
+                pass
+            elif type_maps.class_is_virtual(cls):
+                continue
             ver_name = loxi_utils.version_to_name(version)
             out.write("""
-extern %(cls)s_t *
+extern of_object_t *
     %(cls)s_%(ver_name)s_dup(
-        %(cls)s_t *src);
+        of_object_t *src);
 """ % dict(cls=cls, ver_name=ver_name))
 
     out.write("\n#endif /* _OF_DUP_H_ */\n")
@@ -1943,7 +1866,7 @@
         for j, cls in enumerate(of_g.all_class_order):
             if not loxi_utils.class_in_version(cls, version):
                 continue
-            if cls in type_maps.inheritance_map:
+            if type_maps.class_is_virtual(cls):
                 continue
             if cls == "of_bsn_virtual_port_create_request": # test q_in_q
                 out.write("""
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 6c45d4d..36ad5f6 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -64,6 +64,18 @@
 extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
 
+extern void of_port_desc_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_port_desc_wire_length_set(of_object_t *obj, int bytes);
+
+extern void of_port_stats_entry_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_port_stats_entry_wire_length_set(of_object_t *obj, int bytes);
+
+extern void of_queue_stats_entry_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_queue_stats_entry_wire_length_set(of_object_t *obj, int bytes);
+
+extern void of_queue_desc_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_queue_desc_wire_length_set(of_object_t *obj, int bytes);
+
 """)
 
 
@@ -106,44 +118,3 @@
     out.write("""
 };
 """)
-
-
-def gen_extra_length_array(out):
-    """
-    Generate an array giving the extra lengths of all objects/versions
-    @param out The file handle to which to write
-    """
-    out.write("""
-/**
- * An array with the number of bytes in the extra length part
- * of each OF object
- */
-""")
-
-    for version in of_g.of_version_range:
-        out.write("""
-static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
-    -1,   /* of_object is not instantiable */
-""" % version)
-        for i, cls in enumerate(of_g.all_class_order):
-            comma = ","
-            if i == len(of_g.all_class_order) - 1:
-                comma = ""
-            val = "-1" + comma
-            if (cls, version) in of_g.base_length:
-                val = str(of_g.extra_length.get((cls, version), 0)) + comma
-            out.write("    %-5s /* %d: %s */\n" % (val, i + 1, cls))
-        out.write("};\n")
-
-    out.write("""
-/**
- * Unified map of extra length part of each object
- */
-const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
-    NULL,
-""")
-    for version in of_g.of_version_range:
-        out.write("    of_object_extra_len_v%d,\n" % version)
-    out.write("""
-};
-""")
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index ea05826..f052950 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -121,26 +121,12 @@
                 c_code_gen.gen_new_function_definitions(out, uclass.name)
                 c_code_gen.gen_accessor_definitions(out, uclass.name)
 
-# TODO remove header classes and use the corresponding class instead
-def generate_header_classes(install_dir):
-    for cls in of_g.standard_class_order:
-        if cls.find("_header") < 0 or cls in ["of_header", "of_bsn_header", "of_nicira_header"]:
-            continue
-        with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
-            util.render_template(out, "class.c",
-                push_wire_types_data=None,
-                parse_wire_types_data=None)
-            # Append legacy generated code
-            c_code_gen.gen_new_function_definitions(out, cls)
-            c_code_gen.gen_accessor_definitions(out, cls)
-
 def generate_classes_header(install_dir):
     # Collect legacy code
     tmp = StringIO()
     c_code_gen.gen_struct_typedefs(tmp)
     c_code_gen.gen_new_function_declarations(tmp)
     c_code_gen.gen_accessor_declarations(tmp)
-    c_code_gen.gen_generics(tmp)
 
     with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
         util.render_template(out, "loci_classes.h",
@@ -186,7 +172,6 @@
     # Collect legacy code
     tmp = StringIO()
     c_type_maps.gen_length_array(tmp)
-    c_type_maps.gen_extra_length_array(tmp)
 
     with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
         util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
@@ -197,6 +182,14 @@
 class_metadata = []
 class_metadata_dict = {}
 
+# These classes have handwritten C code to get/set their length fields
+# See templates/of_type_maps.c
+special_length_classes = set([
+    'of_packet_queue', 'of_meter_stats', 'of_port_desc',
+    'of_port_stats_entry', 'of_queue_stats_entry',
+    'of_queue_desc',
+])
+
 def build_class_metadata():
     for uclass in loxi_globals.unified.classes:
         wire_length_get = 'NULL'
@@ -207,69 +200,24 @@
         if uclass and not uclass.virtual and uclass.has_type_members:
             wire_type_set = '%s_push_wire_types' % uclass.name
 
+        root = uclass.inheritance_root()
+        if root and root.name != 'of_header':
+            wire_type_get = root.name + '_wire_object_id_get'
+
         if uclass.is_message:
             wire_length_get = 'of_object_message_wire_length_get'
             wire_length_set = 'of_object_message_wire_length_set'
-        elif uclass.is_action:
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_action_wire_object_id_get'
-        elif uclass.is_instanceof('of_bsn_vport'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_bsn_vport_wire_object_id_get'
-        elif uclass.is_action_id:
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_action_id_wire_object_id_get'
-        elif uclass.is_instruction:
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_instruction_wire_object_id_get'
-        elif uclass.is_instanceof('of_instruction_id'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_instruction_id_wire_object_id_get'
-        elif uclass.is_instanceof('of_queue_prop'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_queue_prop_wire_object_id_get'
-        elif uclass.is_instanceof('of_table_feature_prop'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_table_feature_prop_wire_object_id_get'
-        elif uclass.is_instanceof('of_meter_band'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_meter_band_wire_object_id_get'
-        elif uclass.is_instanceof('of_hello_elem'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_hello_elem_wire_object_id_get'
-        elif uclass.is_instanceof('of_bsn_tlv'):
-            wire_length_set = 'of_tlv16_wire_length_set'
-            wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_get = 'of_bsn_tlv_wire_object_id_get'
         elif uclass.is_oxm:
             wire_length_get = 'of_oxm_wire_length_get'
-            wire_type_get = 'of_oxm_wire_object_id_get'
-        elif uclass.name == "of_packet_queue":
-            wire_length_get = 'of_packet_queue_wire_length_get'
-            wire_length_set = 'of_packet_queue_wire_length_set'
-        elif uclass.name == "of_meter_stats":
-            wire_length_get = 'of_meter_stats_wire_length_get'
-            wire_length_set = 'of_meter_stats_wire_length_set'
-        elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
-                "of_flow_stats_entry", "of_bucket", "of_table_features",
-                "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
-                "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
-                "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]:
-            wire_length_get = "of_u16_len_wire_length_get"
-            wire_length_set = "of_u16_len_wire_length_set"
-        elif uclass.name == 'of_match_v3':
+        elif uclass.name in special_length_classes:
+            wire_length_get = '%s_wire_length_get' % uclass.name
+            wire_length_set = '%s_wire_length_set' % uclass.name
+        elif loxi_utils_legacy.class_is_tlv16(uclass.name):
             wire_length_set = 'of_tlv16_wire_length_set'
             wire_length_get = 'of_tlv16_wire_length_get'
-            wire_type_set = 'of_match_v3_push_wire_types'
+        elif loxi_utils_legacy.class_is_u16_len(uclass.name):
+            wire_length_get = "of_u16_len_wire_length_get"
+            wire_length_set = "of_u16_len_wire_length_set"
 
         class_metadata.append(ClassMetadata(
             name=uclass.name,
@@ -278,75 +226,6 @@
             wire_type_get=wire_type_get,
             wire_type_set=wire_type_set))
 
-    class_metadata.extend([
-        ClassMetadata(
-            name="of_action_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_action_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_action_id_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_action_id_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_bsn_vport_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_bsn_vport_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_instruction_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_instruction_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_instruction_id_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_instruction_id_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_queue_prop_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_queue_prop_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_table_feature_prop_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_table_feature_prop_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_meter_band_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_meter_band_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_hello_elem_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_hello_elem_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_bsn_tlv_header",
-            wire_length_set='of_tlv16_wire_length_set',
-            wire_length_get='of_tlv16_wire_length_get',
-            wire_type_get='of_bsn_tlv_wire_object_id_get',
-            wire_type_set='NULL'),
-        ClassMetadata(
-            name="of_oxm_header",
-            wire_length_set='NULL',
-            wire_length_get='of_oxm_wire_length_get',
-            wire_type_get='of_oxm_wire_object_id_get',
-            wire_type_set='NULL'),
-    ])
-
     for metadata in class_metadata:
         class_metadata_dict[metadata.name] = metadata
 
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 4472ffa..0399638 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -37,6 +37,8 @@
 import c_gen.of_g_legacy as of_g
 import tenjin
 from generic_utils import find, memoize
+import loxi_globals
+from loxi_ir import ir
 
 def class_signature(members):
     """
@@ -99,40 +101,49 @@
     """
     Return True if cls_name is an object which uses uint16 for type and length
     """
-    if cls.find("of_action") == 0: # Includes of_action_id classes
-        return True
-    if cls.find("of_instruction") == 0:
-        return True
-    if cls.find("of_queue_prop") == 0:
-        return True
-    if cls.find("of_table_feature_prop") == 0:
-        return True
-    # *sigh*
-    if cls.find("of_meter_band_stats") == 0:  # NOT A TLV
+
+    ofclass = loxi_globals.unified.class_by_name(cls)
+    if not ofclass:
         return False
-    if cls.find("of_meter_band") == 0:
-        return True
-    if cls.find("of_hello_elem") == 0:
-        return True
-    if cls == "of_match_v3":
-        return True
-    if cls == "of_match_v4":
-        return True
-    if cls.find("of_bsn_tlv") == 0:
-        return True
-    if cls.find("of_bsn_vport") == 0:
-        return True
-    return False
+
+    if len(ofclass.members) < 2:
+        return False
+
+    m1 = ofclass.members[0]
+    m2 = ofclass.members[1]
+
+    if not (isinstance(m1, ir.OFTypeMember) or isinstance(m1, ir.OFDiscriminatorMember)):
+        return False
+
+    if not isinstance(m2, ir.OFLengthMember):
+        return False
+
+    if m1.oftype != "uint16_t" or m2.oftype != "uint16_t":
+        return False
+
+    return True
 
 def class_is_u16_len(cls):
     """
     Return True if cls_name is an object which uses initial uint16 length
     """
-    return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
-                   "of_flow_stats_entry", "of_bucket", "of_table_features",
-                   "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
-                   "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
-                   "of_bsn_gentable_desc_stats_entry", "of_bsn_vrf_counter_stats_entry"]
+
+    ofclass = loxi_globals.unified.class_by_name(cls)
+    if not ofclass:
+        return False
+
+    if len(ofclass.members) < 1:
+        return False
+
+    m = ofclass.members[0]
+
+    if not isinstance(m, ir.OFLengthMember):
+        return False
+
+    if m.oftype != "uint16_t":
+        return False
+
+    return True
 
 def class_is_list(cls):
     """
@@ -219,6 +230,10 @@
     """
     return parent + "_" + instance
 
+def class_to_instance(cls, base_cls):
+    assert cls.startswith(base_cls + '_')
+    return cls[len(base_cls)+1:]
+
 def class_is_var_len(cls, version):
     # Match is special case.  Only version 1.2 (wire version 3) is var
     if cls == "of_match":
@@ -283,7 +298,7 @@
     """
     Convert an integer version to the C macro name
     """
-    return "OF_" + of_g.version_names[version]
+    return of_g.of_version_wire2name[version]
 
 def gen_c_copy_license(out):
     """
diff --git a/c_gen/match.py b/c_gen/match.py
index 7b7dcce..c6459d4 100644
--- a/c_gen/match.py
+++ b/c_gen/match.py
@@ -131,6 +131,7 @@
     2: of_v2_keys,
     3: [],
     4: [],
+    5: [],
 }
 
 # Complete list of match keys, sorted by the standard order
@@ -196,8 +197,7 @@
     # Generate list of OXM names from the unified classes
     oxm_names = [x[7:] for x in of_g.unified.keys() if
                  x.startswith('of_oxm_') and
-                 x.find('masked') < 0 and
-                 x.find('header') < 0]
+                 x.find('masked') < 0]
 
     # Check that all OXMs are in the match members
     for key in oxm_names:
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index 0c48edd..caabc1a 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -31,8 +31,7 @@
 # @fixme This needs to be refactored and brought into the 21st century.
 #
 
-import sys
-# @fixme Replace with argparse
+import loxi_globals
 
 ################################################################
 #
@@ -114,6 +113,7 @@
         2: "uint32_t",
         3: "uint32_t",
         4: "uint32_t",
+        5: "uint32_t",
         "short_name":"port_no"
         },
     of_port_desc_t = {
@@ -121,6 +121,7 @@
         2: "of_port_desc_t",
         3: "of_port_desc_t",
         4: "of_port_desc_t",
+        5: "of_port_desc_t",
         "short_name":"port_desc"
         },
     of_bsn_vport_t = {
@@ -128,6 +129,7 @@
         2: "of_bsn_vport_t",
         3: "of_bsn_vport_t",
         4: "of_bsn_vport_t",
+        5: "of_bsn_vport_t",
         "short_name":"bsn_vport"
         },
     of_fm_cmd_t = { # Flow mod command went from u16 to u8
@@ -135,6 +137,7 @@
         2: "uint8_t",
         3: "uint8_t",
         4: "uint8_t",
+        5: "uint8_t",
         "short_name":"fm_cmd"
         },
     of_wc_bmap_t = { # Wildcard bitmap
@@ -142,6 +145,7 @@
         2: "uint32_t",
         3: "uint64_t",
         4: "uint64_t",
+        5: "uint64_t",
         "short_name":"wc_bmap"
         },
     of_match_bmap_t = { # Match bitmap
@@ -149,6 +153,7 @@
         2: "uint32_t",
         3: "uint64_t",
         4: "uint64_t",
+        5: "uint64_t",
         "short_name":"match_bmap"
         },
     of_match_t = { # Match object
@@ -156,6 +161,7 @@
         2: "of_match_v2_t",
         3: "of_match_v3_t",
         4: "of_match_v3_t",  # Currently uses same match as 1.2 (v3).
+        5: "of_match_v3_t",  # Currently uses same match as 1.2 (v3).
         "short_name":"match"
         },
 )
@@ -209,6 +215,7 @@
 #                         short_name="match_v4"),
     of_octets_t = dict(bytes=-1, short_name="octets"),
     of_bitmap_128_t = dict(bytes=16, short_name="bitmap_128"),
+    of_bitmap_512_t = dict(bytes=64, short_name="bitmap_512"),
     of_checksum_128_t = dict(bytes=16, short_name="checksum_128"),
     of_app_code_t = dict(bytes=ofp_constants["OF_APP_CODE_LEN"],
                           short_name="app_code"),
@@ -221,7 +228,7 @@
                    "of_match_bmap_t", "of_port_name_t", "of_table_name_t",
                    "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
                    "of_ipv6_t", "of_ipv4_t", "of_bitmap_128_t", "of_checksum_128_t",
-                   "of_str64_t"]
+                   "of_str64_t", "of_bitmap_512_t"]
 
 ##
 # LOXI identifiers
@@ -273,12 +280,6 @@
 ## Map from class, wire_version to size of fixed part of class
 base_length = {}
 
-## Map from class, wire_version to size of variable-offset, fixed length part of class
-extra_length = {
-    ("of_packet_in", 3): 2,
-    ("of_packet_in", 4): 2,
-}
-
 ## Boolean indication of variable length, per class, wire_version,
 is_fixed_length = set()
 
@@ -292,25 +293,21 @@
 # Indexed by (cls, version, member-name) and value is prev-member-name
 special_offsets = {}
 
-## Define Python variables with integer wire version values
-VERSION_1_0 = 1
-VERSION_1_1 = 2
-VERSION_1_2 = 3
-VERSION_1_3 = 4
-
-version_names = {1:"VERSION_1_0", 2:"VERSION_1_1", 3:"VERSION_1_2",
-                 4:"VERSION_1_3"}
-short_version_names = {1:"OF_1_0", 2:"OF_1_1", 3:"OF_1_2", 4:"OF_1_3"}
+# Map from wire version to OF_1_x
+short_version_names = {}
 
 # The iteration object that gives the wire versions supported
-of_version_range = [VERSION_1_0, VERSION_1_1, VERSION_1_2, VERSION_1_3]
+of_version_range = []
 
-of_version_wire2name = {
-    VERSION_1_0:"OF_VERSION_1_0",
-    VERSION_1_1:"OF_VERSION_1_1",
-    VERSION_1_2:"OF_VERSION_1_2",
-    VERSION_1_3:"OF_VERSION_1_3"
-    }
+# Map from wire version to OF_VERSION_1_x
+of_version_wire2name = {}
+
+for version in loxi_globals.OFVersions.all_supported:
+    v = version.version.replace('.', '_')
+    short_version_names[version.wire_version] = 'OF_' + v
+    of_version_range.append(version.wire_version)
+    of_version_wire2name[version.wire_version] = 'OF_VERSION_' + v
+    globals()['VERSION_' + v] = version.wire_version
 
 
 ################################################################
diff --git a/c_gen/templates/README b/c_gen/templates/README
index 71c4a48..44eedab 100644
--- a/c_gen/templates/README
+++ b/c_gen/templates/README
@@ -60,7 +60,7 @@
     for (i = 1; i <= 4; i++) {
         of_action_output_t action;
         of_action_output_init(&action, flow_add->version, -1, 1);
-        of_list_action_append_bind(&actions, (of_action_t *)&action);
+        of_list_action_append_bind(&actions, &action);
         of_action_output_port_set(&action, i);
     }
 
diff --git a/c_gen/templates/list.c b/c_gen/templates/list.c
index 9ff6e42..5eb45c6 100644
--- a/c_gen/templates/list.c
+++ b/c_gen/templates/list.c
@@ -42,12 +42,11 @@
  */
 
 int
-${cls}_first(${cls}_t *list, ${e_cls}_t *_obj)
+${cls}_first(${cls}_t *list, of_object_t *obj)
 {
     int rv;
-    of_object_t *obj = (of_object_t *)_obj;
 
-    ${e_cls}_init(_obj, list->version, -1, 1);
+    ${e_cls}_init(obj, list->version, -1, 1);
 
     if ((rv = of_list_first(list, obj)) < 0) {
         return rv;
@@ -73,10 +72,9 @@
  */
 
 int
-${cls}_next(${cls}_t *list, ${e_cls}_t *_obj)
+${cls}_next(${cls}_t *list, of_object_t *obj)
 {
     int rv;
-    of_object_t *obj = (of_object_t *)_obj;
 
     if ((rv = of_list_next(list, obj)) < 0) {
         return rv;
@@ -105,9 +103,9 @@
  */
 
 int
-${cls}_append_bind(${cls}_t *list, ${e_cls}_t *obj)
+${cls}_append_bind(${cls}_t *list, of_object_t *obj)
 {
-    return of_list_append_bind(list, (of_object_t *)obj);
+    return of_list_append_bind(list, obj);
 }
 
 /**
@@ -119,7 +117,7 @@
  */
 
 int
-${cls}_append(${cls}_t *list, ${e_cls}_t *obj)
+${cls}_append(${cls}_t *list, of_object_t *obj)
 {
-    return of_list_append(list, (of_object_t *)obj);
+    return of_list_append(list, obj);
 }
diff --git a/c_gen/templates/loci_dump.h b/c_gen/templates/loci_dump.h
index 1344565..89c5f2a 100644
--- a/c_gen/templates/loci_dump.h
+++ b/c_gen/templates/loci_dump.h
@@ -99,6 +99,8 @@
 
 #define LOCI_DUMP_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_DUMP_bitmap_512(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64, (val).words[7], (val).words[6], (val).words[5], (val).words[4], (val).words[3], (val).words[2], (val).words[1], (val).words[0])
+
 /**
  * Generic version for any object
  */
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index 1ea9eeb..eb1c923 100644
--- a/c_gen/templates/loci_int.h
+++ b/c_gen/templates/loci_int.h
@@ -30,6 +30,8 @@
 :: flow_mod = of_g.base_length[("of_flow_modify",of_g.VERSION_1_2)]
 :: packet_in = of_g.base_length[("of_packet_in",of_g.VERSION_1_2)]
 :: packet_in_1_3 = of_g.base_length[("of_packet_in",of_g.VERSION_1_3)]
+:: packet_in_1_4 = of_g.base_length[("of_packet_in",of_g.VERSION_1_4)]
+:: assert packet_in_1_3 == packet_in_1_4
 :: flow_stats = of_g.base_length[("of_flow_stats_entry", of_g.VERSION_1_2)]
 :: match1 = of_g.base_length[("of_match_v1",of_g.VERSION_1_0)]
 :: match2 = of_g.base_length[("of_match_v2",of_g.VERSION_1_1)]
@@ -239,13 +241,16 @@
  * @param obj An object of type of_packet_in_t
  *
  * Get length of preceding match object and add to fixed length
- * Applies only to version 1.2 and 1.3
- * The +2 comes from the 2 bytes of padding between the match and packet data.
+ * Applies only to version 1.2+
+ * There are 2 bytes of padding between the match and data. The
+ * _OFFSET_FOLLOWING_MATCH_V3 macro assumes the match is at the end of the
+ * fixed length, so we need to subtract 2 from the fixed length we pass and
+ * then add 2 to the resulting offset.
  */
 
 #define _PACKET_IN_DATA_OFFSET(obj) \
     (_OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
-${packet_in} : ${packet_in_1_3}) + 2)
+(${packet_in} - 2) : (${packet_in_1_3} - 2)) + 2)
 
 /**
  * Macro to calculate variable offset of data (packet) member in packet_out
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index 3624bcd..dc35959 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -67,61 +67,6 @@
 #define LOCI_SHOW_d32(writer, cookie, val) LOCI_SHOW_D_INT(cookie, PRId32, val)
 #define LOCI_SHOW_d64(writer, cookie, val) LOCI_SHOW_D_INT(cookie, PRId64, val)
 
-
-
-/**
- * Field-specific show macros. 
- */
-#define LOCI_SHOW_u32_ipv6_flabel(writer, cookie, val)     LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_vlan_pcp(writer, cookie, val)         LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_src(writer, cookie, val)        LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_ipv6_ipv6_dst(writer, cookie, val)       LOCI_SHOW_ipv6(writer, cookie, val)
-#define LOCI_SHOW_u32_arp_tpa(writer, cookie, val)         LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_icmpv6_type(writer, cookie, val)      LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_mac_arp_sha(writer, cookie, val)         LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_ipv6_ipv6_src(writer, cookie, val)       LOCI_SHOW_ipv6(writer, cookie, val)
-#define LOCI_SHOW_u16_sctp_src(writer, cookie, val)        LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u8_icmpv6_code(writer, cookie, val)      LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_mac_eth_dst(writer, cookie, val)         LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_mac_ipv6_nd_sll(writer, cookie, val)     LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u8_mpls_tc(writer, cookie, val)          LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_u64_tunnel_id(writer, cookie, val)       LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u16_arp_op(writer, cookie, val)          LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_eth_type(writer, cookie, val)        LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_ipv6_ipv6_nd_target(writer, cookie, val) LOCI_SHOW_ipv6(writer, cookie, val)
-#define LOCI_SHOW_u16_vlan_vid(writer, cookie, val)        LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_mac_arp_tha(writer, cookie, val)         LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_port_no_in_port(writer, cookie, val)     LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_u8_ip_dscp(writer, cookie, val)          LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_u16_sctp_dst(writer, cookie, val)        LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u8_icmpv4_code(writer, cookie, val)      LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_tcp_src(writer, cookie, val)         LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u32_arp_spa(writer, cookie, val)         LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_ip_ecn(writer, cookie, val)           LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_udp_dst(writer, cookie, val)         LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_port_no_in_phy_port(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_dst(writer, cookie, val)        LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_mac_eth_src(writer, cookie, val)         LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u16_udp_src(writer, cookie, val)         LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_mac_ipv6_nd_tll(writer, cookie, val)     LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u8_icmpv4_type(writer, cookie, val)      LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_mpls_label(writer, cookie, val)      LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u16_tcp_dst(writer, cookie, val)         LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u8_ip_proto(writer, cookie, val)         LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u64_metadata(writer, cookie, val)        LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u8_enabled(writer, cookie, val)          LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_vport_no(writer, cookie, val)        LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_port_no(writer, cookie, val)         LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u16_ingress_tpid(writer, cookie, val)    LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_u16_egress_tpid(writer, cookie, val)     LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_u16_ingress_vlan_id(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_egress_vlan_id(writer, cookie, val)  LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u32_enabled(writer, cookie, val)         LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_enable(writer, cookie, val)          LOCI_SHOW_u32(writer, cookie, val)
-
-
-
-
 /* @todo Add checks for special port numbers */
 #define LOCI_SHOW_port_no(writer, cookie, val) writer(cookie, "%d", val)
 #define LOCI_SHOW_fm_cmd(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
@@ -168,253 +113,11 @@
 
 #define LOCI_SHOW_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_SHOW_bitmap_512(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64, (val).words[7], (val).words[6], (val).words[5], (val).words[4], (val).words[3], (val).words[2], (val).words[1], (val).words[0])
+
 /**
  * Generic version for any object
  */
 int of_object_show(loci_writer_f writer, void *cookie, of_object_t *obj);
 
-
-
-
-/**
- * Choose a representation for each field that 
- * makes the most sense for display to the user. 
- */
-#define LOCI_SHOW_u32_xid(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u16_flags(writer, cookie, val) LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_u64_packet_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_byte_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u32_flow_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_match_match(writer, cookie, val) LOCI_SHOW_match(writer, cookie, val)
-#define LOCI_SHOW_u8_table_id(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_port_no_out_port(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_u32_experimenter(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_subtype(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_index(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_mask(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u8_report_mirror_ports(writer, cookie, val) LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_desc_str_mfr_desc(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_desc_str_hw_desc(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_desc_str_sw_desc(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_ser_num_serial_num(writer, cookie, val) LOCI_SHOW_ser_num(writer, cookie, val)
-#define LOCI_SHOW_desc_str_dp_desc(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_desc_str_pipeline(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_octets_data(writer, cookie, val) LOCI_SHOW_octets(writer, cookie, val)
-#define LOCI_SHOW_octets_value(writer, cookie, val) LOCI_SHOW_octets(writer, cookie, val)
-#define LOCI_SHOW_u16_err_type(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_code(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u64_datapath_id(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u32_n_buffers(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_n_tables(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_capabilities(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_actions(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u64_cookie(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u16_idle_timeout(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_hard_timeout(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u32_buffer_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_reason(writer, cookie, val) LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_u32_duration_sec(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_duration_nsec(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u16_miss_send_len(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u32_role(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u16_total_len(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_port_no_port_no(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_port_no_loopback_port_no(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_mac_hw_addr(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u32_config(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_advertise(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_port_no_port(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_u32_queue_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_dest_port(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_vlan_tag(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_copy_stage(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_max_len(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_mac_dl_addr(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u32_nw_addr(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_nw_tos(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_tp_port(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_wc_bmap_wildcards(writer, cookie, val) LOCI_SHOW_wc_bmap(writer, cookie, val)
-#define LOCI_SHOW_port_name_name(writer, cookie, val) LOCI_SHOW_port_name(writer, cookie, val)
-#define LOCI_SHOW_u32_state(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_curr(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_advertised(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_supported(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_peer(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_packets(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_packets_unicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_packets_multicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_packets_broadcast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_uint64_value(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_packets(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_packets_unicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_packets_multicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_packets_broadcast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_bytes(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_bytes(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_dropped(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_dropped(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_errors(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_tx_errors(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_frame_err(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_over_err(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_rx_crc_err(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_collisions(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u16_rate(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_tab_name_name(writer, cookie, val) LOCI_SHOW_tab_name(writer, cookie, val)
-#define LOCI_SHOW_u32_max_entries(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_active_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u64_lookup_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_matched_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u32_out_group(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u64_cookie_mask(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u32_reserved(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u16_command(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u8_group_type(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_group_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u16_ethertype(writer, cookie, val) LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_u8_mpls_ttl(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_nw_ecn(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_nw_ttl(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_weight(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_port_no_watch_port(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_u32_watch_group(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_ref_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u64_metadata_mask(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_mac_eth_src_mask(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_mac_eth_dst_mask(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_src_mask(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_dst_mask(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u32_curr_speed(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_max_speed(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_match_bmap_match(writer, cookie, val) LOCI_SHOW_match_bmap(writer, cookie, val)
-#define LOCI_SHOW_u32_instructions(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_write_actions(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_apply_actions(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_types(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_max_groups_all(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_max_groups_select(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_max_groups_indirect(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_max_groups_ff(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_actions_all(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_actions_select(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_actions_indirect(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_actions_ff(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u64_generation_id(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_octets_field(writer, cookie, val) LOCI_SHOW_octets(writer, cookie, val)
-#define LOCI_SHOW_u16_value(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_value_mask(writer, cookie, val) LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_mac_value(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_mac_value_mask(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u32_value(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_value_mask(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_oxm_header(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u8_value(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_value_mask(writer, cookie, val) LOCI_SHOW_x8(writer, cookie, val)
-#define LOCI_SHOW_port_no_value(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_port_no_value_mask(writer, cookie, val) LOCI_SHOW_port_no(writer, cookie, val)
-#define LOCI_SHOW_ipv6_value(writer, cookie, val) LOCI_SHOW_ipv6(writer, cookie, val)
-#define LOCI_SHOW_ipv6_value_mask(writer, cookie, val) LOCI_SHOW_ipv6(writer, cookie, val)
-#define LOCI_SHOW_u64_value(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_value_mask(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u64_write_setfields(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u64_apply_setfields(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u64_metadata_match(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u64_metadata_write(writer, cookie, val) LOCI_SHOW_x64(writer, cookie, val)
-#define LOCI_SHOW_u32_packet_in_mask_equal_master(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_packet_in_mask_slave(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_port_status_mask_equal_master(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_port_status_mask_slave(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_flow_removed_mask_equal_master(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u32_flow_removed_mask_slave(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u8_auxiliary_id(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_meter_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_rate(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_burst_size(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_prec_level(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u64_packet_band_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_byte_band_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u32_max_meter(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_band_types(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
-#define LOCI_SHOW_u8_max_bands(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_max_color(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u64_packet_in_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u64_byte_in_count(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_octets_experimenter_data(writer, cookie, val) LOCI_SHOW_octets(writer, cookie, val)
-#define LOCI_SHOW_u32_dst(writer, cookie, val)        LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u32_service(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_status(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u16_subtype(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_addr(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_ipv4_ipv4_netmask(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_l2_table_enable(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_l2_table_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_ipv4_value(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_ipv4_value_mask(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_hybrid_enable(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_hybrid_version(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_bitmap_128_value(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
-#define LOCI_SHOW_bitmap_128_value_mask(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
-#define LOCI_SHOW_bitmap_128_bsn_in_ports_128(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
-#define LOCI_SHOW_u32_timeout_ms(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_tx_interval_ms(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_slot_num(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_lag_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_vrf(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_bsn_global_vrf_allowed(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_l3_interface_class_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_l3_src_class_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_l3_dst_class_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u8_convergence_status(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_actor_sys_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_mac_actor_sys_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u16_actor_port_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_actor_port_num(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_actor_key(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_partner_sys_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_mac_partner_sys_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_u16_partner_port_priority(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_partner_port_num(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u16_partner_key(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u64_time_ms(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_desc_str_uri(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_u8_state(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u16_table_id(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
-#define LOCI_SHOW_u32_deleted_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_error_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_checksum_128_checksum(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
-#define LOCI_SHOW_checksum_128_checksum_mask(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
-#define LOCI_SHOW_u32_buckets_size(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_entry_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_num_aux(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u64_checksum(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_egr_port_group_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf0(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf1(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf2(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf3(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf4(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf5(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf6(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_udf7(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u64_counter_id(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
-#define LOCI_SHOW_desc_str_description(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_str64_name(writer, cookie, val) LOCI_SHOW_str64(writer, cookie, val)
-#define LOCI_SHOW_mac_local_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_mac_nh_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
-#define LOCI_SHOW_ipv4_src_ip(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_ipv4_dst_ip(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
-#define LOCI_SHOW_u8_dscp_mode(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_dscp(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u8_ttl(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_vpn(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_rate_limit(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_flags(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_desc_str_image_checksum(write, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_desc_str_startup_config_checksum(write, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
-#define LOCI_SHOW_u16_bsn_tcp_flags(write, cookie, val) LOCI_SHOW_x16(writer, cookie, val)
-#define LOCI_SHOW_u8_loglevel(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
-#define LOCI_SHOW_u32_vrf(write, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-#define LOCI_SHOW_u32_bsn_vlan_xlate_port_group_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
-
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/loci_strings.c b/c_gen/templates/loci_strings.c
index f546e12..165bf56 100644
--- a/c_gen/templates/loci_strings.c
+++ b/c_gen/templates/loci_strings.c
@@ -69,6 +69,12 @@
     }
 };
 
+const of_bitmap_512_t of_bitmap_512_all_ones = {
+    { -1, -1, -1, -1, -1, -1, -1, -1, }
+};
+
+const of_bitmap_512_t of_bitmap_512_all_zeroes;
+
 /** @var of_error_strings
  * The error string map; use abs value to index
  */
diff --git a/c_gen/templates/loci_validator.c b/c_gen/templates/loci_validator.c
index 1f98b21..c4e8b5c 100644
--- a/c_gen/templates/loci_validator.c
+++ b/c_gen/templates/loci_validator.c
@@ -199,7 +199,7 @@
         return ${validator_name(proto.class_by_name('of_header'))}(msg, len, &out_len);
 :: #endfor
     default:
-        VALIDATOR_LOG("Bad version %d", OF_VERSION_1_3);
+        VALIDATOR_LOG("Bad version %d", version);
         return -1;
     }
 }
diff --git a/c_gen/templates/locitest/test_utils.c b/c_gen/templates/locitest/test_utils.c
index 10a6b3d..d078a59 100644
--- a/c_gen/templates/locitest/test_utils.c
+++ b/c_gen/templates/locitest/test_utils.c
@@ -43,12 +43,8 @@
 test_has_outport(void)
 {
     of_list_action_t *list;
-    of_action_t elt;
-    of_action_set_dl_src_t *set_dl_src;
-    of_action_output_t *output;
-
-    set_dl_src = &elt.set_dl_src;
-    output = &elt.output;
+    of_object_t set_dl_src;
+    of_object_t output;
 
     list = of_list_action_new(OF_VERSION_1_0);
     TEST_ASSERT(list != NULL);
@@ -57,25 +53,25 @@
     TEST_ASSERT(!of_action_list_has_out_port(list, 1));
 
     /* Add some other action */
-    of_action_set_dl_src_init(set_dl_src, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)set_dl_src));
+    of_action_set_dl_src_init(&set_dl_src, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &set_dl_src));
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(!of_action_list_has_out_port(list, 1));
 
     /* Add port 2 */
-    of_action_output_init(output, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)output));
-    of_action_output_port_set(output, 2);
+    of_action_output_init(&output, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &output));
+    of_action_output_port_set(&output, 2);
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(!of_action_list_has_out_port(list, 1));
     TEST_ASSERT(of_action_list_has_out_port(list, 2));
 
     /* Add port 1 */
-    of_action_output_init(output, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)output));
-    of_action_output_port_set(output, 1);
+    of_action_output_init(&output, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &output));
+    of_action_output_port_set(&output, 1);
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(of_action_list_has_out_port(list, 1));
@@ -88,26 +84,26 @@
     TEST_ASSERT(list != NULL);
 
     /* Add port 2 */
-    of_action_output_init(output, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)output));
-    of_action_output_port_set(output, 2);
+    of_action_output_init(&output, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &output));
+    of_action_output_port_set(&output, 2);
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(!of_action_list_has_out_port(list, 1));
     TEST_ASSERT(of_action_list_has_out_port(list, 2));
 
     /* Add some other action */
-    of_action_set_dl_src_init(set_dl_src, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)set_dl_src));
+    of_action_set_dl_src_init(&set_dl_src, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &set_dl_src));
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(!of_action_list_has_out_port(list, 1));
     TEST_ASSERT(of_action_list_has_out_port(list, 2));
 
     /* Add port 1 */
-    of_action_output_init(output, OF_VERSION_1_0, -1, 1);
-    TEST_OK(of_list_action_append_bind(list, (of_action_t *)output));
-    of_action_output_port_set(output, 1);
+    of_action_output_init(&output, OF_VERSION_1_0, -1, 1);
+    TEST_OK(of_list_action_append_bind(list, &output));
+    of_action_output_port_set(&output, 1);
 
     TEST_ASSERT(of_action_list_has_out_port(list, OF_PORT_DEST_WILDCARD));
     TEST_ASSERT(of_action_list_has_out_port(list, 1));
diff --git a/c_gen/templates/locitest/test_validator.c b/c_gen/templates/locitest/test_validator.c
index a4b55eb..fde5cba 100644
--- a/c_gen/templates/locitest/test_validator.c
+++ b/c_gen/templates/locitest/test_validator.c
@@ -88,9 +88,9 @@
     of_message_t msg; 
     of_flow_modify_actions_bind(obj, &list);
     of_action_set_tp_dst_init(&element1, OF_VERSION_1_0, -1, 1);
-    of_list_action_append_bind(&list, (of_action_t *)&element1);
+    of_list_action_append_bind(&list, &element1);
     of_action_output_init(&element2, OF_VERSION_1_0, -1, 1);
-    of_list_action_append_bind(&list, (of_action_t *)&element2);
+    of_list_action_append_bind(&list, &element2);
     msg = OF_OBJECT_TO_MESSAGE(obj);
 
     TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == 0);
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 5647d81..574db27 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -521,7 +521,7 @@
     obj->wbuf = NULL;
 }
 
-#define _MAX_PARENT_ITERATIONS 4
+#define _MAX_PARENT_ITERATIONS 8
 /**
  * Iteratively update parent lengths thru hierarchy
  * @param obj The object whose length is being updated
@@ -581,9 +581,6 @@
     if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t id;
         loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
-        if (!of_wire_id_valid(id, base_object_id)) {
-            return OF_ERROR_PARSE;
-        }
         obj->object_id = id;
         /* Call the init function for this object type; do not push to wire */
         of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 9fa59e0..3fcf024 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -305,3 +305,173 @@
     of_wire_buffer_u16_set(wbuf, 
         OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET), bytes);
 }
+
+/**
+ * Get the wire length for a port desc object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_port_desc_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 4),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a port desc object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_port_desc_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 4),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}
+
+/**
+ * Get the wire length for a port stats_entry object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_port_stats_entry_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a port stats_entry object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_port_stats_entry_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}
+
+/**
+ * Get the wire length for a queue stats_entry object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_queue_stats_entry_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a queue stats_entry object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_queue_stats_entry_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}
+
+/**
+ * Get the wire length for a queue_desc object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ */
+void
+of_queue_desc_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 8), &u16);
+    *bytes = u16;
+}
+
+/**
+ * Set the wire length for a queue_desc object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ */
+
+void
+of_queue_desc_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 8), bytes);
+}
diff --git a/c_gen/templates/of_utils.c b/c_gen/templates/of_utils.c
index 373ad59..bddbc8d 100644
--- a/c_gen/templates/of_utils.c
+++ b/c_gen/templates/of_utils.c
@@ -54,7 +54,7 @@
 int
 of_action_list_has_out_port(of_list_action_t *actions, of_port_no_t outport)
 {
-    of_action_t elt;
+    of_object_t elt;
     of_action_output_t *output;
     int loop_rv;
     of_port_no_t port_no;
@@ -64,7 +64,7 @@
         return 1;
     }
 
-    output = &elt.output;
+    output = &elt;
     OF_LIST_ACTION_ITER(actions, &elt, loop_rv) {
         if (output->object_id == OF_ACTION_OUTPUT) {
             of_action_output_port_get(output, &port_no);
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index 0922a69..9ade2c4 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -469,14 +469,10 @@
         of_wire_buffer_u16_get(wbuf, offset, &v16);
         *value = v16;
         break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u32_get(wbuf, offset, &v32);
         *value = v32;
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -498,13 +494,9 @@
     case OF_VERSION_1_0:
         of_wire_buffer_u16_set(wbuf, offset, (uint16_t)value);
         break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u32_set(wbuf, offset, (uint32_t)value);
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -527,14 +519,10 @@
         of_wire_buffer_u16_get(wbuf, offset, &v16);
         *value = v16;
         break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u8_get(wbuf, offset, &v8);
         *value = v8;
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -553,13 +541,9 @@
     case OF_VERSION_1_0:
         of_wire_buffer_u16_set(wbuf, offset, (uint16_t)value);
         break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u8_set(wbuf, offset, (uint8_t)value);
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -583,13 +567,10 @@
         of_wire_buffer_u32_get(wbuf, offset, &v32);
         *value = v32;
         break;
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u64_get(wbuf, offset, &v64);
         *value = v64;
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -609,12 +590,9 @@
     case OF_VERSION_1_1:
         of_wire_buffer_u32_set(wbuf, offset, (uint32_t)value);
         break;
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
+    default:
         of_wire_buffer_u64_set(wbuf, offset, (uint64_t)value);
         break;
-    default:
-        LOCI_ASSERT(0);
     }
 }
 
@@ -910,6 +888,45 @@
 #define of_wire_buffer_checksum_128_set(buf, offset, checksum) \
     (of_wire_buffer_u64_set(buf, offset, checksum.hi), of_wire_buffer_u64_set(buf, offset+8, checksum.lo))
 
+
+/**
+ * Get a bitmap_512 from a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param value Pointer to where to put value
+ *
+ * The underlying buffer accessor funtions handle endian and alignment.
+ */
+
+static inline void
+of_wire_buffer_bitmap_512_get(of_wire_buffer_t *wbuf, int offset, of_bitmap_512_t *value)
+{
+    OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + (int) sizeof(of_bitmap_512_t));
+    int i;
+    for (i = 0; i < 8; i++) {
+        buf_u64_get(OF_WIRE_BUFFER_INDEX(wbuf, offset+i*8), &value->words[i]);
+    }
+}
+
+/**
+ * Set a bitmap_512 in a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param value The value to store
+ *
+ * The underlying buffer accessor funtions handle endian and alignment.
+ */
+
+static inline void
+of_wire_buffer_bitmap_512_set(of_wire_buffer_t *wbuf, int offset, of_bitmap_512_t value)
+{
+    OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + (int) sizeof(of_bitmap_512_t));
+    int i;
+    for (i = 0; i < 8; i++) {
+        buf_u64_set(OF_WIRE_BUFFER_INDEX(wbuf, offset+i*8), value.words[i]);
+    }
+}
+
 /* Relocate data from start offset to the end of the buffer to a new position */
 static inline void
 of_wire_buffer_move_end(of_wire_buffer_t *wbuf, int start_offset, int new_offset)
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 7b745a6..607814c 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -25,432 +25,37 @@
 # EPL for the specific language governing permissions and limitations
 # under the EPL.
 
-#
-# Miscellaneous type information
-#
-# Define the map between sub-class types and wire values.  In each
-# case, an array indexed by wire version gives a hash from identifier
-# to wire value.
-#
-
-import c_gen.of_g_legacy as of_g
-import sys
 from generic_utils import *
-import loxi_utils.loxi_utils as loxi_utils
 import c_gen.loxi_utils_legacy as loxi_utils
 import loxi_globals
 
-invalid_type = "invalid_type"
-
-################################################################
-#
-# Define type data for inheritance classes:
-#   instructions, actions, queue properties and OXM
-#
-# Messages are not in this group; they're treated specially for now
-#
-# These are indexed by wire protocol number
-#
-################################################################
-
-instruction_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-instruction_id_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-action_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-action_id_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-queue_prop_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-bsn_vport_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-oxm_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-hello_elem_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-table_feature_prop_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-meter_band_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-bsn_tlv_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-# All inheritance data for non-messages
-inheritance_data = dict(
-    of_instruction = instruction_types,
-    of_instruction_id = instruction_id_types,
-    of_action = action_types,
-    of_action_id = action_id_types,
-    of_oxm = oxm_types,
-    of_queue_prop = queue_prop_types,
-    of_hello_elem = hello_elem_types,
-    of_table_feature_prop = table_feature_prop_types,
-    of_meter_band = meter_band_types,
-    # BSN specific inheritance extensions
-    of_bsn_vport = bsn_vport_types,
-    of_bsn_tlv = bsn_tlv_types,
-    )
+# map from inheritance root class name to set of subclass names
+inheritance_map = {}
 
 def class_is_virtual(cls):
     """
     Returns True if cls is a virtual class
     """
-    if cls.find("header") > 0:
-        return True
     if loxi_utils.class_is_list(cls):
         return True
     return loxi_globals.unified.class_by_name(cls).virtual
 
-################################################################
-#
-# These are message types
-#
-################################################################
-
-# The hardcoded message types are for inheritance parents
-message_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(
-        error_msg               = 1,
-        experimenter            = 4,
-        flow_mod                = 14,
-        stats_request           = 16,
-        stats_reply             = 17,
-        ),
-
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        error_msg               = 1,
-        experimenter            = 4,
-        flow_mod                = 14,
-        group_mod               = 15,
-        stats_request           = 18,
-        stats_reply             = 19,
-        ),
-
-    # version 1.2
-    of_g.VERSION_1_2:dict(
-        error_msg               = 1,
-        experimenter            = 4,
-        flow_mod                = 14,
-        group_mod               = 15,
-        stats_request           = 18,
-        stats_reply             = 19,
-        ),
-
-    # version 1.3
-    of_g.VERSION_1_3:dict(
-        error_msg               = 1,
-        experimenter            = 4,
-        flow_mod                = 14,
-        group_mod               = 15,
-        stats_request           = 18,  # FIXME Multipart
-        stats_reply             = 19,
-        )
-    }
-
-################################################################
-#
-# These are other objects that have a notion of type but are
-# not (yet) promoted to objects with inheritance
-#
-################################################################
-
-stats_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(
-        desc = 0,
-        flow = 1,
-        aggregate = 2,
-        table = 3,
-        port = 4,
-        queue = 5,
-        experimenter = 0xffff
-        ),
-
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        desc = 0,
-        flow = 1,
-        aggregate = 2,
-        table = 3,
-        port = 4,
-        queue = 5,
-        group = 6,
-        group_desc = 7,
-        experimenter = 0xffff
-        ),
-
-    # version 1.2
-        of_g.VERSION_1_2:dict(
-        desc = 0,
-        flow = 1,
-        aggregate = 2,
-        table = 3,
-        port = 4,
-        queue = 5,
-        group = 6,
-        group_desc = 7,
-        group_features = 8,
-        experimenter = 0xffff
-        ),
-
-    # version 1.3
-        of_g.VERSION_1_3:dict(
-        desc = 0,
-        flow = 1,
-        aggregate = 2,
-        table = 3,
-        port = 4,
-        queue = 5,
-        group = 6,
-        group_desc = 7,
-        group_features = 8,
-        meter = 9,
-        meter_config = 10,
-        meter_features = 11,
-        table_features = 12,
-        port_desc = 13,
-        experimenter = 0xffff,
-        bsn_lacp = 0xffff,
-        bsn_switch_pipeline = 0xffff,
-        bsn_port_counter = 0xffff,
-        bsn_vlan_counter = 0xffff
-        )
-    }
-
-common_flow_mod_types = dict(
-    add = 0,
-    modify = 1,
-    modify_strict = 2,
-    delete = 3,
-    delete_strict = 4
-    )
-
-flow_mod_types = {
-    # version 1.0
-    of_g.VERSION_1_0:common_flow_mod_types,
-    of_g.VERSION_1_1:common_flow_mod_types,
-    of_g.VERSION_1_2:common_flow_mod_types,
-    of_g.VERSION_1_3:common_flow_mod_types
-    }
-
-# These do not translate to objects (yet)
-error_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(
-        hello_failed        = 0,
-        bad_request         = 1,
-        bad_action          = 2,
-        flow_mod_failed     = 3,
-        port_mod_failed     = 4,
-        queue_op_failed     = 5
-        ),
-
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        hello_failed         = 0,
-        bad_request          = 1,
-        bad_action           = 2,
-        bad_instruction      = 3,
-        bad_match            = 4,
-        flow_mod_failed      = 5,
-        group_mod_failed     = 6,
-        port_mod_failed      = 7,
-        table_mod_failed     = 8,
-        queue_op_failed      = 9,
-        switch_config_failed = 10
-        ),
-
-    # version 1.2
-    of_g.VERSION_1_2:dict(
-        hello_failed         = 0,
-        bad_request          = 1,
-        bad_action           = 2,
-        bad_instruction      = 3,
-        bad_match            = 4,
-        flow_mod_failed      = 5,
-        group_mod_failed     = 6,
-        port_mod_failed      = 7,
-        table_mod_failed     = 8,
-        queue_op_failed      = 9,
-        switch_config_failed = 10,
-        role_request_failed  = 11,
-        experimenter = 0xffff
-        ),
-
-    # version 1.3
-    of_g.VERSION_1_3:dict(
-        hello_failed         = 0,
-        bad_request          = 1,
-        bad_action           = 2,
-        bad_instruction      = 3,
-        bad_match            = 4,
-        flow_mod_failed      = 5,
-        group_mod_failed     = 6,
-        port_mod_failed      = 7,
-        table_mod_failed     = 8,
-        queue_op_failed      = 9,
-        switch_config_failed = 10,
-        role_request_failed  = 11,
-        meter_mod_failed     = 12,
-        table_features_failed= 13,
-        experimenter = 0xffff
-        )
-    }
-
-group_mod_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(),
-
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        add = 0,
-        modify = 1,
-        delete = 2
-        ),
-
-    # version 1.2
-    of_g.VERSION_1_2:dict(
-        add = 0,
-        modify = 1,
-        delete = 2
-        ),
-
-    # version 1.3
-    of_g.VERSION_1_3:dict(
-        add = 0,
-        modify = 1,
-        delete = 2
-        )
-    }
-
-################################################################
-#
-# type_val is the primary data structure that maps an
-# (class_name, version) pair to the wire data type value
-#
-################################################################
-
-type_val = dict()
-inheritance_map = dict()
+def class_is_inheritance_root(cls):
+    return cls in inheritance_map
 
 def generate_maps():
-    for parent, versioned in inheritance_data.items():
-        inheritance_map[parent] = set()
-        for ver, subclasses in versioned.items():
-            for subcls in subclasses:
-                inheritance_map[parent].add(subcls)
+    for ofclass in loxi_globals.unified.classes:
+        if ofclass.virtual and not ofclass.superclass:
+            inheritance_map[ofclass.name] = set()
 
-    for version, classes in message_types.items():
-        for cls in classes:
-            name = "of_" + cls
-            type_val[(name, version)] = classes[cls]
+    for version, protocol in loxi_globals.ir.items():
+        wire_version = version.wire_version
+        for ofclass in protocol.classes:
+            root = ofclass.inheritance_root()
+            if not root or root == ofclass or root.name == "of_header":
+                continue
 
-    for parent, versioned in inheritance_data.items():
-        for version, subclasses in versioned.items():
-            for subcls, value in subclasses.items():
-                name = parent + "_" + subcls
-                type_val[(name, version)] = value
-
-    # Special case OF-1.2 match type
-    type_val[("of_match_v3", of_g.VERSION_1_2)] = 1
-    type_val[("of_match_v3", of_g.VERSION_1_3)] = 1
-
-# Utility function
-def dict_to_array(d, m_val, def_val=-1):
-    """
-    Given a dictionary, d, with each value a small integer,
-    produce an array indexed by the integer whose value is the key.
-    @param d The dictionary
-    @param m_val Ignore values greater than m_val
-    @param def_val The default value (for indices not in range of d)
-    """
-
-    # Get the max value in range for hash
-    max_val = 0
-    for key in d:
-        if (d[key] > max_val) and (d[key] < m_val):
-            max_val = d[key]
-    ar = []
-    for x in range(0, max_val + 1):
-        ar.append(def_val)
-    for key in d:
-        if (d[key] < m_val):
-            ar[d[key]] = key
-    return ar
-
-def type_array_len(version_indexed, max_val):
-    """
-    Given versioned information about a type, calculate how long
-    the unified array should be.
-
-    @param version_indexed A dict indexed by version. Each value is a
-    dict indexed by a name and whose value is an integer
-    @param max_val Ignore values greater than this for length calcs
-    """
-    # First, find the max length of all arrays
-    arr_len = 0
-    for version, val_dict in version_indexed.items():
-        ar = dict_to_array(val_dict, max_val, invalid_type)
-        if arr_len < len(ar):
-            arr_len = len(ar)
-    return arr_len
+            inheritance_map[root.name].add(ofclass.name)
 
 def sub_class_map(base_type, version):
     """
@@ -461,99 +66,10 @@
     if base_type not in inheritance_map:
         return rv
 
-    for instance in inheritance_map[base_type]:
-        subcls = loxi_utils.instance_to_class(instance, base_type)
+    for subcls in inheritance_map[base_type]:
         if not loxi_utils.class_in_version(subcls, version):
             continue
+        instance = loxi_utils.class_to_instance(subcls, base_type)
         rv.append((instance, subcls))
 
     return rv
-
-################################################################
-#
-# Extension related data and functions
-#
-################################################################
-
-# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
-# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
-extension_message_subtype = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(  # Version 1.0 extensions
-        bsn = {   # BSN extensions; indexed by class name, value is subtype
-            },
-        nicira = {   # Nicira extensions, value is subtype
-            },
-        ),
-    of_g.VERSION_1_1:dict(  # Version 1.0 extensions
-        bsn = {   # BSN extensions; indexed by class name, value is subtype
-            },
-        ),
-    of_g.VERSION_1_2:dict(  # Version 1.0 extensions
-        bsn = {   # BSN extensions; indexed by class name, value is subtype
-            },
-        ),
-    of_g.VERSION_1_3:dict(  # Version 1.0 extensions
-        bsn = {   # BSN extensions; indexed by class name, value is subtype
-            },
-        ),
-}
-
-# Set to empty dict if no extension actions defined
-# Per OF Version, per experimenter, map actions to subtype
-extension_action_subtype = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(  # Version 1.0 extensions
-        bsn = {   # of_action_bsn_
-            },
-        nicira = {   # of_action_nicira_
-            }
-        ),
-    of_g.VERSION_1_1:dict(  # Version 1.0 extensions
-        bsn = {   # of_action_bsn_
-            },
-        nicira = {   # of_action_nicira_
-            }
-        ),
-    of_g.VERSION_1_2:dict(  # Version 1.0 extensions
-        bsn = {   # of_action_bsn_
-            },
-        nicira = {   # of_action_nicira_
-            }
-        ),
-    of_g.VERSION_1_3:dict(  # Version 1.0 extensions
-        bsn = {   # of_action_bsn_
-            },
-        nicira = {   # of_action_nicira_
-            }
-        ),
-}
-
-# Set to empty dict if no extension actions defined
-# Per OF Version, per experimenter, map actions to subtype
-extension_action_id_subtype = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(  # Version 1.3 extensions
-        bsn = {   # of_action_bsn_
-            },
-        nicira = {   # of_action_nicira_
-            }
-        ),
-}
-
-# Set to empty dict if no extension instructions defined
-extension_instruction_subtype = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(
-        bsn = {   # of_instruction_bsn_
-            },
-        nicira = {   # of_instruction_nicira_
-            }
-        ),
-}
diff --git a/cmdline.py b/cmdline.py
index 6395fff..de7070a 100644
--- a/cmdline.py
+++ b/cmdline.py
@@ -33,7 +33,7 @@
 # The default configuration dictionary for LOXI code generation
 options_default = {
     "lang"               : "c",
-    "version-list"       : "1.0 1.1 1.2 1.3",
+    "version-list"       : "1.0 1.1 1.2 1.3 1.4",
     "install-dir"        : "loxi_output",
 }
 
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 8726632..c8f70e6 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -184,14 +184,25 @@
     @memoize
     def enums(self):
         name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
+        name_stable_map = {}
 
         for version in self.versions:
-            logger.info("version: {}".format(version.ir_version))
+            logger.debug("version: {}".format(version.ir_version))
             of_protocol = loxi_globals.ir[version.ir_version]
             for enum in of_protocol.enums:
                 name_version_enum_map[enum.name][version] = enum
+                stable = (enum.params.get('stable') == 'True')
 
-        enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
+                logger.debug("Enum: %s stable: %s", enum.name, stable)
+
+                if not enum.name in name_stable_map:
+                    name_stable_map[enum.name] = stable
+                else:
+                    if name_stable_map[enum.name] != stable:
+                        raise Exception("Inconsistent enum stability (should be caught " +\
+                            " by IR)")
+
+        enums = [ JavaEnum(name, name_stable_map[name], version_enum_map) for name, version_enum_map,
                         in name_version_enum_map.items() ]
 
         # inelegant - need java name here
@@ -402,6 +413,9 @@
                 reply_name = m.group(1) + "Reply"
                 if model.interface_by_name(reply_name):
                     return ["OFRequest<%s>" % reply_name ]
+            elif self.name == "OFBundleCtrlMsg":
+                reply_name = "OFBundleCtrlMsg"
+                return ["OFRequest<%s>" % reply_name ]
         return []
 
 
@@ -573,6 +587,8 @@
             if not find(lambda x: x.name == "mask", self.ir_model_members):
                 virtual_members.append(
                         JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
+        elif self.name =="OFErrorMsg":
+            virtual_members += [ JavaVirtualMember(self, "data", java_type.error_cause_data) ]
 
         if not find(lambda m: m.name == "version", self.ir_model_members):
             virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
@@ -815,7 +831,7 @@
             entry = enum.entry_by_version_value(self.msg.version, self.value)
             return "%s.%s" % ( enum.name, entry.name)
         except KeyError, e:
-            logger.debug("No enum found", e)
+            logger.debug("No enum found for type %s version %s value %s", java_type, self.msg.version, self.value)
             return self.value
 
     @property
@@ -1041,8 +1057,9 @@
 #######################################################################
 
 class JavaEnum(object):
-    def __init__(self, c_name, version_enum_map):
+    def __init__(self, c_name, stable, version_enum_map):
         self.c_name = c_name
+        self.stable = stable
 
         self.name   = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
 
@@ -1062,7 +1079,23 @@
         self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
         self.package = "org.projectfloodlight.openflow.protocol"
 
-        self.metadata = model.enum_metadata_map[self.name]
+        static_metadata = model.enum_metadata_map[self.name]
+        if self.stable:
+            # need this to look up wire_type, which does not matter
+            any_version = version_enum_map.keys()[0]
+            # if this is a 'stable' enum, i.e., its value won't change, add
+            # a "Metadata" (virtual) field "StableValue" to it that returns
+            # its wirevalue.
+            stable_value = JavaModel.OFEnumPropertyMetadata("StableValue",
+                    self.wire_type(any_version),
+                    value = lambda entry: entry.stable_value)
+
+            self.metadata = JavaModel.OFEnumMetadata(
+                              properties=static_metadata.properties + (stable_value, ),
+                              to_string=static_metadata.to_string
+                            )
+        else:
+            self.metadata = static_metadata
 
     def wire_type(self, version):
         ir_enum = self.version_enums[version]
@@ -1113,7 +1146,7 @@
 
     @property
     def constructor_params(self):
-        return [ m.value(self) for m in self.enum.metadata.properties ]
+        return [ (m.type, m.value(self)) for m in self.enum.metadata.properties ]
 
     def has_value(self, version):
         return version in self.values
@@ -1129,6 +1162,13 @@
         return [ self.values[version] if version in self.values else not_present for version in versions ]
 
     @property
+    def stable_value(self):
+        if self.enum.stable:
+            return self.values.values()[0]
+        else:
+            raise Exception("Enum {} not stable".format(self.enum.name))
+
+    @property
     @memoize
     def masked_enum_group(self):
         group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 5ff987d..900aa6d 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -53,9 +53,12 @@
         signed-craziness
     """
     signed, bits, cast_needed = java_primitives_info[t]
+    if t == 'boolean':
+        return "true" if bool(value) and value not in("False", "false") else "false"
+
     max = (1 << bits)-1
     if value > max:
-        raise Exception("Value %d to large for type %s" % (value, t))
+        raise Exception("Value %s to large for type %s" % (value, t))
 
     if signed:
         max_pos = (1 << (bits-1)) - 1
@@ -361,10 +364,20 @@
         .op(read="IPv4Address.read4Bytes(bb)", \
             write="$name.write4Bytes(bb)",
             default='IPv4Address.NONE')
+ipv4_list =  JType('List<IPv4Address>') \
+        .op(read='ChannelUtils.readList(bb, $length, IPv4Address.READER)',
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<IPv4Address>of()',
+            funnel="FunnelUtils.putList($name, sink)")
 ipv6 = JType("IPv6Address") \
         .op(read="IPv6Address.read16Bytes(bb)", \
             write="$name.write16Bytes(bb)",
             default='IPv6Address.NONE')
+ipv6_list =  JType('List<IPv46ddress>') \
+        .op(read='ChannelUtils.readList(bb, $length, IPv6Address.READER)',
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<IPv6Address>of()',
+            funnel="FunnelUtils.putList($name, sink)")
 packetin_reason = gen_enum_jtype("OFPacketInReason")
 transport_port = JType("TransportPort")\
         .op(read="TransportPort.read2Bytes(bb)",
@@ -437,10 +450,14 @@
 table_stats_wildcards = JType("int") \
         .op(read='bb.readInt()',
             write='bb.writeInt($name)')
-port_bitmap = JType('OFBitMask128') \
+port_bitmap_128 = JType('OFBitMask128') \
             .op(read='OFBitMask128.read16Bytes(bb)',
                 write='$name.write16Bytes(bb)',
                 default='OFBitMask128.NONE')
+port_bitmap_512 = JType('OFBitMask512') \
+            .op(read='OFBitMask512.read64Bytes(bb)',
+                write='$name.write64Bytes(bb)',
+                default='OFBitMask512.NONE')
 table_id = JType("TableId") \
         .op(read='TableId.readByte(bb)',
             write='$name.writeByte(bb)',
@@ -458,6 +475,10 @@
 
 port_speed = JType("PortSpeed")
 error_type = JType("OFErrorType")
+of_message = JType("OFMessage")\
+            .op(read="OFMessageVer$version.READER.readFrom(bb)",
+                write="$name.writeTo(bb)")
+
 of_type = JType("OFType", 'byte') \
             .op(read='bb.readByte()', write='bb.writeByte($name)')
 action_type= gen_enum_jtype("OFActionType")\
@@ -505,6 +526,10 @@
         .op(read='GenTableId.read2Bytes(bb)',
             write='$name.write2Bytes(bb)',
            )
+bundle_id = JType("BundleId") \
+        .op(read='BundleId.read4Bytes(bb)',
+            write='$name.write4Bytes(bb)',
+           )
 udf = JType("UDF") \
          .op(version=ANY, read="UDF.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="UDF.ZERO")
 error_cause_data = JType("OFErrorCauseData") \
@@ -519,6 +544,10 @@
 
 generic_t = JType("T")
 
+table_desc = JType('OFTableDesc') \
+        .op(read='OFTableDescVer$version.READER.readFrom(bb)', \
+            write='$name.writeTo(bb)')
+
 
 default_mtype_to_jtype_convert_map = {
         'uint8_t' : u8,
@@ -535,6 +564,8 @@
         'list(of_uint32_t)' : u32_list,
         'list(of_uint8_t)' : u8_list,
         'list(of_oxm_t)' : oxm_list,
+        'list(of_ipv4_t)' : ipv4_list,
+        'list(of_ipv6_t)' : ipv6_list,
         'of_octets_t' : octets,
         'of_match_t': of_match,
         'of_fm_cmd_t': flow_mod_cmd,
@@ -550,11 +581,13 @@
         'of_wc_bmap_t': flow_wildcards,
         'of_oxm_t': oxm,
         'of_meter_features_t': meter_features,
-        'of_bitmap_128_t': port_bitmap,
+        'of_bitmap_128_t': port_bitmap_128,
+        'of_bitmap_512_t': port_bitmap_512,
         'of_checksum_128_t': u128,
         'of_bsn_vport_t': bsn_vport,
         'of_app_code_t': app_code,  
         'of_sig_id_t': sig_id,
+        'of_table_desc_t': table_desc,
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
@@ -608,9 +641,18 @@
         'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
         'of_oxm_mpls_tc' : { 'value' : u8obj },
         'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
+        'of_oxm_mpls_bos' : { 'value' : boolean_value },
+        'of_oxm_mpls_bos_masked' : { 'value' : boolean_value, 'value_mask' : boolean_value },
+        'of_oxm_ipv6_exthdr' : { 'value' : u16obj },
+        'of_oxm_ipv6_exthdr_masked' : { 'value' : u16obj, 'value_mask' : u16obj },
+        'of_oxm_pbb_uca' : { 'value' : boolean_value },
+        'of_oxm_pbb_uca_masked' : { 'value' : boolean_value, 'value_mask' : boolean_value },
 
-        'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
-        'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
+        'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap_128 },
+        'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap_128, 'value_mask': port_bitmap_128 },
+
+        'of_oxm_bsn_in_ports_512' : { 'value': port_bitmap_512 },
+        'of_oxm_bsn_in_ports_512_masked' : { 'value': port_bitmap_512, 'value_mask': port_bitmap_512 },
 
         'of_oxm_bsn_lag_id' : { 'value' : lag_id },
         'of_oxm_bsn_lag_id_masked' : { 'value' : lag_id, 'value_mask' : lag_id },
@@ -663,6 +705,9 @@
         'of_oxm_bsn_vlan_xlate_port_group_id' : { 'value' : class_id },
         'of_oxm_bsn_vlan_xlate_port_group_id_masked' : { 'value' : class_id, 'value_mask' : class_id },
 
+        'of_oxm_bsn_l2_cache_hit' : { 'value' : boolean_value },
+        'of_oxm_bsn_l2_cache_hit_masked' : { 'value' : boolean_value, 'value_mask' : boolean_value },
+
         'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
         'of_match_v1': { 'vlan_vid' : vlan_vid_match, 'vlan_pcp': vlan_pcp,
                 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
@@ -704,8 +749,10 @@
         'of_features_reply' : { 'auxiliary_id' : of_aux_id},
         'of_oxm_och_sigtype' : { 'value' : u8obj },
         'of_oxm_och_sigtype_basic' : { 'value' : u8obj },
-	'of_oxm_och_sigid' : {'value' : sig_id},
-	'of_oxm_och_sigid_basic' : {'value' : sig_id},  
+        'of_oxm_och_sigid' : {'value' : sig_id},
+        'of_oxm_och_sigid_basic' : {'value' : sig_id},  
+
+        'of_bundle_add_msg' : { 'data' : of_message },
 }
 
 
@@ -770,6 +817,8 @@
         return action_type_set
     elif field_name == "table_id" and re.match(r'of_bsn_gentable.*', obj_name):
         return gen_table_id
+    elif field_name == "bundle_id" and re.match(r'of_bundle_.*', obj_name):
+        return bundle_id
     elif c_type in default_mtype_to_jtype_convert_map:
         return default_mtype_to_jtype_convert_map[c_type]
     elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java
new file mode 100644
index 0000000..2cb3583
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java
@@ -0,0 +1,7 @@
+package org.projectfloodlight.openflow.protocol;
+
+import org.projectfloodlight.openflow.types.BundleId;
+
+public interface BundleIdGenerator {
+    BundleId nextBundleId();
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java
new file mode 100644
index 0000000..997e0cd
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java
@@ -0,0 +1,28 @@
+package org.projectfloodlight.openflow.protocol;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.projectfloodlight.openflow.types.BundleId;
+
+public class BundleIdGenerators {
+    private static final BundleIdGenerator GLOBAL_BUNDLE_ID_GENERATOR = create();
+
+    public static BundleIdGenerator create() {
+        return new StandardBundleIdGenerator();
+    }
+
+    public static BundleIdGenerator global() {
+        return GLOBAL_BUNDLE_ID_GENERATOR;
+    }
+}
+
+class StandardBundleIdGenerator implements BundleIdGenerator {
+
+    private final AtomicInteger idGen = new AtomicInteger();
+
+    @Override
+    public BundleId nextBundleId() {
+        return BundleId.of(idGen.incrementAndGet());
+    }
+
+}
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFVersion.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFVersion.java
index 6f54e5f..0c54fdc 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFVersion.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFVersion.java
@@ -1,7 +1,7 @@
 package org.projectfloodlight.openflow.protocol;
 
 public enum OFVersion {
-    OF_10(1), OF_11(2), OF_12(3), OF_13(4);
+    OF_10(1), OF_11(2), OF_12(3), OF_13(4), OF_14(5);
 
     public final int wireVersion;
 
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
index 9fb3fd4..e2f172b 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
@@ -14,6 +14,7 @@
 import org.projectfloodlight.openflow.types.LagId;
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFBitMask128;
+import org.projectfloodlight.openflow.types.OFBitMask512;
 import org.projectfloodlight.openflow.types.OFBooleanValue;
 import org.projectfloodlight.openflow.types.OFMetadata;
 import org.projectfloodlight.openflow.types.OFPort;
@@ -179,12 +180,33 @@
             new MatchField<U8>("mpls_tc", MatchFields.MPLS_TC,
                     new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.MPLS_UNICAST, EthType.MPLS_MULTICAST));
 
-    public final static MatchField<U64> TUNNEL_ID = 
+    public final static MatchField<OFBooleanValue> MPLS_BOS =
+            new MatchField<OFBooleanValue>("mpls_bos", MatchFields.MPLS_BOS,
+                    new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.MPLS_UNICAST, EthType.MPLS_MULTICAST));
+
+    public final static MatchField<U64> TUNNEL_ID =
             new MatchField<U64>("tunnel_id", MatchFields.TUNNEL_ID);
 
+    public final static MatchField<U16> IPV6_EXTHDR =
+            new MatchField<U16>("ipv6_exthdr", MatchFields.IPV6_EXTHDR);
+
+    public final static MatchField<OFBooleanValue> PBB_UCA =
+            new MatchField<OFBooleanValue>("pbb_uca", MatchFields.PBB_UCA);
+
+    public final static MatchField<IPv4Address> TUNNEL_IPV4_SRC =
+            new MatchField<IPv4Address>("tunnel_ipv4_src", MatchFields.TUNNEL_IPV4_SRC,
+                    new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4));
+
+    public final static MatchField<IPv4Address> TUNNEL_IPV4_DST =
+            new MatchField<IPv4Address>("tunnel_ipv4_dst", MatchFields.TUNNEL_IPV4_DST,
+                    new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.IPv4));
+
     public final static MatchField<OFBitMask128> BSN_IN_PORTS_128 =
             new MatchField<OFBitMask128>("bsn_in_ports_128", MatchFields.BSN_IN_PORTS_128);
 
+    public final static MatchField<OFBitMask512> BSN_IN_PORTS_512 =
+            new MatchField<OFBitMask512>("bsn_in_ports_512", MatchFields.BSN_IN_PORTS_512);
+
     public final static MatchField<LagId> BSN_LAG_ID =
             new MatchField<LagId>("bsn_lag_id", MatchFields.BSN_LAG_ID);
 
@@ -236,7 +258,6 @@
     public final static MatchField<ClassId> BSN_VLAN_XLATE_PORT_GROUP_ID =
             new MatchField<ClassId>("bsn_vlan_xlate_port_group_id", MatchFields.BSN_VLAN_XLATE_PORT_GROUP_ID);
 
-
     public final static MatchField<U8> OCH_SIGTYPE =
             new MatchField<U8>("och_sigtype",
                                     MatchFields.OCH_SIGTYPE);
@@ -245,7 +266,6 @@
             new MatchField<U8>("och_sigtype_basic",
                                     MatchFields.OCH_SIGTYPE_BASIC);
 
-
     public final static MatchField<CircuitSignalID> OCH_SIGID =
             new MatchField<CircuitSignalID>("och_sigid",
                                     MatchFields.OCH_SIGID);
@@ -254,6 +274,9 @@
             new MatchField<CircuitSignalID>("och_sigid_basic",
                                     MatchFields.OCH_SIGID);
     
+    public final static MatchField<OFBooleanValue> BSN_L2_CACHE_HIT =
+            new MatchField<OFBooleanValue>("bsn_l2_cache_hit", MatchFields.BSN_L2_CACHE_HIT);
+
     public String getName() {
         return name;
     }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
index 3bf717b..12e2b20 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
@@ -38,8 +38,14 @@
     IPV6_ND_TLL,
     MPLS_LABEL,
     MPLS_TC,
+    MPLS_BOS,
     TUNNEL_ID,
+    IPV6_EXTHDR,
+    PBB_UCA,
+    TUNNEL_IPV4_SRC,
+    TUNNEL_IPV4_DST,
     BSN_IN_PORTS_128,
+    BSN_IN_PORTS_512,
     BSN_LAG_ID,
     BSN_VRF,
     BSN_GLOBAL_VRF_ALLOWED,
@@ -57,8 +63,9 @@
     BSN_UDF7,
     BSN_TCP_FLAGS,
     BSN_VLAN_XLATE_PORT_GROUP_ID,
+    BSN_L2_CACHE_HIT,
     OCH_SIGTYPE,
     OCH_SIGTYPE_BASIC,
     OCH_SIGID,
-    OCH_SIGID_BASIC,;
+    OCH_SIGID_BASIC,
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver14/ChannelUtilsVer14.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver14/ChannelUtilsVer14.java
new file mode 100644
index 0000000..c893cab
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver14/ChannelUtilsVer14.java
@@ -0,0 +1,26 @@
+package org.projectfloodlight.openflow.protocol.ver14;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.OFMatchBmap;
+import org.projectfloodlight.openflow.protocol.match.Match;
+
+/**
+ * Collection of helper functions for reading and writing into ChannelBuffers
+ *
+ * @author capveg
+ */
+
+public class ChannelUtilsVer14 {
+    public static Match readOFMatch(final ChannelBuffer bb) throws OFParseError {
+        return OFMatchV3Ver14.READER.readFrom(bb);
+    }
+
+    public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
+    public static void writeOFMatchBmap(ChannelBuffer bb, OFMatchBmap match) {
+        throw new UnsupportedOperationException("not implemented");
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java
new file mode 100644
index 0000000..cccf67e
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java
@@ -0,0 +1,92 @@
+package org.projectfloodlight.openflow.types;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.UnsignedInts;
+
+@Immutable
+public class BundleId implements OFValueType<BundleId> {
+    static final int LENGTH = 4;
+
+    private final static int NONE_VAL = 0;
+    public final static BundleId NONE = new BundleId(NONE_VAL);
+
+    private final static int NO_MASK_VAL = 0xFFFFFFFF;
+    public final static BundleId NO_MASK = new BundleId(NO_MASK_VAL);
+    public final static BundleId FULL_MASK = NONE;
+
+    private final int rawValue;
+
+    private BundleId(final int rawValue) {
+        this.rawValue = rawValue;
+    }
+
+    public static BundleId of(final int raw) {
+        if(raw == NONE_VAL)
+            return NONE;
+        else if(raw == NO_MASK_VAL)
+            return NO_MASK;
+        return new BundleId(raw);
+    }
+
+    public int getInt() {
+        return rawValue;
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public String toString() {
+        return UnsignedInts.toString(rawValue);
+    }
+
+    @Override
+    public BundleId applyMask(BundleId mask) {
+        return BundleId.of(rawValue & mask.rawValue);    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + rawValue;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        BundleId other = (BundleId) obj;
+        if (rawValue != other.rawValue)
+            return false;
+        return true;
+    }
+
+    public void write4Bytes(ChannelBuffer c) {
+        c.writeInt(rawValue);
+    }
+
+    public static BundleId read4Bytes(ChannelBuffer c) {
+        return BundleId.of(c.readInt());
+    }
+
+    @Override
+    public int compareTo(BundleId o) {
+        return UnsignedInts.compare(rawValue, rawValue);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
index 7d7c38e..98c1253 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
@@ -43,7 +43,7 @@
 
     @Override
     public String toString() {
-        return Integer.toString(rawValue);
+        return UnsignedInts.toString(rawValue);
     }
 
     @Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index 3a1b15e..eb37a20 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -12,14 +12,16 @@
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
-
+import org.projectfloodlight.openflow.protocol.Writeable;
+import org.projectfloodlight.openflow.protocol.OFMessageReader;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
 
 /**
  * Wrapper around an IPv4Address address
  *
  * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
  */
-public class IPv4Address extends IPAddress<IPv4Address> {
+public class IPv4Address extends IPAddress<IPv4Address> implements Writeable {
     static final int LENGTH = 4;
     private final int rawValue;
 
@@ -38,6 +40,15 @@
         this.rawValue = rawValue;
     }
 
+    public final static Reader READER = new Reader();
+
+    private static class Reader implements OFMessageReader<IPv4Address> {
+        @Override
+        public IPv4Address readFrom(ChannelBuffer bb) throws OFParseError {
+            return new IPv4Address(bb.readInt());
+        }
+    }
+
     @Override
     public IPVersion getIpVersion() {
         return IPVersion.IPv4;
@@ -345,4 +356,8 @@
         sink.putInt(rawValue);
     }
 
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        bb.writeInt(rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index 471d0fb..9d6fa4d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -8,19 +8,22 @@
 import javax.annotation.Nonnull;
 
 import org.jboss.netty.buffer.ChannelBuffer;
-import org.projectfloodlight.openflow.exceptions.OFParseError;
 
 import com.google.common.base.Preconditions;
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
+import org.projectfloodlight.openflow.protocol.Writeable;
+import org.projectfloodlight.openflow.protocol.OFMessageReader;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
 /**
  * IPv6 address object. Instance controlled, immutable. Internal representation:
  * two 64 bit longs (not that you'd have to know).
  *
  * @author Andreas Wundsam <andreas.wundsam@teleteach.de>
  */
-public class IPv6Address extends IPAddress<IPv6Address> {
+public class IPv6Address extends IPAddress<IPv6Address> implements Writeable {
     static final int LENGTH = 16;
     private final long raw1;
     private final long raw2;
@@ -43,6 +46,15 @@
         this.raw2 = raw2;
     }
 
+    public final static Reader READER = new Reader();
+
+    private static class Reader implements OFMessageReader<IPv6Address> {
+        @Override
+        public IPv6Address readFrom(ChannelBuffer bb) throws OFParseError {
+            return new IPv6Address(bb.readLong(), bb.readLong());
+        }
+    }
+
     @Override
     public IPVersion getIpVersion() {
         return IPVersion.IPv6;
@@ -213,8 +225,17 @@
     public static IPv6Address of(@Nonnull final String string) throws IllegalArgumentException {
         Preconditions.checkNotNull(string, "string must not be null");
 
+        // remove the zone id
+        int zoneDelimIndex = string.indexOf("%");
+        String substring;
+        if (zoneDelimIndex != -1) {
+            substring = string.substring(0, zoneDelimIndex);
+        } else {
+            substring = string;
+        }
+
         IPv6Builder builder = new IPv6Builder();
-        String[] parts = colonPattern.split(string, -1);
+        String[] parts = colonPattern.split(substring, -1);
 
         int leftWord = 0;
         int leftIndex = 0;
@@ -538,4 +559,10 @@
         sink.putLong(raw1);
         sink.putLong(raw2);
     }
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        bb.writeLong(raw1);
+        bb.writeLong(raw2);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask512.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask512.java
new file mode 100644
index 0000000..3fe9b88
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask512.java
@@ -0,0 +1,205 @@
+package org.projectfloodlight.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+import com.google.common.hash.PrimitiveSink;
+
+public class OFBitMask512 implements OFValueType<OFBitMask512> {
+
+    static final int LENGTH = 64;
+
+    private final long raw1;
+    private final long raw2;
+    private final long raw3;
+    private final long raw4;
+    private final long raw5;
+    private final long raw6;
+    private final long raw7;
+    private final long raw8;
+
+    public static final OFBitMask512 ALL = new OFBitMask512(-1, -1, -1, -1,
+                                                            -1, -1, -1, -1);
+    public static final OFBitMask512 NONE = new OFBitMask512(0, 0, 0, 0,
+                                                             0, 0, 0, 0);
+
+    public static final OFBitMask512 NO_MASK = ALL;
+    public static final OFBitMask512 FULL_MASK = NONE;
+
+    private OFBitMask512(long raw1, long raw2, long raw3, long raw4,
+                         long raw5, long raw6, long raw7, long raw8) {
+        this.raw1 = raw1;
+        this.raw2 = raw2;
+        this.raw3 = raw3;
+        this.raw4 = raw4;
+        this.raw5 = raw5;
+        this.raw6 = raw6;
+        this.raw7 = raw7;
+        this.raw8 = raw8;
+    }
+
+    public static OFBitMask512 of(long raw1, long raw2, long raw3, long raw4,
+                                  long raw5, long raw6, long raw7, long raw8) {
+        if (raw1 == -1 && raw2 == -1 && raw3 == -1 && raw4 == -1
+                && raw5 == -1 && raw6 == -1 && raw7 == -1 && raw8 == -1)
+            return ALL;
+        if (raw1 == 0 && raw2 == 0 && raw3 == 0 && raw4 == 0
+                && raw5 == 0 && raw6 == 0 && raw7 == 0 && raw8 == 0)
+            return NONE;
+        return new OFBitMask512(raw1, raw2, raw3, raw4, raw5, raw6, raw7, raw8);
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public OFBitMask512 applyMask(OFBitMask512 mask) {
+        return of(this.raw1 & mask.raw1, this.raw2 & mask.raw2,
+                  this.raw3 & mask.raw3, this.raw4 & mask.raw4,
+                  this.raw5 & mask.raw5, this.raw6 & mask.raw6,
+                  this.raw7 & mask.raw7, this.raw8 & mask.raw8);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (int) (raw1 ^ (raw1 >>> 32));
+        result = prime * result + (int) (raw2 ^ (raw2 >>> 32));
+        result = prime * result + (int) (raw3 ^ (raw3 >>> 32));
+        result = prime * result + (int) (raw4 ^ (raw4 >>> 32));
+        result = prime * result + (int) (raw5 ^ (raw5 >>> 32));
+        result = prime * result + (int) (raw6 ^ (raw6 >>> 32));
+        result = prime * result + (int) (raw7 ^ (raw7 >>> 32));
+        result = prime * result + (int) (raw8 ^ (raw8 >>> 32));
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        OFBitMask512 other = (OFBitMask512) obj;
+        if (raw1 != other.raw1) return false;
+        if (raw2 != other.raw2) return false;
+        if (raw3 != other.raw3) return false;
+        if (raw4 != other.raw4) return false;
+        if (raw5 != other.raw5) return false;
+        if (raw6 != other.raw6) return false;
+        if (raw7 != other.raw7) return false;
+        if (raw8 != other.raw8) return false;
+        return true;
+    }
+
+    protected static boolean isBitOn(long raw1, long raw2, long raw3, long raw4,
+                                     long raw5, long raw6, long raw7, long raw8, int bit) {
+        if (bit < 0 || bit >= 512)
+            throw new IndexOutOfBoundsException();
+        long word;
+        if (bit < 64) {
+            word = raw8;
+        } else if (bit < 128) {
+            word = raw7;
+            bit -= 64;
+        } else if (bit < 128) {
+            word = raw6;
+            bit -= 128;
+        } else if (bit < 128) {
+            word = raw5;
+            bit -= 192;
+        } else if (bit < 128) {
+            word = raw4;
+            bit -= 256;
+        } else if (bit < 128) {
+            word = raw3;
+            bit -= 320;
+        } else if (bit < 128) {
+            word = raw2;
+            bit -= 384;
+        } else {
+            word = raw1;
+            bit -= 448;
+        }
+        return (word & ((long)1 << bit)) != 0;
+    }
+
+    public void write64Bytes(ChannelBuffer cb) {
+        cb.writeLong(raw1);
+        cb.writeLong(raw2);
+        cb.writeLong(raw3);
+        cb.writeLong(raw4);
+        cb.writeLong(raw5);
+        cb.writeLong(raw6);
+        cb.writeLong(raw7);
+        cb.writeLong(raw8);
+    }
+
+    public static OFBitMask512 read64Bytes(ChannelBuffer cb) {
+        long raw1 = cb.readLong();
+        long raw2 = cb.readLong();
+        long raw3 = cb.readLong();
+        long raw4 = cb.readLong();
+        long raw5 = cb.readLong();
+        long raw6 = cb.readLong();
+        long raw7 = cb.readLong();
+        long raw8 = cb.readLong();
+        return of(raw1, raw2, raw3, raw4, raw5, raw6, raw7, raw8);
+    }
+
+    public boolean isOn(int bit) {
+        return isBitOn(raw1, raw2, raw3, raw4, raw5, raw6, raw7, raw8, bit);
+    }
+
+    @Override
+    public String toString() {
+        return (String.format("%64s", Long.toBinaryString(raw8))
+                + String.format("%64s", Long.toBinaryString(raw7))
+                + String.format("%64s", Long.toBinaryString(raw6))
+                + String.format("%64s", Long.toBinaryString(raw5))
+                + String.format("%64s", Long.toBinaryString(raw4))
+                + String.format("%64s", Long.toBinaryString(raw3))
+                + String.format("%64s", Long.toBinaryString(raw2))
+                + String.format("%64s", Long.toBinaryString(raw1))).replaceAll(" ", "0");
+    }
+
+    @Override
+    public int compareTo(OFBitMask512 o) {
+        long c = this.raw1 - o.raw1;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw2 - o.raw2;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw3 - o.raw3;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw4 - o.raw4;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw5 - o.raw5;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw6 - o.raw6;
+        if (c != 0)
+            return Long.signum(c);
+        c = this.raw7 - o.raw7;
+        if (c != 0)
+            return Long.signum(c);
+        return Long.signum(this.raw8 - o.raw8);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(raw1);
+        sink.putLong(raw2);
+        sink.putLong(raw3);
+        sink.putLong(raw4);
+        sink.putLong(raw5);
+        sink.putLong(raw6);
+        sink.putLong(raw7);
+        sink.putLong(raw8);
+    }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java
index a919f62..3ee588f 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java
@@ -22,10 +22,10 @@
      * reasons in Match.MetaData field.
      * */
     public static Set<OFBsnPktinFlag> getOFBsnPktinFlags(OFPacketIn pktIn) {
-        if(pktIn.getVersion() != OFVersion.OF_13) {
+        if(pktIn.getVersion().compareTo(OFVersion.OF_13) < 0) {
             throw new IllegalArgumentException("multiple pkt in reasons are "
                                                + "only supported by BVS using "
-                                               + "openflow 1.3");
+                                               + "openflow version >= 1.3");
         }
 
         Match match = pktIn.getMatch();
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
index a397c2a..fd26856 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -399,4 +399,10 @@
             assertNotNull(e.getMessage());
         }
     }
+
+    @Test
+    public void testZoneId() throws OFParseError {
+        assertEquals("::", IPv6Address.of("::%eth0").toString(true, false));
+        assertEquals("1:0:0:4::8", IPv6Address.of("1:0:0:4:0:0:0:8%2").toString(true, false));
+    }
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/OFPortDescTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/OFPortDescTest.java
new file mode 100644
index 0000000..965e314
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/OFPortDescTest.java
@@ -0,0 +1,53 @@
+package org.projectfloodlight.protocol;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFPortConfig;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFPortState;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+import static org.hamcrest.Matchers.is;
+
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests auxiliary OFPortDesc methods for all versions of OpenFlow
+ *
+ * @author Jason Parraga <jason.parraga@bigswitch.com>
+ */
+public class OFPortDescTest {
+
+    @Test
+    public void testIsEnabled() {
+       testIsEnabledForFactory(OFFactories.getFactory(OFVersion.OF_10));
+       testIsEnabledForFactory(OFFactories.getFactory(OFVersion.OF_11));
+       testIsEnabledForFactory(OFFactories.getFactory(OFVersion.OF_12));
+       testIsEnabledForFactory(OFFactories.getFactory(OFVersion.OF_13));
+       testIsEnabledForFactory(OFFactories.getFactory(OFVersion.OF_14));
+    }
+
+    public void testIsEnabledForFactory(OFFactory factory) {
+        // Default
+        OFPortDesc desc = factory.buildPortDesc()
+                .build();
+        assertThat(desc.isEnabled(), is(true));
+
+        // Partially disabled
+        desc = factory.buildPortDesc()
+                .setConfig(new HashSet<OFPortConfig>(Arrays.asList(OFPortConfig.PORT_DOWN)))
+                .build();
+        assertThat(desc.isEnabled(), is(false));
+
+        // Fully disabled
+        desc = factory.buildPortDesc()
+                .setConfig(new HashSet<OFPortConfig>(Arrays.asList(OFPortConfig.PORT_DOWN)))
+                .setState(new HashSet<OFPortState>(Arrays.asList(OFPortState.LINK_DOWN)))
+                .build();
+        assertThat(desc.isEnabled(), is(false));
+    }
+}
diff --git a/java_gen/templates/const.java b/java_gen/templates/const.java
index a7786f4..1828bac 100644
--- a/java_gen/templates/const.java
+++ b/java_gen/templates/const.java
@@ -37,7 +37,7 @@
 public enum ${class_name} {
 //:: for i, entry in enumerate(enum.entries):
 //::    if enum.metadata.properties:
-//::        params = "({})".format(", ".join(entry.constructor_params))
+//::        params = "({})".format(", ".join(type.format_value(value) for (type, value) in entry.constructor_params))
 //::    else:
 //::        params = ""
 //::    #endif
diff --git a/java_gen/templates/custom/OFMatchV3.Builder.java b/java_gen/templates/custom/OFMatchV3.Builder.java
new file mode 100644
index 0000000..54b35ba
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3.Builder.java
@@ -0,0 +1,106 @@
+
+    private OFOxmList.Builder oxmListBuilder;
+
+    private void initBuilder() {
+        if (oxmListBuilder != null)
+            return;
+        oxmListBuilder = new OFOxmList.Builder();
+    }
+
+    private void updateOxmList() {
+        this.oxmList = this.oxmListBuilder.build();
+        this.oxmListSet = true;
+    }
+
+    private <F extends OFValueType<F>> OFOxm<F> getOxm(MatchField<F> field) {
+//:: if has_parent:
+        return this.oxmListSet ? this.oxmList.get(field) : parentMessage.oxmList.get(field);
+//:: else:
+        return this.oxmListSet ? this.oxmList.get(field) : null;
+//:: #endif
+    }
+
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        OFOxm<F> value = getOxm(field);
+        if (value == null)
+            return null;
+        return value.getValue();
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        OFOxm<F> value = getOxm(field);
+        if (value == null || !value.isMasked())
+            return null;
+        // TODO: If changing OXMs to extend Masked, then use it here
+        return Masked.of(value.getValue(), value.getMask());
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        return supportsField(field);
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        return supportsField(field);
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        OFOxm<?> value = getOxm(field);
+        return (value != null && !value.isMasked());
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        OFOxm<?> value = getOxm(field);
+        return (value == null);
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        OFOxm<?> value = getOxm(field);
+        return (value != null && value.isMasked());
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Match.Builder setExact(
+            MatchField<F> field, F value) {
+        initBuilder();
+        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.${version.constant_version}).oxms().fromValue(value, field);
+        this.oxmListBuilder.set(oxm);
+        updateOxmList();
+        return this;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Match.Builder setMasked(
+            MatchField<F> field, F value, F mask) {
+        initBuilder();
+        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.${version.constant_version}).oxms().fromValueAndMask(value, mask, field);
+        this.oxmListBuilder.set(oxm);
+        updateOxmList();
+        return this;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Match.Builder setMasked(
+            MatchField<F> field, Masked<F> valueWithMask) {
+        initBuilder();
+        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.${version.constant_version}).oxms().fromMasked(valueWithMask, field);
+        this.oxmListBuilder.set(oxm);
+        updateOxmList();
+        return this;
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Match.Builder wildcard(MatchField<F> field) {
+        initBuilder();
+        this.oxmListBuilder.unset(field);
+        updateOxmList();
+        return this;
+    }
diff --git a/java_gen/templates/custom/OFMatchV3.java b/java_gen/templates/custom/OFMatchV3.java
new file mode 100644
index 0000000..799135c
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3.java
@@ -0,0 +1,112 @@
+//:: from generic_utils import OrderedSet
+//:: from java_gen.java_model import model
+    @Override
+    public <F extends OFValueType<F>> F get(MatchField<F> field)
+            throws UnsupportedOperationException {
+        if (!supports(field))
+            throw new UnsupportedOperationException("${msg.name} does not support matching on field " + field.getName());
+
+        OFOxm<F> oxm = this.oxmList.get(field);
+
+        if (oxm == null || !field.arePrerequisitesOK(this))
+            return null;
+
+        return oxm.getValue();
+    }
+
+    @Override
+    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
+            throws UnsupportedOperationException {
+        if (!supportsMasked(field))
+            throw new UnsupportedOperationException("${msg.name} does not support masked matching on field " + field.getName());
+
+        OFOxm<F> oxm = this.oxmList.get(field);
+
+        if (oxm == null || !field.arePrerequisitesOK(this))
+            return null;
+
+        if (oxm.getMask() == null)
+            return null;
+
+        // TODO: Make OfOxm extend Masked and just return the OXM?
+        return Masked.of(oxm.getValue(), oxm.getMask());
+    }
+
+    private static boolean supportsField(MatchField<?> field) {
+        switch (field.id) {
+            //:: for id_constant in sorted(set(id_constant for _, id_constant, _ in model.oxm_map.values())):
+            case ${id_constant}:
+            //:: #endfor
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public boolean supports(MatchField<?> field) {
+        return supportsField(field);
+    }
+
+    @Override
+    public boolean supportsMasked(MatchField<?> field) {
+        return supportsField(field);
+    }
+
+    @Override
+    public boolean isExact(MatchField<?> field) {
+        if (!supports(field))
+            throw new UnsupportedOperationException("${msg.name} does not support matching on field " + field.getName());
+
+        OFOxm<?> oxm = this.oxmList.get(field);
+
+        return oxm != null && !oxm.isMasked();
+    }
+
+    @Override
+    public boolean isFullyWildcarded(MatchField<?> field) {
+        if (!supports(field))
+            throw new UnsupportedOperationException("${msg.name} does not support matching on field " + field.getName());
+
+        OFOxm<?> oxm = this.oxmList.get(field);
+
+        return oxm == null;
+    }
+
+    @Override
+    public boolean isPartiallyMasked(MatchField<?> field) {
+        if (!supports(field))
+            throw new UnsupportedOperationException("${msg.name} does not support matching on field " + field.getName());
+
+        OFOxm<?> oxm = this.oxmList.get(field);
+
+        return oxm != null && oxm.isMasked();
+    }
+
+    private class MatchFieldIterator extends AbstractIterator<MatchField<?>> {
+        private Iterator<OFOxm<?>> oxmIterator;
+
+        MatchFieldIterator() {
+            oxmIterator = oxmList.iterator();
+        }
+
+        @Override
+        protected MatchField<?> computeNext() {
+            while(oxmIterator.hasNext()) {
+                OFOxm<?> oxm = oxmIterator.next();
+                if(oxm.getMatchField().arePrerequisitesOK(${msg.name}.this))
+                   return oxm.getMatchField();
+            }
+            endOfData();
+            return null;
+        }
+    }
+
+    @Override
+    public Iterable<MatchField<?>> getMatchFields() {
+        return new Iterable<MatchField<?>>() {
+            public Iterator<MatchField<?>> iterator() {
+                return new MatchFieldIterator();
+            }
+        };
+    }
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.Builder.java b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
index 3fae367..ae2ecaa 100644
--- a/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
+++ b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
@@ -1,106 +1 @@
-
-    private OFOxmList.Builder oxmListBuilder;
-
-    private synchronized void initBuilder() {
-        if (oxmListBuilder != null)
-            return;
-        oxmListBuilder = new OFOxmList.Builder();
-    }
-
-    private synchronized void updateOxmList() {
-        this.oxmList = this.oxmListBuilder.build();
-        this.oxmListSet = true;
-    }
-
-    private <F extends OFValueType<F>> OFOxm<F> getOxm(MatchField<F> field) {
-//:: if has_parent:
-        return this.oxmListSet ? this.oxmList.get(field) : parentMessage.oxmList.get(field);
-//:: else:
-        return this.oxmListSet ? this.oxmList.get(field) : null;
-//:: #endif
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> F get(MatchField<F> field)
-            throws UnsupportedOperationException {
-        OFOxm<F> value = getOxm(field);
-        if (value == null)
-            return null;
-        return value.getValue();
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
-            throws UnsupportedOperationException {
-        OFOxm<F> value = getOxm(field);
-        if (value == null || !value.isMasked())
-            return null;
-        // TODO: If changing OXMs to extend Masked, then use it here
-        return Masked.of(value.getValue(), value.getMask());
-    }
-
-    @Override
-    public boolean supports(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean supportsMasked(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public synchronized boolean isExact(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value != null && !value.isMasked());
-    }
-
-    @Override
-    public synchronized boolean isFullyWildcarded(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value == null);
-    }
-
-    @Override
-    public synchronized boolean isPartiallyMasked(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value != null && value.isMasked());
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> Match.Builder setExact(
-            MatchField<F> field, F value) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromValue(value, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, F value, F mask) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromValueAndMask(value, mask, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, Masked<F> valueWithMask) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromMasked(valueWithMask, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public synchronized <F extends OFValueType<F>> Match.Builder wildcard(MatchField<F> field) {
-        initBuilder();
-        this.oxmListBuilder.unset(field);
-        updateOxmList();
-        return this;
-    }
+//:: include("custom/OFMatchV3.Builder.java", msg=msg, version=version, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.java b/java_gen/templates/custom/OFMatchV3Ver12.java
index 81092c1..225b0dc 100644
--- a/java_gen/templates/custom/OFMatchV3Ver12.java
+++ b/java_gen/templates/custom/OFMatchV3Ver12.java
@@ -1,114 +1 @@
-
-    @Override
-    public <F extends OFValueType<F>> F get(MatchField<F> field)
-            throws UnsupportedOperationException {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<F> oxm = this.oxmList.get(field);
-
-        if (oxm == null || !field.arePrerequisitesOK(this))
-            return null;
-
-        return oxm.getValue();
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
-            throws UnsupportedOperationException {
-        if (!supportsMasked(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support masked matching on field " + field.getName());
-
-        OFOxm<F> oxm = this.oxmList.get(field);
-
-        if (oxm == null || !field.arePrerequisitesOK(this))
-            return null;
-
-        if (oxm.getMask() == null)
-            return null;
-
-        // TODO: Make OfOxm extend Masked and just return the OXM?
-        return Masked.of(oxm.getValue(), oxm.getMask());
-    }
-
-    private static boolean supportsField(MatchField<?> field) {
-        switch (field.id) {
-            case IN_PORT:
-            case IN_PHY_PORT:
-            case METADATA:
-            case ETH_DST:
-            case ETH_SRC:
-            case ETH_TYPE:
-            case VLAN_VID:
-            case VLAN_PCP:
-            case IP_DSCP:
-            case IP_ECN:
-            case IP_PROTO:
-            case IPV4_SRC:
-            case IPV4_DST:
-            case TCP_SRC:
-            case TCP_DST:
-            case UDP_SRC:
-            case UDP_DST:
-            case SCTP_SRC:
-            case SCTP_DST:
-            case ICMPV4_TYPE:
-            case ICMPV4_CODE:
-            case ARP_OP:
-            case ARP_SPA:
-            case ARP_TPA:
-            case ARP_SHA:
-            case ARP_THA:
-            case IPV6_SRC:
-            case IPV6_DST:
-            case IPV6_FLABEL:
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    @Override
-    public boolean supports(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean supportsMasked(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean isExact(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm != null && !oxm.isMasked();
-    }
-
-    @Override
-    public boolean isFullyWildcarded(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm == null;
-    }
-
-    @Override
-    public boolean isPartiallyMasked(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm != null && oxm.isMasked();
-    }
-
-    @Override
-    public Iterable<MatchField<?>> getMatchFields() {
-        throw new UnsupportedOperationException();
-    }
+//:: include("custom/OFMatchV3.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver12_toString.java b/java_gen/templates/custom/OFMatchV3Ver12_toString.java
new file mode 100644
index 0000000..3b2783b
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver12_toString.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatch_toString.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.Builder.java b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
index 79cbdbc..ae2ecaa 100644
--- a/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
+++ b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
@@ -1,107 +1 @@
-
-    private OFOxmList.Builder oxmListBuilder;
-
-    private void initBuilder() {
-        if (oxmListBuilder != null)
-            return;
-        oxmListBuilder = new OFOxmList.Builder();
-    }
-
-    private void updateOxmList() {
-        this.oxmList = this.oxmListBuilder.build();
-        this.oxmListSet = true;
-    }
-
-    private <F extends OFValueType<F>> OFOxm<F> getOxm(MatchField<F> field) {
-//:: if has_parent:
-        return this.oxmListSet ? this.oxmList.get(field) : parentMessage.oxmList.get(field);
-//:: else:
-        return this.oxmListSet ? this.oxmList.get(field) : null;
-//:: #endif
-    }
-
-    @Override
-    public <F extends OFValueType<F>> F get(MatchField<F> field)
-            throws UnsupportedOperationException {
-        OFOxm<F> value = getOxm(field);
-        if (value == null)
-            return null;
-        return value.getValue();
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
-            throws UnsupportedOperationException {
-        OFOxm<F> value = getOxm(field);
-        if (value == null || !value.isMasked())
-            return null;
-        // TODO: If changing OXMs to extend Masked, then use it here
-        return Masked.of(value.getValue(), value.getMask());
-    }
-
-    @Override
-    public boolean supports(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean supportsMasked(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean isExact(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value != null && !value.isMasked());
-    }
-
-    @Override
-    public boolean isFullyWildcarded(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value == null);
-    }
-
-    @Override
-    public boolean isPartiallyMasked(MatchField<?> field) {
-        OFOxm<?> value = getOxm(field);
-        return (value != null && value.isMasked());
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setExact(
-            MatchField<F> field, F value) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromValue(value, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, F value, F mask) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromValueAndMask(value, mask, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Match.Builder setMasked(
-            MatchField<F> field, Masked<F> valueWithMask) {
-        initBuilder();
-        OFOxm<F> oxm = OFFactories.getFactory(OFVersion.OF_13).oxms().fromMasked(valueWithMask, field);
-        this.oxmListBuilder.set(oxm);
-        updateOxmList();
-        return this;
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Match.Builder wildcard(MatchField<F> field) {
-        initBuilder();
-        this.oxmListBuilder.unset(field);
-        updateOxmList();
-        return this;
-    }
-
+//:: include("custom/OFMatchV3.Builder.java", msg=msg, version=version, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.java b/java_gen/templates/custom/OFMatchV3Ver13.java
index dc8e637..225b0dc 100644
--- a/java_gen/templates/custom/OFMatchV3Ver13.java
+++ b/java_gen/templates/custom/OFMatchV3Ver13.java
@@ -1,112 +1 @@
-//:: from generic_utils import OrderedSet
-//:: from java_gen.java_model import model
-    @Override
-    public <F extends OFValueType<F>> F get(MatchField<F> field)
-            throws UnsupportedOperationException {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<F> oxm = this.oxmList.get(field);
-
-        if (oxm == null || !field.arePrerequisitesOK(this))
-            return null;
-
-        return oxm.getValue();
-    }
-
-    @Override
-    public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field)
-            throws UnsupportedOperationException {
-        if (!supportsMasked(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support masked matching on field " + field.getName());
-
-        OFOxm<F> oxm = this.oxmList.get(field);
-
-        if (oxm == null || !field.arePrerequisitesOK(this))
-            return null;
-
-        if (oxm.getMask() == null)
-            return null;
-
-        // TODO: Make OfOxm extend Masked and just return the OXM?
-        return Masked.of(oxm.getValue(), oxm.getMask());
-    }
-
-    private static boolean supportsField(MatchField<?> field) {
-        switch (field.id) {
-            //:: for id_constant in sorted(set(id_constant for _, id_constant, _ in model.oxm_map.values())):
-            case ${id_constant}:
-            //:: #endfor
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    @Override
-    public boolean supports(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean supportsMasked(MatchField<?> field) {
-        return supportsField(field);
-    }
-
-    @Override
-    public boolean isExact(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm != null && !oxm.isMasked();
-    }
-
-    @Override
-    public boolean isFullyWildcarded(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm == null;
-    }
-
-    @Override
-    public boolean isPartiallyMasked(MatchField<?> field) {
-        if (!supports(field))
-            throw new UnsupportedOperationException("OFMatchV3Ver13 does not support matching on field " + field.getName());
-
-        OFOxm<?> oxm = this.oxmList.get(field);
-
-        return oxm != null && oxm.isMasked();
-    }
-
-    private class MatchFieldIterator extends AbstractIterator<MatchField<?>> {
-        private Iterator<OFOxm<?>> oxmIterator;
-
-        MatchFieldIterator() {
-            oxmIterator = oxmList.iterator();
-        }
-
-        @Override
-        protected MatchField<?> computeNext() {
-            while(oxmIterator.hasNext()) {
-                OFOxm<?> oxm = oxmIterator.next();
-                if(oxm.getMatchField().arePrerequisitesOK(OFMatchV3Ver13.this))
-                   return oxm.getMatchField();
-            }
-            endOfData();
-            return null;
-        }
-    }
-
-    @Override
-    public Iterable<MatchField<?>> getMatchFields() {
-        return new Iterable<MatchField<?>>() {
-            public Iterator<MatchField<?>> iterator() {
-                return new MatchFieldIterator();
-            }
-        };
-    }
+//:: include("custom/OFMatchV3.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver14.Builder.java b/java_gen/templates/custom/OFMatchV3Ver14.Builder.java
new file mode 100644
index 0000000..ae2ecaa
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver14.Builder.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatchV3.Builder.java", msg=msg, version=version, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver14.java b/java_gen/templates/custom/OFMatchV3Ver14.java
new file mode 100644
index 0000000..225b0dc
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver14.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatchV3.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver14_toString.java b/java_gen/templates/custom/OFMatchV3Ver14_toString.java
new file mode 100644
index 0000000..3b2783b
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver14_toString.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatch_toString.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFPortDesc.java b/java_gen/templates/custom/OFPortDesc.java
new file mode 100644
index 0000000..3be1b70
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDesc.java
@@ -0,0 +1,11 @@
+
+    /**
+     * Returns true if the port is up, i.e., it's neither administratively
+     * down nor link down. It currently does NOT take STP state into
+     * consideration
+     * @return whether the port is up
+     */
+    public boolean isEnabled() {
+        return (!state.contains(OFPortState.LINK_DOWN) && !config.contains(OFPortConfig.PORT_DOWN));
+    }
+    
\ No newline at end of file
diff --git a/java_gen/templates/custom/OFPortDescVer10.java b/java_gen/templates/custom/OFPortDescVer10.java
new file mode 100644
index 0000000..782a726
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDescVer10.java
@@ -0,0 +1 @@
+//:: include("custom/OFPortDesc.java", msg=msg, has_parent=False)
\ No newline at end of file
diff --git a/java_gen/templates/custom/OFPortDescVer11.java b/java_gen/templates/custom/OFPortDescVer11.java
new file mode 100644
index 0000000..782a726
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDescVer11.java
@@ -0,0 +1 @@
+//:: include("custom/OFPortDesc.java", msg=msg, has_parent=False)
\ No newline at end of file
diff --git a/java_gen/templates/custom/OFPortDescVer12.java b/java_gen/templates/custom/OFPortDescVer12.java
new file mode 100644
index 0000000..782a726
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDescVer12.java
@@ -0,0 +1 @@
+//:: include("custom/OFPortDesc.java", msg=msg, has_parent=False)
\ No newline at end of file
diff --git a/java_gen/templates/custom/OFPortDescVer13.java b/java_gen/templates/custom/OFPortDescVer13.java
new file mode 100644
index 0000000..782a726
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDescVer13.java
@@ -0,0 +1 @@
+//:: include("custom/OFPortDesc.java", msg=msg, has_parent=False)
\ No newline at end of file
diff --git a/java_gen/templates/custom/OFPortDescVer14.java b/java_gen/templates/custom/OFPortDescVer14.java
new file mode 100644
index 0000000..782a726
--- /dev/null
+++ b/java_gen/templates/custom/OFPortDescVer14.java
@@ -0,0 +1 @@
+//:: include("custom/OFPortDesc.java", msg=msg, has_parent=False)
\ No newline at end of file
diff --git a/java_gen/templates/custom/interface/OFPortDesc.java b/java_gen/templates/custom/interface/OFPortDesc.java
new file mode 100644
index 0000000..ecf39f3
--- /dev/null
+++ b/java_gen/templates/custom/interface/OFPortDesc.java
@@ -0,0 +1,2 @@
+    // Additional method
+    boolean isEnabled();
\ No newline at end of file
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index f1d72b2..0b032ac 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -74,6 +74,13 @@
     ${impl_class}(${
         ", ".join("%s %s" %(prop.java_type.public_type, prop.name) for prop in msg.data_members) }) {
 //:: for prop in msg.data_members:
+//::   if not prop.java_type.is_primitive and (not prop.default_value or prop.default_value != "null"):
+        if(${prop.name} == null) {
+            throw new NullPointerException("${msg.name}: property ${prop.name} cannot be null");
+        }
+//::   #endif
+//:: #endfor
+//:: for prop in msg.data_members:
         this.${prop.name} = ${prop.name};
 //:: #endfor
     }
@@ -88,7 +95,7 @@
     //:: include("_field_accessors.java", msg=msg, generate_setters=False, builder=False, has_parent=False)
 
     //:: if os.path.exists("%s/custom/%s.java" % (template_dir, msg.name)):
-    //:: include("custom/%s.java" % msg.name, msg=msg)
+    //:: include("custom/%s.java" % msg.name, msg=msg, version=version)
     //:: #endif
 
     //:: if msg.data_members:
@@ -124,7 +131,7 @@
 
                 //
                 //:: if os.path.exists("%s/custom/%s.Builder_normalize_stanza.java" % (template_dir, msg.name)):
-                //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+                //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, version=version, has_parent=False)
                 //:: #endif
                 return new ${impl_class}(
                 //:: for i, prop in enumerate(msg.data_members):
@@ -134,7 +141,7 @@
                 );
         }
         //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
-        //:: include("custom/%s.Builder.java" % msg.name, msg=msg, has_parent=True)
+        //:: include("custom/%s.Builder.java" % msg.name, msg=msg, version=version, has_parent=True)
         //:: #endif
 
     }
@@ -164,7 +171,7 @@
             //:: #endfor
 
             //:: if os.path.exists("%s/custom/%s.Builder_normalize_stanza.java" % (template_dir, msg.name)):
-            //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+            //:: include("custom/%s.Builder_normalize_stanza.java" % msg.name, msg=msg, version=version, has_parent=False)
             //:: #endif
 
             return new ${impl_class}(
@@ -175,7 +182,7 @@
                 );
         }
         //:: if os.path.exists("%s/custom/%s.Builder.java" % (template_dir, msg.name)):
-        //:: include("custom/%s.Builder.java" % msg.name, msg=msg, has_parent=False)
+        //:: include("custom/%s.Builder.java" % msg.name, msg=msg, version=version, has_parent=False)
         //:: #endif
 
     }
@@ -249,7 +256,7 @@
 
             //:: if msg.data_members:
             //:: if os.path.exists("%s/custom/%s.Reader_normalize_stanza.java" % (template_dir, msg.name)):
-            //:: include("custom/%s.Reader_normalize_stanza.java" % msg.name, msg=msg, has_parent=False)
+            //:: include("custom/%s.Reader_normalize_stanza.java" % msg.name, msg=msg, version=version, has_parent=False)
             //:: #endif
             ${impl_class} ${msg.variable_name} = new ${impl_class}(
                     ${",\n                      ".join(
@@ -364,7 +371,7 @@
     }
 
     //:: if os.path.exists("%s/custom/%s_toString.java" % (template_dir, msg.name)):
-    //:: include("custom/%s_toString.java" % msg.name, msg=msg, has_parent=False)
+    //:: include("custom/%s_toString.java" % msg.name, msg=msg, version=version, has_parent=False)
     //:: else:
     @Override
     public String toString() {
diff --git a/java_gen/templates/of_factories.java b/java_gen/templates/of_factories.java
index f9ec015..ba73286 100644
--- a/java_gen/templates/of_factories.java
+++ b/java_gen/templates/of_factories.java
@@ -51,7 +51,9 @@
 
     private static class GenericReader implements OFMessageReader<OFMessage> {
         public OFMessage readFrom(ChannelBuffer bb) throws OFParseError {
-            short wireVersion = U8.f(bb.getByte(0));
+            if(!bb.readable())
+                return null;
+            short wireVersion = U8.f(bb.getByte(bb.readerIndex()));
             OFFactory factory;
             switch (wireVersion) {
             //:: for v in versions:
diff --git a/java_gen/templates/of_interface.java b/java_gen/templates/of_interface.java
index a515ad1..18e2cf1 100644
--- a/java_gen/templates/of_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -27,6 +27,7 @@
 //::
 //:: import itertools
 //:: import re
+//:: import os
 //:: include('_copyright.java')
 
 //:: include('_autogen.java')
@@ -39,6 +40,10 @@
 //:: for prop in msg.members:
     ${prop.java_type.public_type} ${prop.getter_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endfor
+//:: if os.path.exists("%s/custom/interface/%s.java" % (template_dir, msg.name)):
+//:: include("custom/interface/%s.java" % msg.name, msg=msg)
+//:: #endif
+    
 
     void writeTo(ChannelBuffer channelBuffer);
 
diff --git a/lang_c.py b/lang_c.py
index c7b68f7..bec4a65 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -125,7 +125,6 @@
             fn(outfile, os.path.basename(name))
     c_gen.codegen.build_class_metadata()
     c_gen.codegen.generate_classes(install_dir)
-    c_gen.codegen.generate_header_classes(install_dir)
     c_gen.codegen.generate_classes_header(install_dir)
     c_gen.codegen.generate_lists(install_dir)
     c_gen.codegen.generate_strings(install_dir)
diff --git a/lang_python.py b/lang_python.py
index 019b62d..18fca27 100644
--- a/lang_python.py
+++ b/lang_python.py
@@ -28,12 +28,6 @@
 """
 Python backend for LOXI
 
-This language specific file defines a dictionary 'targets' that
-defines the generated files and the functions used to generate them.
-
-For each generated file there is a generate_* function in py_gen.codegen
-and a Tenjin template under py_gen/templates.
-
 Target directory structure:
     pyloxi:
         loxi:
@@ -64,51 +58,9 @@
 """
 
 import os
-from loxi_globals import OFVersions
-import loxi_globals
-import loxi_utils.loxi_utils as loxi_utils
-import py_gen
-import py_gen.util
 import py_gen.codegen
-import template_utils
 
-versions = {
-    1: "of10",
-    2: "of11",
-    3: "of12",
-    4: "of13",
-}
-
-prefix = 'pyloxi/loxi'
-
-modules = {
-    1: ["action", "common", "const", "message", "util"],
-    2: ["action", "common", "const", "instruction", "message", "util"],
-    3: ["action", "common", "const", "instruction", "message", "oxm", "util"],
-    4: ["action", "action_id", "common", "const", "instruction", "instruction_id", "message", "meter_band", "oxm", "bsn_tlv", "util"],
-}
-
-def make_gen(name, version):
-    fn = getattr(py_gen.codegen, "generate_" + name)
-    return lambda out, name: fn(out, name, version)
-
-def static(template_name):
-    return lambda out, name: py_gen.util.render_template(out, template_name)
-
-targets = {
-    prefix+'/__init__.py': static('toplevel_init.py'),
-    prefix+'/pp.py': static('pp.py'),
-    prefix+'/generic_util.py': static('generic_util.py'),
-}
-
-for version, subdir in versions.items():
-    targets['%s/%s/__init__.py' % (prefix, subdir)] = make_gen('init', version)
-    for module in modules[version]:
-        filename = '%s/%s/%s.py' % (prefix, subdir, module)
-        targets[filename] = make_gen(module, OFVersions.from_wire(version))
+PREFIX = 'pyloxi/loxi'
 
 def generate(install_dir):
-    py_gen.codegen.init()
-    for (name, fn) in targets.items():
-        with template_utils.open_output(install_dir, name) as outfile:
-            fn(outfile, os.path.basename(name))
+    py_gen.codegen.codegen(os.path.join(install_dir, PREFIX))
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index 4a465f7..fbf476d 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -68,7 +68,7 @@
          s('}') - s(';')
 
 # Enums
-enum_param_name = kw("wire_type") | kw("bitmask") | kw("complete")
+enum_param_name = kw("wire_type") | kw("bitmask") | kw("complete") | kw("stable")
 enum_param = P.Group(enum_param_name  - s('=') - word)
 enum_param_list = P.Forward()
 enum_param_list << enum_param + P.Optional(s(',') + P.Optional(enum_param_list))
diff --git a/loxi_globals.py b/loxi_globals.py
index e8b21bd..b4662cb 100644
--- a/loxi_globals.py
+++ b/loxi_globals.py
@@ -37,12 +37,14 @@
     VERSION_1_1 = OFVersion("1.1", 2)
     VERSION_1_2 = OFVersion("1.2", 3)
     VERSION_1_3 = OFVersion("1.3", 4)
+    VERSION_1_4 = OFVersion("1.4", 5)
 
     all_supported = (
         VERSION_1_0,
         VERSION_1_1,
         VERSION_1_2,
         VERSION_1_3,
+        VERSION_1_4,
     )
 
     wire_version_map   = { v.wire_version : v for v in all_supported }
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index 0e95473..7b9a0b6 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -145,6 +145,15 @@
     def is_subclassof(self, super_class_name):
         return self.name != super_class_name and self.is_instanceof(super_class_name)
 
+    def inheritance_root(self):
+        if not self.superclass:
+            if self.virtual:
+                return self
+            else:
+                return None
+        else:
+            return self.superclass.inheritance_root()
+
     @property
     def is_message(self):
         return self.is_instanceof("of_header")
diff --git a/loxi_ir/ir_offset.py b/loxi_ir/ir_offset.py
index 1d66115..490c6b0 100644
--- a/loxi_ir/ir_offset.py
+++ b/loxi_ir/ir_offset.py
@@ -36,6 +36,7 @@
         2: "uint32_t",
         3: "uint32_t",
         4: "uint32_t",
+        5: "uint32_t",
         "short_name":"port_no"
         },
     of_port_desc_t = {
@@ -43,6 +44,7 @@
         2: "of_port_desc_t",
         3: "of_port_desc_t",
         4: "of_port_desc_t",
+        5: "of_port_desc_t",
         "short_name":"port_desc"
         },
     of_bsn_vport_t = {
@@ -50,6 +52,7 @@
         2: "of_bsn_vport_t",
         3: "of_bsn_vport_t",
         4: "of_bsn_vport_t",
+        5: "of_bsn_vport_t",
         "short_name":"bsn_vport"
         },
     of_fm_cmd_t = { # Flow mod command went from u16 to u8
@@ -57,6 +60,7 @@
         2: "uint8_t",
         3: "uint8_t",
         4: "uint8_t",
+        5: "uint8_t",
         "short_name":"fm_cmd"
         },
     of_wc_bmap_t = { # Wildcard bitmap
@@ -64,6 +68,7 @@
         2: "uint32_t",
         3: "uint64_t",
         4: "uint64_t",
+        5: "uint64_t",
         "short_name":"wc_bmap"
         },
     of_match_bmap_t = { # Match bitmap
@@ -71,6 +76,7 @@
         2: "uint32_t",
         3: "uint64_t",
         4: "uint64_t",
+        5: "uint64_t",
         "short_name":"match_bmap"
         },
     of_match_t = { # Match object
@@ -78,6 +84,7 @@
         2: "of_match_v2_t",
         3: "of_match_v3_t",
         4: "of_match_v3_t",  # Currently uses same match as 1.2 (v3).
+        5: "of_match_v3_t",  # Currently uses same match as 1.2 (v3).
         "short_name":"match"
         },
 )
@@ -105,6 +112,7 @@
     of_checksum_128_t = (16, True),
     of_app_code_t = (15,True),
     of_sig_id_t = (6, True),
+    of_bitmap_512_t = (64, True),
 )
 
 def type_dec_to_count_base(m_type):
@@ -183,6 +191,8 @@
         member_ir_class = existing_classes[base_class]
         bytes = member_ir_class.base_length
         length_fixed = member_ir_class.is_fixed_length
+        if member_ir_class.has_external_alignment:
+            bytes = (bytes + 7) & ~7
     else:
         if base_type in existing_enums:
             enum = existing_enums[base_type]
diff --git a/loxi_ir/unified.py b/loxi_ir/unified.py
index 41b86dc..fa97c87 100644
--- a/loxi_ir/unified.py
+++ b/loxi_ir/unified.py
@@ -98,6 +98,9 @@
                     self.entries[e.name] = ir.OFEnumEntry(e.name, e.value, copy.copy(e.params))
                 else:
                     entry = self.entries[e.name]
+                    if v_enum.params.get('stable') == 'True' and e.value != entry.value:
+                        raise Exception("Error unifying stable ir enum {} - adding entry {} version {} value {} <-> {}".format(
+                            self.name, e.name, version, entry.value, e.value))
                     for name, value in e.params.items():
                         if not name in entry.params:
                             entry.params[name] = value
diff --git a/openflow_input/bsn-1.3 b/openflow_input/bsn-1.3
index f9340b4..5ad480c 100644
--- a/openflow_input/bsn-1.3
+++ b/openflow_input/bsn-1.3
@@ -26,6 +26,7 @@
 // under the EPL.
 
 #version 4
+#version 5
 
 // BSN extension instruction
 struct of_instruction_bsn : of_instruction_experimenter {
diff --git a/openflow_input/bsn_acl b/openflow_input/bsn_acl
index 4035904..bcca842 100644
--- a/openflow_input/bsn_acl
+++ b/openflow_input/bsn_acl
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 // Instructions to express control flow in ACL tables
 
diff --git a/openflow_input/bsn_arp_idle b/openflow_input/bsn_arp_idle
index 26cea92..16a1782 100644
--- a/openflow_input/bsn_arp_idle
+++ b/openflow_input/bsn_arp_idle
@@ -35,6 +35,7 @@
 // not remove the table entry on its own.
 
 #version 4
+#version 5
 
 struct of_bsn_arp_idle : of_bsn_header {
     uint8_t version;
diff --git a/openflow_input/bsn_arp_offload b/openflow_input/bsn_arp_offload
index 5a229b1..f13f6ac 100644
--- a/openflow_input/bsn_arp_offload
+++ b/openflow_input/bsn_arp_offload
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_arp_offload : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_auto_negotiation b/openflow_input/bsn_auto_negotiation
new file mode 100644
index 0000000..68116cf
--- /dev/null
+++ b/openflow_input/bsn_auto_negotiation
@@ -0,0 +1,41 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 4
+#version 5
+
+struct of_instruction_bsn_auto_negotiation : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 11;
+    pad(4);
+};
diff --git a/openflow_input/bsn_aux_cxns b/openflow_input/bsn_aux_cxns
index 247f81b..8ceaa72 100644
--- a/openflow_input/bsn_aux_cxns
+++ b/openflow_input/bsn_aux_cxns
@@ -28,6 +28,8 @@
 // Request that the switch spawn and configure auxiliary OF connections.
 //
 #version 4
+#version 5
+
 // Set the number of desired aux connections num_aux=(0-16) accompanying this main connection
 // This message is only allowed on the main connection. 
 struct of_bsn_set_aux_cxns_request : of_bsn_header {
diff --git a/openflow_input/bsn_controller_connections b/openflow_input/bsn_controller_connections
index eae315e..845d3b8 100644
--- a/openflow_input/bsn_controller_connections
+++ b/openflow_input/bsn_controller_connections
@@ -37,6 +37,7 @@
 // The URIs are of the form tcp://1.2.3.4:6553
 
 #version 4
+#version 5
 
 enum ofp_bsn_controller_connection_state(wire_type=uint8_t) {
     OFP_BSN_CONTROLLER_CONNECTION_STATE_DISCONNECTED = 0,
diff --git a/openflow_input/bsn_debug_counter b/openflow_input/bsn_debug_counter
index 75cafcc..6c28b87 100644
--- a/openflow_input/bsn_debug_counter
+++ b/openflow_input/bsn_debug_counter
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 // Switches have many non-dataplane counters that are mainly useful for
 // debugging. An example is the number of packet-ins dropped due to
diff --git a/openflow_input/bsn_dhcp_offload b/openflow_input/bsn_dhcp_offload
index b21b036..5352754 100644
--- a/openflow_input/bsn_dhcp_offload
+++ b/openflow_input/bsn_dhcp_offload
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_dhcp_offload : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_disable_src_mac_check b/openflow_input/bsn_disable_src_mac_check
index f75c237..6b095ca 100644
--- a/openflow_input/bsn_disable_src_mac_check
+++ b/openflow_input/bsn_disable_src_mac_check
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_disable_src_mac_check : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_disable_vlan_counters b/openflow_input/bsn_disable_vlan_counters
index 068db64..e586917 100644
--- a/openflow_input/bsn_disable_vlan_counters
+++ b/openflow_input/bsn_disable_vlan_counters
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_disable_vlan_counters : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_egr_port_group_id b/openflow_input/bsn_egr_port_group_id
index a237b49..3ba5462 100644
--- a/openflow_input/bsn_egr_port_group_id
+++ b/openflow_input/bsn_egr_port_group_id
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * Egress port group ID for SwitchLight
diff --git a/openflow_input/bsn_flow_checksum b/openflow_input/bsn_flow_checksum
index bfa5f3c..35b658f 100644
--- a/openflow_input/bsn_flow_checksum
+++ b/openflow_input/bsn_flow_checksum
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 // Retrieves the checksum for every bucket in a table. The entries are ordered
 // by bucket index.
diff --git a/openflow_input/bsn_flow_idle b/openflow_input/bsn_flow_idle
index 40a95d8..e0139e2 100644
--- a/openflow_input/bsn_flow_idle
+++ b/openflow_input/bsn_flow_idle
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 /*
  * Notification of idle flows
diff --git a/openflow_input/bsn_generic_stats b/openflow_input/bsn_generic_stats
new file mode 100644
index 0000000..b67d8e3
--- /dev/null
+++ b/openflow_input/bsn_generic_stats
@@ -0,0 +1,67 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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 EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+#version 5
+
+// This extension provides flexibility for stats requests like gentable
+// does for table programming.
+
+struct of_bsn_generic_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 16;
+    of_str64_t name;
+    list(of_bsn_tlv_t) tlvs;
+};
+
+struct of_bsn_generic_stats_entry {
+    uint16_t length;
+    list(of_bsn_tlv_t) tlvs;
+};
+
+struct of_bsn_generic_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 16;
+    list(of_bsn_generic_stats_entry_t) entries;
+};
diff --git a/openflow_input/bsn_gentable b/openflow_input/bsn_gentable
index 1344ef5..556ae0b 100644
--- a/openflow_input/bsn_gentable
+++ b/openflow_input/bsn_gentable
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 // We have a number of switch agents that need to be configured by the
 // controller and report stats. Some of them will have large tables (1000+
@@ -351,3 +352,13 @@
     uint32_t subtype == 5;
     list(of_bsn_gentable_bucket_stats_entry_t) entries;
 };
+
+// Reference a gentable entry from an action list
+struct of_action_bsn_gentable : of_action_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 5;
+    uint32_t table_id;
+    list(of_bsn_tlv_t) key;
+};
diff --git a/openflow_input/bsn_image b/openflow_input/bsn_image
index 05a1a97..fafe8d8 100644
--- a/openflow_input/bsn_image
+++ b/openflow_input/bsn_image
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 struct of_bsn_image_desc_stats_request : of_bsn_stats_request {
     uint8_t version;
diff --git a/openflow_input/bsn_in_ports b/openflow_input/bsn_in_ports
index b23df63..bb4c030 100644
--- a/openflow_input/bsn_in_ports
+++ b/openflow_input/bsn_in_ports
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * Bitmap of input ports
@@ -59,3 +60,14 @@
     of_bitmap_128_t value;
     of_bitmap_128_t value_mask;
 };
+
+struct of_oxm_bsn_in_ports_512 : of_oxm {
+    uint32_t type_len == 0x00032640;
+    of_bitmap_512_t value;
+};
+
+struct of_oxm_bsn_in_ports_512_masked : of_oxm {
+    uint32_t type_len == 0x00032780;
+    of_bitmap_512_t value;
+    of_bitmap_512_t value_mask;
+};
diff --git a/openflow_input/bsn_l2_cache_hit b/openflow_input/bsn_l2_cache_hit
new file mode 100644
index 0000000..694bc65
--- /dev/null
+++ b/openflow_input/bsn_l2_cache_hit
@@ -0,0 +1,47 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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 EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 3
+#version 4
+
+/*
+ * L2 Cache Hit
+ */
+
+struct of_oxm_bsn_l2_cache_hit : of_oxm {
+    uint32_t type_len == 0x00032401;
+    uint8_t value;
+};
+
+struct of_oxm_bsn_l2_cache_hit_masked : of_oxm {
+    uint32_t type_len == 0x00032502;
+    uint8_t value;
+    uint8_t value_mask;
+};
diff --git a/openflow_input/bsn_l3_interface_class_id b/openflow_input/bsn_l3_interface_class_id
index 80d1e37..f16d333 100644
--- a/openflow_input/bsn_l3_interface_class_id
+++ b/openflow_input/bsn_l3_interface_class_id
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * L3 interface class ID for SwitchLight
diff --git a/openflow_input/bsn_l3_src_class_id b/openflow_input/bsn_l3_src_class_id
index 58f60c6..7e2569e 100644
--- a/openflow_input/bsn_l3_src_class_id
+++ b/openflow_input/bsn_l3_src_class_id
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * L3 source class ID for SwitchLight
diff --git a/openflow_input/bsn_lacp b/openflow_input/bsn_lacp
index d2e540a..ed36b0d 100644
--- a/openflow_input/bsn_lacp
+++ b/openflow_input/bsn_lacp
@@ -29,9 +29,10 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 // LACP Convergence Status set in of_bsn_lacp_convergence_notif message
-enum of_bsn_lacp_convergence_status_t(wire_type=uint8_t, complete=False) {
+enum of_bsn_lacp_convergence_status(wire_type=uint8_t, complete=False) {
     LACP_SUCCESS = 0,
     LACP_TIMEDOUT = 1,
     LACP_OUT_OF_SYNC = 2,
diff --git a/openflow_input/bsn_lag_id b/openflow_input/bsn_lag_id
index 63645a3..d428933 100644
--- a/openflow_input/bsn_lag_id
+++ b/openflow_input/bsn_lag_id
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * Ingress LAG ID for SwitchLight
diff --git a/openflow_input/bsn_log b/openflow_input/bsn_log
index b2a9758..e636d6e 100644
--- a/openflow_input/bsn_log
+++ b/openflow_input/bsn_log
@@ -29,6 +29,7 @@
 // the receiver's configured loglevel is lower than the message's loglevel.
 
 #version 4
+#version 5
 
 enum ofp_bsn_loglevel(wire_type=uint8_t) {
     OFP_BSN_LOGLEVEL_MSG = 0,
diff --git a/openflow_input/bsn_lua b/openflow_input/bsn_lua
new file mode 100644
index 0000000..d941666
--- /dev/null
+++ b/openflow_input/bsn_lua
@@ -0,0 +1,108 @@
+// Copyright 2015, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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 EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+// IVS supports running sandboxed Lua code as the forwarding pipeline.
+// This extension allows the controller to upload the Lua code, send
+// commands to it, and receive async notifications.
+//
+// Most of the data passed between the controller and the Lua code is
+// opaque to the rest of the switch. It's assumed that the controller
+// is tightly coupled to the Lua code it uploaded, so there's no need
+// to version the protocol between them.
+
+#version 4
+#version 5
+
+// Upload chunks of Lua code to the switch
+//
+// If the MORE flag is not set, the old VM will be cleaned up and
+// a new VM will be initialized with the uploaded code. Each chunk
+// of code is executed in the VM in the order it was received.
+//
+// If the FORCE flag is not set, the switch will check to see if the
+// old and new code is identical. If they are identical the message
+// will be ignored.
+//
+// As part of the VM cleanup, all gentables registered by Lua code
+// will be unregistered.
+//
+// Consecutive messages with the same filename are concatenated,
+// to support chunks larger than 64K.
+
+enum ofp_bsn_lua_upload_flags(wire_type=uint16_t, bitmask=True) {
+    OFP_BSN_LUA_UPLOAD_MORE = 0x1,
+    OFP_BSN_LUA_UPLOAD_FORCE = 0x2,
+};
+
+struct of_bsn_lua_upload : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 64;
+    enum ofp_bsn_lua_upload_flags flags;
+    of_str64_t filename;
+    of_octets_t data;
+};
+
+// Send a command to Lua
+
+struct of_bsn_lua_command_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 65;
+    of_octets_t data;
+};
+
+struct of_bsn_lua_command_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 66;
+    of_octets_t data;
+};
+
+// Async message from Lua to the controller
+
+struct of_bsn_lua_notification : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 67;
+    of_octets_t data;
+};
diff --git a/openflow_input/bsn_packet_of_death b/openflow_input/bsn_packet_of_death
index e8679f0..c1ac28d 100644
--- a/openflow_input/bsn_packet_of_death
+++ b/openflow_input/bsn_packet_of_death
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_packet_of_death : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_pdu b/openflow_input/bsn_pdu
index 66465f3..007365b 100644
--- a/openflow_input/bsn_pdu
+++ b/openflow_input/bsn_pdu
@@ -32,7 +32,7 @@
 
 // When the slot_num field has this value, the message applies
 // to all currently used slots on the switch for the given port
-enum of_bsn_pdu_slot_num_t(wire_type=uint8_t, complete=False) {
+enum of_bsn_pdu_slot_num(wire_type=uint8_t, complete=False) {
     BSN_PDU_SLOT_NUM_ANY = 0xff
 };
 
diff --git a/openflow_input/bsn_pktin_flag b/openflow_input/bsn_pktin_flag
index fd94a49..b046024 100644
--- a/openflow_input/bsn_pktin_flag
+++ b/openflow_input/bsn_pktin_flag
@@ -26,6 +26,7 @@
 // under the EPL.
 
 #version 4
+#version 5
 
 // In a realistic switch pipeline there are multiple reasons a given packet
 // should be sent to the controller. The packet-in reason field is only 8 bits,
@@ -43,4 +44,6 @@
     OFP_BSN_PKTIN_FLAG_L3_MISS = 0x100,
     OFP_BSN_PKTIN_FLAG_L3_CPU = 0x200,
     OFP_BSN_PKTIN_FLAG_INGRESS_ACL = 0x400,
+    OFP_BSN_PKTIN_FLAG_SFLOW = 0x800,
+    OFP_BSN_PKTIN_FLAG_ARP_CACHE = 0x1000,
 };
diff --git a/openflow_input/bsn_port_counter b/openflow_input/bsn_port_counter
index 73ba80e..6cf5e10 100644
--- a/openflow_input/bsn_port_counter
+++ b/openflow_input/bsn_port_counter
@@ -29,8 +29,9 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
-enum ofp_bsn_port_counter(wire_type=uint8_t, complete=False) {
+enum ofp_bsn_port_counter(wire_type=uint8_t, complete=False, stable=True) {
   OFP_BSN_PORT_COUNTER_RX_BYTES = 0,
   OFP_BSN_PORT_COUNTER_RX_PACKETS_UNICAST = 1,
   OFP_BSN_PORT_COUNTER_RX_PACKETS_BROADCAST = 2,
diff --git a/openflow_input/bsn_prioritize_pdus b/openflow_input/bsn_prioritize_pdus
index fbec0a0..7a179a9 100644
--- a/openflow_input/bsn_prioritize_pdus
+++ b/openflow_input/bsn_prioritize_pdus
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_prioritize_pdus : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_require_vlan_xlate b/openflow_input/bsn_require_vlan_xlate
index 24cf137..32fc55c 100644
--- a/openflow_input/bsn_require_vlan_xlate
+++ b/openflow_input/bsn_require_vlan_xlate
@@ -30,6 +30,7 @@
 // Copyright (c) 2011, 2012 Open Networking Foundation
 
 #version 4
+#version 5
 
 struct of_instruction_bsn_require_vlan_xlate : of_instruction_bsn {
     uint16_t type == 65535;
diff --git a/openflow_input/bsn_span_destination b/openflow_input/bsn_span_destination
new file mode 100644
index 0000000..fd4f677
--- /dev/null
+++ b/openflow_input/bsn_span_destination
@@ -0,0 +1,41 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 4
+#version 5
+
+struct of_instruction_bsn_span_destination : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 10;
+    pad(4);
+};
diff --git a/openflow_input/bsn_switch_pipeline b/openflow_input/bsn_switch_pipeline
index ff2213f..d42532b 100644
--- a/openflow_input/bsn_switch_pipeline
+++ b/openflow_input/bsn_switch_pipeline
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 struct of_bsn_get_switch_pipeline_request : of_bsn_header {
     uint8_t version;
diff --git a/openflow_input/bsn_tcp_flags b/openflow_input/bsn_tcp_flags
index e8ef2e9..1a84a90 100644
--- a/openflow_input/bsn_tcp_flags
+++ b/openflow_input/bsn_tcp_flags
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * TCP flags
diff --git a/openflow_input/bsn_time b/openflow_input/bsn_time
index 0a955be..d69e538 100644
--- a/openflow_input/bsn_time
+++ b/openflow_input/bsn_time
@@ -33,6 +33,7 @@
 // The timestamp must be monotonic (not affected by system time updates).
 
 #version 4
+#version 5
 
 struct of_bsn_time_request : of_bsn_header {
     uint8_t version;
diff --git a/openflow_input/bsn_tlv b/openflow_input/bsn_tlv
index 4113759..7e9b376 100644
--- a/openflow_input/bsn_tlv
+++ b/openflow_input/bsn_tlv
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 struct of_bsn_tlv_port : of_bsn_tlv {
     uint16_t type == 0;
@@ -172,3 +173,304 @@
     uint16_t length;
     uint8_t value;
 };
+
+struct of_bsn_tlv_external_ip : of_bsn_tlv {
+    uint16_t type == 23;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_external_mac : of_bsn_tlv {
+    uint16_t type == 24;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_external_netmask : of_bsn_tlv {
+    uint16_t type == 25;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_external_gateway_ip : of_bsn_tlv {
+    uint16_t type == 26;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_internal_mac : of_bsn_tlv {
+    uint16_t type == 27;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_internal_gateway_mac : of_bsn_tlv {
+    uint16_t type == 28;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_external_gateway_mac : of_bsn_tlv {
+    uint16_t type == 29;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_sampling_rate : of_bsn_tlv {
+    uint16_t type == 30;
+    uint16_t length;
+    uint32_t value;
+};
+
+struct of_bsn_tlv_header_size : of_bsn_tlv {
+    uint16_t type == 31;
+    uint16_t length;
+    uint32_t value; /* bytes */
+};
+
+struct of_bsn_tlv_eth_src : of_bsn_tlv {
+    uint16_t type == 32;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_eth_dst : of_bsn_tlv {
+    uint16_t type == 33;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_ipv4_src : of_bsn_tlv {
+    uint16_t type == 34;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_ipv4_dst : of_bsn_tlv {
+    uint16_t type == 35;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_udp_src : of_bsn_tlv {
+    uint16_t type == 36;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_udp_dst : of_bsn_tlv {
+    uint16_t type == 37;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_sub_agent_id : of_bsn_tlv {
+    uint16_t type == 38;
+    uint16_t length;
+    uint32_t value;
+};
+
+struct of_bsn_tlv_tx_bytes : of_bsn_tlv {
+    uint16_t type == 39;
+    uint16_t length;
+    uint64_t value;
+};
+
+struct of_bsn_tlv_actor_system_priority: of_bsn_tlv {
+    uint16_t type == 40;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_actor_system_mac: of_bsn_tlv {
+    uint16_t type == 41;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_actor_port_priority: of_bsn_tlv {
+    uint16_t type == 42;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_actor_port_num: of_bsn_tlv {
+    uint16_t type == 43;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_actor_key: of_bsn_tlv {
+    uint16_t type == 44;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_convergence_status: of_bsn_tlv {
+    uint16_t type == 45;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_partner_system_priority: of_bsn_tlv {
+    uint16_t type == 47;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_partner_system_mac: of_bsn_tlv {
+    uint16_t type == 48;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_partner_port_priority: of_bsn_tlv {
+    uint16_t type == 49;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_partner_port_num: of_bsn_tlv {
+    uint16_t type == 50;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_partner_key: of_bsn_tlv {
+    uint16_t type == 51;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_name : of_bsn_tlv {
+    uint16_t type == 52;
+    uint16_t length;
+    of_octets_t value; /* UTF-8 encoded. Not null terminated. */
+};
+
+enum ofp_bsn_lacp_state(wire_type=uint8_t, bitmask=True) {
+    OFP_BSN_LACP_STATE_ACTIVITY = 0x01,
+    OFP_BSN_LACP_STATE_TIMEOUT = 0x02,
+    OFP_BSN_LACP_STATE_AGGREGATION = 0x04,
+    OFP_BSN_LACP_STATE_SYNCHRONIZATION = 0x08,
+    OFP_BSN_LACP_STATE_COLLECTING = 0x10,
+    OFP_BSN_LACP_STATE_DISTRIBUTING = 0x20,
+    OFP_BSN_LACP_STATE_DEFAULTED = 0x40,
+    OFP_BSN_LACP_STATE_EXPIRED = 0x80,
+};
+
+struct of_bsn_tlv_actor_state: of_bsn_tlv {
+    uint16_t type == 53;
+    uint16_t length;
+    enum ofp_bsn_lacp_state value;
+};
+
+struct of_bsn_tlv_partner_state: of_bsn_tlv {
+    uint16_t type == 54;
+    uint16_t length;
+    enum ofp_bsn_lacp_state value;
+};
+
+struct of_bsn_tlv_data : of_bsn_tlv {
+    uint16_t type == 55;
+    uint16_t length;
+    of_octets_t value;
+};
+
+struct of_bsn_tlv_mac_mask : of_bsn_tlv {
+    uint16_t type == 56;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_priority : of_bsn_tlv {
+    uint16_t type == 57;
+    uint16_t length;
+    uint32_t value;
+};
+
+struct of_bsn_tlv_interval : of_bsn_tlv {
+    uint16_t type == 58;
+    uint16_t length;
+    uint32_t value; /* Milliseconds */
+};
+
+/* A reference to an entry in another gentable */
+struct of_bsn_tlv_reference : of_bsn_tlv {
+    uint16_t type == 59;
+    uint16_t length;
+    uint16_t table_id;
+    list(of_bsn_tlv_t) key;
+};
+
+struct of_bsn_tlv_ipv4_netmask : of_bsn_tlv {
+    uint16_t type == 60;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_mpls_label : of_bsn_tlv {
+    uint16_t type == 61;
+    uint16_t length;
+    uint32_t value;
+};
+
+struct of_bsn_tlv_mpls_control_word : of_bsn_tlv {
+    uint16_t type == 62;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_mpls_sequenced : of_bsn_tlv {
+    uint16_t type == 63;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_bucket : of_bsn_tlv {
+    uint16_t type == 64;
+    uint16_t length;
+    list(of_bsn_tlv_t) value;
+};
+
+struct of_bsn_tlv_tcp_src : of_bsn_tlv {
+    uint16_t type == 65;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_tcp_dst : of_bsn_tlv {
+    uint16_t type == 66;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_ip_proto : of_bsn_tlv {
+    uint16_t type == 67;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_icmp_type : of_bsn_tlv {
+    uint16_t type == 68;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_icmp_code : of_bsn_tlv {
+    uint16_t type == 69;
+    uint16_t length;
+    uint8_t value;
+};
+
+struct of_bsn_tlv_icmp_id : of_bsn_tlv {
+    uint16_t type == 70;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_rx_bytes : of_bsn_tlv {
+    uint16_t type == 71;
+    uint16_t length;
+    uint64_t value;
+};
diff --git a/openflow_input/bsn_udf b/openflow_input/bsn_udf
index f7ce9a6..12ad1cb 100644
--- a/openflow_input/bsn_udf
+++ b/openflow_input/bsn_udf
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * User Defined Fields
diff --git a/openflow_input/bsn_vlan_counter b/openflow_input/bsn_vlan_counter
index 5d90724..d39d35f 100644
--- a/openflow_input/bsn_vlan_counter
+++ b/openflow_input/bsn_vlan_counter
@@ -29,12 +29,13 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 enum ofp_bsn_vlan_counter_constants {
     OFP_BSN_VLAN_ALL = 0xffff,
 };
 
-enum of_bsn_vlan_counter_t(wire_type=uint8_t, complete=False) {
+enum of_bsn_vlan_counter(wire_type=uint8_t, complete=False, stable=True) {
   OFP_BSN_VLAN_COUNTER_RX_BYTES = 0,
   OFP_BSN_VLAN_COUNTER_RX_PACKETS = 1,
   OFP_BSN_VLAN_COUNTER_TX_BYTES = 2,
diff --git a/openflow_input/bsn_vlan_xlate_port_group_id b/openflow_input/bsn_vlan_xlate_port_group_id
index c8e5a25..986dc0e 100644
--- a/openflow_input/bsn_vlan_xlate_port_group_id
+++ b/openflow_input/bsn_vlan_xlate_port_group_id
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * VLAN xlate port group ID for SwitchLight
diff --git a/openflow_input/bsn_vrf b/openflow_input/bsn_vrf
index 26959bd..c61c313 100644
--- a/openflow_input/bsn_vrf
+++ b/openflow_input/bsn_vrf
@@ -30,6 +30,7 @@
 
 #version 3
 #version 4
+#version 5
 
 /*
  * Virtual Routing/Forwarding ID for SwitchLight
diff --git a/openflow_input/bsn_vrf_counter b/openflow_input/bsn_vrf_counter
index 7676e69..012d728 100644
--- a/openflow_input/bsn_vrf_counter
+++ b/openflow_input/bsn_vrf_counter
@@ -29,12 +29,13 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 enum ofp_bsn_vrf_counter_constants(wire_type=uint32_t) {
     OFP_BSN_VRF_ALL = 0xffffffff,
 };
 
-enum of_bsn_vrf_counter_t(wire_type=uint8_t, complete=False) {
+enum of_bsn_vrf_counter(wire_type=uint8_t, complete=False, stable=True) {
   OFP_BSN_VRF_COUNTER_BYTES = 0,
   OFP_BSN_VRF_COUNTER_PACKETS = 1,
 };
diff --git a/openflow_input/oxm-1.2 b/openflow_input/oxm-1.2
index 5006cff..dd596bd 100644
--- a/openflow_input/oxm-1.2
+++ b/openflow_input/oxm-1.2
@@ -31,6 +31,7 @@
 
 #version 3
 #version 4
+#version 5
 
 struct of_oxm {
     uint32_t type_len == ?;
diff --git a/openflow_input/oxm-1.3 b/openflow_input/oxm-1.3
index 2dbab42..4bb55a1 100644
--- a/openflow_input/oxm-1.3
+++ b/openflow_input/oxm-1.3
@@ -29,6 +29,7 @@
 // governing permissions and limitations under the EPL.
 
 #version 4
+#version 5
 
 struct of_oxm_tunnel_id : of_oxm {
     uint32_t type_len == 0x80004c08;
@@ -40,3 +41,27 @@
     uint64_t value;
     uint64_t value_mask;
 };
+
+struct of_oxm_mpls_bos : of_oxm {
+    uint32_t type_len == 0x80004801;
+    uint8_t value;
+};
+
+struct of_oxm_mpls_bos_masked : of_oxm {
+    uint32_t type_len == 0x80004902;
+    uint8_t value;
+    uint8_t value_mask;
+};
+
+/* Not supporting pbb_isid at the moment, requires a 3-byte field */
+
+struct of_oxm_ipv6_exthdr : of_oxm {
+    uint32_t type_len == 0x80004e02;
+    uint16_t value;
+};
+
+struct of_oxm_ipv6_exthdr_masked : of_oxm {
+    uint32_t type_len == 0x80004f04;
+    uint16_t value;
+    uint16_t value_mask;
+};
diff --git a/openflow_input/oxm-1.4 b/openflow_input/oxm-1.4
new file mode 100644
index 0000000..0fd96ec
--- /dev/null
+++ b/openflow_input/oxm-1.4
@@ -0,0 +1,42 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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 EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 5
+
+struct of_oxm_pbb_uca : of_oxm {
+    uint32_t type_len == 0x80005201;
+    uint8_t value;
+};
+
+struct of_oxm_pbb_uca_masked : of_oxm {
+    uint32_t type_len == 0x80005302;
+    uint8_t value;
+    uint8_t value_mask;
+};
diff --git a/openflow_input/oxm_nicira_tun b/openflow_input/oxm_nicira_tun
new file mode 100644
index 0000000..408f63e
--- /dev/null
+++ b/openflow_input/oxm_nicira_tun
@@ -0,0 +1,54 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removd
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by t"
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. Youn
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+
+#version 3
+#version 4
+#version 5
+
+// Nicira extension for tun_ipv4_src (31)
+struct of_oxm_tunnel_ipv4_src : of_oxm {
+    uint32_t type_len == 0x00013e04;
+    of_ipv4_t value;
+};
+
+struct of_oxm_tunnel_ipv4_src_masked : of_oxm {
+    uint32_t type_len == 0x00013f08;
+    of_ipv4_t value;
+    of_ipv4_t value_mask;
+};
+
+// Nicira extension for tun_ipv4_dst (32)
+struct of_oxm_tunnel_ipv4_dst : of_oxm {
+    uint32_t type_len == 0x00014004;
+    of_ipv4_t value;
+};
+
+struct of_oxm_tunnel_ipv4_dst_masked : of_oxm {
+    uint32_t type_len == 0x00014108;
+    of_ipv4_t value;
+    of_ipv4_t value_mask;
+};
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index 64a465d..fa1a967 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -160,6 +160,7 @@
     OFPPF_AUTONEG = 0x2000,
     OFPPF_PAUSE = 0x4000,
     OFPPF_PAUSE_ASYM = 0x8000,
+    OFPPF_BSN_BREAKOUT_CAPABLE = 0x80000000,
 };
 
 enum ofp_port_reason(wire_type=uint8_t) {
@@ -1700,7 +1701,7 @@
 struct of_table_feature_prop_experimenter : of_table_feature_prop {
     uint16_t         type == 65534;
     uint16_t         length;
-    uint32_t         experimenter;
+    uint32_t         experimenter == ?;
     uint32_t         subtype;
     of_octets_t      experimenter_data;
 };
@@ -1708,7 +1709,7 @@
 struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
     uint16_t         type == 65535;
     uint16_t         length;
-    uint32_t         experimenter;
+    uint32_t         experimenter == ?;
     uint32_t         subtype;
     of_octets_t      experimenter_data;
 };
diff --git a/openflow_input/standard-1.4 b/openflow_input/standard-1.4
new file mode 100644
index 0000000..edcc781
--- /dev/null
+++ b/openflow_input/standard-1.4
@@ -0,0 +1,2675 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// 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
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 5
+
+enum macro_definitions {
+    OFP_MAX_TABLE_NAME_LEN = 32,
+    OFP_MAX_PORT_NAME_LEN = 16,
+
+    OFP_TCP_PORT = 6653,
+    OFP_SSL_PORT = 6653,
+
+    OFP_ETH_ALEN = 6,
+
+    OFP_DEFAULT_MISS_SEND_LEN = 128,
+
+    OFP_VLAN_NONE = 0,
+
+    OFP_FLOW_PERMANENT = 0,
+
+    OFP_DEFAULT_PRIORITY = 0x8000,
+
+    OFP_NO_BUFFER = 0xffffffff,
+
+    DESC_STR_LEN = 256,
+    SERIAL_NUM_LEN = 32,
+
+    OFPQ_ALL = 0xffffffff,
+    OFPQ_MAX_RATE_UNCFG = 0xffff,
+    OFPQ_MIN_RATE_UNCFG = 0xffff,
+};
+
+enum ofp_port(wire_type=uint32_t) {
+    OFPP_MAX = 0xffffff00,
+    OFPP_IN_PORT = 0xfffffff8,
+    OFPP_TABLE = 0xfffffff9,
+    OFPP_NORMAL = 0xfffffffa,
+    OFPP_FLOOD = 0xfffffffb,
+    OFPP_ALL = 0xfffffffc,
+    OFPP_CONTROLLER = 0xfffffffd,
+    OFPP_LOCAL = 0xfffffffe,
+    OFPP_ANY = 0xffffffff,
+};
+
+enum ofp_type(wire_type=uint8_t) {
+    OFPT_HELLO = 0,
+    OFPT_ERROR = 1,
+    OFPT_ECHO_REQUEST = 2,
+    OFPT_ECHO_REPLY = 3,
+    OFPT_EXPERIMENTER = 4,
+    OFPT_FEATURES_REQUEST = 5,
+    OFPT_FEATURES_REPLY = 6,
+    OFPT_GET_CONFIG_REQUEST = 7,
+    OFPT_GET_CONFIG_REPLY = 8,
+    OFPT_SET_CONFIG = 9,
+    OFPT_PACKET_IN = 10,
+    OFPT_FLOW_REMOVED = 11,
+    OFPT_PORT_STATUS = 12,
+    OFPT_PACKET_OUT = 13,
+    OFPT_FLOW_MOD = 14,
+    OFPT_GROUP_MOD = 15,
+    OFPT_PORT_MOD = 16,
+    OFPT_TABLE_MOD = 17,
+    OFPT_STATS_REQUEST = 18,
+    OFPT_STATS_REPLY = 19,
+    OFPT_BARRIER_REQUEST = 20,
+    OFPT_BARRIER_REPLY = 21,
+    OFPT_ROLE_REQUEST = 24,
+    OFPT_ROLE_REPLY = 25,
+    OFPT_GET_ASYNC_REQUEST = 26,
+    OFPT_GET_ASYNC_REPLY = 27,
+    OFPT_SET_ASYNC = 28,
+    OFPT_METER_MOD = 29,
+    OFPT_ROLE_STATUS = 30,
+    OFPT_TABLE_STATUS = 31,
+    OFPT_REQUESTFORWARD = 32,
+    OFPT_BUNDLE_CONTROL = 33,
+    OFPT_BUNDLE_ADD_MESSAGE = 34,
+};
+
+enum ofp_config_flags(wire_type=uint16_t, bitmask=True) {
+    OFPC_FRAG_NORMAL = 0,
+    OFPC_FRAG_DROP = 1,
+    OFPC_FRAG_REASM = 2,
+    OFPC_FRAG_MASK = 3,
+};
+
+enum ofp_table_config(wire_type=uint32_t, bitmask=True) {
+    OFPTC_DEPRECATED_MASK = 0x3,
+    OFPTC_EVICTION = 0x4,
+    OFPTC_VACANCY_EVENTS = 0x8,
+};
+
+enum ofp_table(wire_type=uint8_t, complete=False) {
+    OFPTT_MAX = 0xfe,
+    OFPTT_ALL = 0xff,
+};
+
+enum ofp_capabilities(wire_type=uint32_t, bitmask=True) {
+    OFPC_FLOW_STATS = 0x1,
+    OFPC_TABLE_STATS = 0x2,
+    OFPC_PORT_STATS = 0x4,
+    OFPC_GROUP_STATS = 0x8,
+    OFPC_IP_REASM = 0x20,
+    OFPC_QUEUE_STATS = 0x40,
+    OFPC_PORT_BLOCKED = 0x100,
+};
+
+enum ofp_port_config(wire_type=uint32_t, bitmask=True) {
+    OFPPC_PORT_DOWN = 0x1,
+    OFPPC_NO_RECV = 0x4,
+    OFPPC_NO_FWD = 0x20,
+    OFPPC_NO_PACKET_IN = 0x40,
+    OFPPC_BSN_MIRROR_DEST = 0x80000000,
+};
+
+enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
+    OFPPS_LINK_DOWN = 0x1,
+    OFPPS_BLOCKED = 0x2,
+    OFPPS_LIVE = 0x4,
+};
+
+enum ofp_port_features(wire_type=uint32_t, bitmask=True) {
+    OFPPF_10MB_HD = 0x1,
+    OFPPF_10MB_FD = 0x2,
+    OFPPF_100MB_HD = 0x4,
+    OFPPF_100MB_FD = 0x8,
+    OFPPF_1GB_HD = 0x10,
+    OFPPF_1GB_FD = 0x20,
+    OFPPF_10GB_FD = 0x40,
+    OFPPF_40GB_FD = 0x80,
+    OFPPF_100GB_FD = 0x100,
+    OFPPF_1TB_FD = 0x200,
+    OFPPF_OTHER = 0x400,
+    OFPPF_COPPER = 0x800,
+    OFPPF_FIBER = 0x1000,
+    OFPPF_AUTONEG = 0x2000,
+    OFPPF_PAUSE = 0x4000,
+    OFPPF_PAUSE_ASYM = 0x8000,
+    OFPPF_BSN_BREAKOUT_CAPABLE = 0x80000000,
+};
+
+enum ofp_port_reason(wire_type=uint8_t) {
+    OFPPR_ADD = 0,
+    OFPPR_DELETE = 1,
+    OFPPR_MODIFY = 2,
+};
+
+enum ofp_match_type(wire_type=uint16_t) {
+    OFPMT_STANDARD = 0,
+    OFPMT_OXM = 1,
+};
+
+enum ofp_oxm_class(wire_type=uint16_t) {
+    OFPXMC_NXM_0 = 0,
+    OFPXMC_NXM_1 = 1,
+    OFPXMC_OPENFLOW_BASIC = 0x8000,
+    OFPXMC_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_vlan_id(wire_type=uint16_t) {
+    OFPVID_NONE = 0,
+    OFPVID_PRESENT = 0x1000,
+};
+
+// FIXME: OF spec specified this as '9' bits, implicitly adding
+// to full byte
+enum ofp_ipv6exthdr_flags(wire_type=uint16_t, bitmask=True) {
+    OFPIEH_NONEXT = 0x1,
+    OFPIEH_ESP = 0x2,
+    OFPIEH_AUTH = 0x4,
+    OFPIEH_DEST = 0x8,
+    OFPIEH_FRAG = 0x10,
+    OFPIEH_ROUTER = 0x20,
+    OFPIEH_HOP = 0x40,
+    OFPIEH_UNREP = 0x80,
+    OFPIEH_UNSEQ = 0x100,
+};
+
+enum ofp_action_type(wire_type=uint16_t) {
+    OFPAT_OUTPUT = 0,
+    OFPAT_COPY_TTL_OUT = 0xb,
+    OFPAT_COPY_TTL_IN = 0xc,
+    OFPAT_SET_MPLS_TTL = 0xf,
+    OFPAT_DEC_MPLS_TTL = 0x10,
+    OFPAT_PUSH_VLAN = 0x11,
+    OFPAT_POP_VLAN = 0x12,
+    OFPAT_PUSH_MPLS = 0x13,
+    OFPAT_POP_MPLS = 0x14,
+    OFPAT_SET_QUEUE = 0x15,
+    OFPAT_GROUP = 0x16,
+    OFPAT_SET_NW_TTL = 0x17,
+    OFPAT_DEC_NW_TTL = 0x18,
+    OFPAT_SET_FIELD = 0x19,
+    OFPAT_PUSH_PBB = 0x1a,
+    OFPAT_POP_PBB = 0x1b,
+    OFPAT_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_controller_max_len(wire_type=uint16_t, complete=False) {
+    OFPCML_MAX = 0xffe5,
+    OFPCML_NO_BUFFER = 0xffff,
+};
+
+enum ofp_instruction_type(wire_type=uint16_t, bitmask=True) {
+    OFPIT_GOTO_TABLE = 0x1,
+    OFPIT_WRITE_METADATA = 0x2,
+    OFPIT_WRITE_ACTIONS = 0x3,
+    OFPIT_APPLY_ACTIONS = 0x4,
+    OFPIT_CLEAR_ACTIONS = 0x5,
+    OFPIT_METER = 0x6,
+    OFPIT_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_flow_mod_command(wire_type=uint8_t) {
+    OFPFC_ADD = 0,
+    OFPFC_MODIFY = 1,
+    OFPFC_MODIFY_STRICT = 2,
+    OFPFC_DELETE = 3,
+    OFPFC_DELETE_STRICT = 4,
+};
+
+enum ofp_flow_mod_flags(wire_type=uint16_t, bitmask=True) {
+    OFPFF_SEND_FLOW_REM = 0x1,
+    OFPFF_CHECK_OVERLAP = 0x2,
+    OFPFF_RESET_COUNTS = 0x4,
+    OFPFF_NO_PKT_COUNTS = 0x8,
+    OFPFF_NO_BYT_COUNTS = 0x10,
+
+    /* Non-standard, enabled by an experimenter message */
+    /* See the bsn_flow_idle input file */
+    OFPFF_BSN_SEND_IDLE = 0x80,
+};
+
+enum ofp_group(wire_type=uint32_t, complete=False) {
+    OFPG_MAX = 0xffffff00,
+    OFPG_ALL = 0xfffffffc,
+    OFPG_ANY = 0xffffffff,
+};
+
+enum ofp_group_mod_command(wire_type=uint16_t) {
+    OFPGC_ADD = 0,
+    OFPGC_MODIFY = 1,
+    OFPGC_DELETE = 2,
+};
+
+enum ofp_group_type(wire_type=uint8_t) {
+    OFPGT_ALL = 0,
+    OFPGT_SELECT = 1,
+    OFPGT_INDIRECT = 2,
+    OFPGT_FF = 3,
+};
+
+enum ofp_packet_in_reason(wire_type=uint8_t) {
+    OFPR_NO_MATCH = 0,
+    OFPR_ACTION = 1,
+    OFPR_INVALID_TTL = 2,
+    OFPR_ACTION_SET = 3,
+    OFPR_GROUP = 4,
+    OFPR_PACKET_OUT = 5,
+
+    // non-standard BSN extensions. OF does not have a standard-conformant
+    // way to extend the set of packet_in reasons
+    OFPR_BSN_NEW_HOST = 128,
+    OFPR_BSN_STATION_MOVE = 129,
+    OFPR_BSN_BAD_VLAN = 130,
+    OFPR_BSN_DESTINATION_LOOKUP_FAILURE = 131,
+    OFPR_BSN_NO_ROUTE = 132,
+    OFPR_BSN_ICMP_ECHO_REQUEST = 133,
+    OFPR_BSN_DEST_NETWORK_UNREACHABLE = 134,
+    OFPR_BSN_DEST_HOST_UNREACHABLE = 135,
+    OFPR_BSN_DEST_PORT_UNREACHABLE = 136,
+    OFPR_BSN_FRAGMENTATION_REQUIRED = 137,
+    OFPR_BSN_ARP = 139,
+    OFPR_BSN_DHCP = 140,
+    OFPR_BSN_DEBUG = 141,
+    OFPR_BSN_PACKET_OF_DEATH = 142,
+};
+
+enum ofp_flow_removed_reason(wire_type=uint8_t) {
+    OFPRR_IDLE_TIMEOUT = 0,
+    OFPRR_HARD_TIMEOUT = 1,
+    OFPRR_DELETE = 2,
+    OFPRR_GROUP_DELETE = 3,
+    OFPRR_METER_DELETE = 4,
+    OFPRR_EVICTION = 5,
+};
+
+enum ofp_meter(wire_type=uint32_t, complete=False) {
+    OFPM_MAX = 0xffff0000,
+    OFPM_SLOWPATH = 0xfffffffd,
+    OFPM_CONTROLLER = 0xfffffffe,
+    OFPM_ALL = 0xffffffff,
+};
+
+enum ofp_meter_band_type(wire_type=uint16_t) {
+    OFPMBT_DROP = 0x1,
+    OFPMBT_DSCP_REMARK = 0x2,
+    OFPMBT_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_meter_mod_command(wire_type=uint16_t) {
+    OFPMC_ADD = 0,
+    OFPMC_MODIFY = 1,
+    OFPMC_DELETE = 2,
+};
+
+enum ofp_meter_flags(wire_type=uint16_t, bitmask=True) {
+    OFPMF_KBPS = 0x1,
+    OFPMF_PKTPS = 0x2,
+    OFPMF_BURST = 0x4,
+    OFPMF_STATS = 0x8,
+};
+
+enum ofp_error_type(wire_type=uint16_t) {
+    OFPET_HELLO_FAILED = 0,
+    OFPET_BAD_REQUEST = 1,
+    OFPET_BAD_ACTION = 2,
+    OFPET_BAD_INSTRUCTION = 3,
+    OFPET_BAD_MATCH = 4,
+    OFPET_FLOW_MOD_FAILED = 5,
+    OFPET_GROUP_MOD_FAILED = 6,
+    OFPET_PORT_MOD_FAILED = 7,
+    OFPET_TABLE_MOD_FAILED = 8,
+    OFPET_QUEUE_OP_FAILED = 9,
+    OFPET_SWITCH_CONFIG_FAILED = 10,
+    OFPET_ROLE_REQUEST_FAILED = 11,
+    OFPET_METER_MOD_FAILED = 12,
+    OFPET_TABLE_FEATURES_FAILED = 13,
+    OFPET_BAD_PROPERTY = 14,
+    OFPET_ASYNC_CONFIG_FAILED = 15,
+    OFPET_FLOW_MONITOR_FAILED = 16,
+    OFPET_BUNDLE_FAILED = 17,
+    OFPET_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_hello_failed_code(wire_type=uint16_t) {
+    OFPHFC_INCOMPATIBLE = 0,
+    OFPHFC_EPERM = 1,
+};
+
+enum ofp_bad_request_code(wire_type=uint16_t) {
+    OFPBRC_BAD_VERSION = 0,
+    OFPBRC_BAD_TYPE = 1,
+    OFPBRC_BAD_STAT = 2,
+    OFPBRC_BAD_EXPERIMENTER = 3,
+    OFPBRC_BAD_EXPERIMENTER_TYPE = 4,
+    OFPBRC_EPERM = 5,
+    OFPBRC_BAD_LEN = 6,
+    OFPBRC_BUFFER_EMPTY = 7,
+    OFPBRC_BUFFER_UNKNOWN = 8,
+    OFPBRC_BAD_TABLE_ID = 9,
+    OFPBRC_IS_SLAVE = 10,
+    OFPBRC_BAD_PORT = 11,
+    OFPBRC_BAD_PACKET = 12,
+    OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13,
+    OFPBRC_MULTIPART_REQUEST_TIMEOUT = 14,
+    OFPBRC_MULTIPART_REPLY_TIMEOUT = 15,
+};
+
+enum ofp_bad_action_code(wire_type=uint16_t) {
+    OFPBAC_BAD_TYPE = 0,
+    OFPBAC_BAD_LEN = 1,
+    OFPBAC_BAD_EXPERIMENTER = 2,
+    OFPBAC_BAD_EXPERIMENTER_TYPE = 3,
+    OFPBAC_BAD_OUT_PORT = 4,
+    OFPBAC_BAD_ARGUMENT = 5,
+    OFPBAC_EPERM = 6,
+    OFPBAC_TOO_MANY = 7,
+    OFPBAC_BAD_QUEUE = 8,
+    OFPBAC_BAD_OUT_GROUP = 9,
+    OFPBAC_MATCH_INCONSISTENT = 10,
+    OFPBAC_UNSUPPORTED_ORDER = 11,
+    OFPBAC_BAD_TAG = 12,
+    OFPBAC_BAD_SET_TYPE = 13,
+    OFPBAC_BAD_SET_LEN = 14,
+    OFPBAC_BAD_SET_ARGUMENT = 15,
+};
+
+enum ofp_bad_instruction_code(wire_type=uint16_t) {
+    OFPBIC_UNKNOWN_INST = 0,
+    OFPBIC_UNSUP_INST = 1,
+    OFPBIC_BAD_TABLE_ID = 2,
+    OFPBIC_UNSUP_METADATA = 3,
+    OFPBIC_UNSUP_METADATA_MASK = 4,
+    OFPBIC_BAD_EXPERIMENTER = 5,
+    OFPBIC_BAD_EXPERIMENTER_TYPE = 6,
+    OFPBIC_BAD_LEN = 7,
+    OFPBIC_EPERM = 8,
+    OFPBIC_DUP_INST = 9,
+};
+
+enum ofp_bad_match_code(wire_type=uint16_t) {
+    OFPBMC_BAD_TYPE = 0,
+    OFPBMC_BAD_LEN = 1,
+    OFPBMC_BAD_TAG = 2,
+    OFPBMC_BAD_DL_ADDR_MASK = 3,
+    OFPBMC_BAD_NW_ADDR_MASK = 4,
+    OFPBMC_BAD_WILDCARDS = 5,
+    OFPBMC_BAD_FIELD = 6,
+    OFPBMC_BAD_VALUE = 7,
+    OFPBMC_BAD_MASK = 8,
+    OFPBMC_BAD_PREREQ = 9,
+    OFPBMC_DUP_FIELD = 10,
+    OFPBMC_EPERM = 11,
+};
+
+enum ofp_flow_mod_failed_code(wire_type=uint16_t) {
+    OFPFMFC_UNKNOWN = 0,
+    OFPFMFC_TABLE_FULL = 1,
+    OFPFMFC_BAD_TABLE_ID = 2,
+    OFPFMFC_OVERLAP = 3,
+    OFPFMFC_EPERM = 4,
+    OFPFMFC_BAD_TIMEOUT = 5,
+    OFPFMFC_BAD_COMMAND = 6,
+    OFPFMFC_BAD_FLAGS = 7,
+    OFPFMFC_CANT_SYNC = 8,
+    OFPFMFC_BAD_PRIORITY = 9,
+};
+
+enum ofp_group_mod_failed_code(wire_type=uint16_t) {
+    OFPGMFC_GROUP_EXISTS = 0,
+    OFPGMFC_INVALID_GROUP = 1,
+    OFPGMFC_WEIGHT_UNSUPPORTED = 2,
+    OFPGMFC_OUT_OF_GROUPS = 3,
+    OFPGMFC_OUT_OF_BUCKETS = 4,
+    OFPGMFC_CHAINING_UNSUPPORTED = 5,
+    OFPGMFC_WATCH_UNSUPPORTED = 6,
+    OFPGMFC_LOOP = 7,
+    OFPGMFC_UNKNOWN_GROUP = 8,
+    OFPGMFC_CHAINED_GROUP = 9,
+    OFPGMFC_BAD_TYPE = 10,
+    OFPGMFC_BAD_COMMAND = 11,
+    OFPGMFC_BAD_BUCKET = 12,
+    OFPGMFC_BAD_WATCH = 13,
+    OFPGMFC_EPERM = 14,
+};
+
+enum ofp_port_mod_failed_code(wire_type=uint16_t) {
+    OFPPMFC_BAD_PORT = 0,
+    OFPPMFC_BAD_HW_ADDR = 1,
+    OFPPMFC_BAD_CONFIG = 2,
+    OFPPMFC_BAD_ADVERTISE = 3,
+    OFPPMFC_EPERM = 4,
+};
+
+enum ofp_table_mod_failed_code(wire_type=uint16_t) {
+    OFPTMFC_BAD_TABLE = 0,
+    OFPTMFC_BAD_CONFIG = 1,
+    OFPTMFC_EPERM = 2,
+};
+
+enum ofp_queue_op_failed_code(wire_type=uint16_t) {
+    OFPQOFC_BAD_PORT = 0,
+    OFPQOFC_BAD_QUEUE = 1,
+    OFPQOFC_EPERM = 2,
+};
+
+enum ofp_switch_config_failed_code(wire_type=uint16_t) {
+    OFPSCFC_BAD_FLAGS = 0,
+    OFPSCFC_BAD_LEN = 1,
+    OFPSCFC_EPERM = 2,
+};
+
+enum ofp_role_request_failed_code(wire_type=uint16_t){
+    OFPRRFC_STALE = 0,
+    OFPRRFC_UNSUP = 1,
+    OFPRRFC_BAD_ROLE = 2,
+};
+
+enum ofp_meter_mod_failed_code(wire_type=uint16_t) {
+    OFPMMFC_UNKNOWN = 0,
+    OFPMMFC_METER_EXISTS = 1,
+    OFPMMFC_INVALID_METER = 2,
+    OFPMMFC_UNKNOWN_METER = 3,
+    OFPMMFC_BAD_COMMAND = 4,
+    OFPMMFC_BAD_FLAGS = 5,
+    OFPMMFC_BAD_RATE = 6,
+    OFPMMFC_BAD_BURST = 7,
+    OFPMMFC_BAD_BAND = 8,
+    OFPMMFC_BAD_BAND_VALUE = 9,
+    OFPMMFC_OUT_OF_METERS = 10,
+    OFPMMFC_OUT_OF_BANDS = 11,
+};
+
+enum ofp_table_features_failed_code(wire_type=uint16_t) {
+    OFPTFFC_BAD_TABLE = 0,
+    OFPTFFC_BAD_METADATA = 1,
+    OFPTFFC_EPERM = 5,
+};
+
+enum ofp_bad_property_code(wire_type=uint16_t) {
+    OFPBPC_BAD_TYPE = 0, /* Unknown property type. */
+    OFPBPC_BAD_LEN = 1, /* Length problem in property. */
+    OFPBPC_BAD_VALUE = 2, /* Unsupported property value. */
+    OFPBPC_TOO_MANY = 3, /* Can’t handle this many properties. */
+    OFPBPC_DUP_TYPE = 4, /* A property type was duplicated. */
+    OFPBPC_BAD_EXPERIMENTER = 5, /* Unknown experimenter id specified. */
+    OFPBPC_BAD_EXP_TYPE = 6, /* Unknown exp_type for experimenter id. */
+    OFPBPC_BAD_EXP_VALUE = 7, /* Unknown value for experimenter id. */
+    OFPBPC_EPERM = 8, /* Permissions error. */
+};
+
+
+enum ofp_async_config_failed_code(wire_type=uint16_t) {
+    OFPACFC_INVALID = 0, /* One mask is invalid. */
+    OFPACFC_UNSUPPORTED = 1, /* Requested configuration not supported. */
+    OFPACFC_EPERM = 2, /* Permissions error. */
+};
+
+enum ofp_flow_monitor_failed_code(wire_type=uint16_t) {
+    OFPMOFC_UNKNOWN = 0, /* Unspecified error. */
+    OFPMOFC_MONITOR_EXISTS = 1, /* Monitor not added because a Monitor ADD
+                                 * attempted to replace an existing Monitor. */
+    OFPMOFC_INVALID_MONITOR = 2, /* Monitor not added because Monitor specified
+                                  * is invalid. */
+    OFPMOFC_UNKNOWN_MONITOR = 3, /* Monitor not modified because a Monitor
+                                    MODIFY attempted to modify a non-existent
+                                    Monitor. */
+    OFPMOFC_BAD_COMMAND = 4, /* Unsupported or unknown command. */
+    OFPMOFC_BAD_FLAGS = 5, /* Flag configuration unsupported. */
+    OFPMOFC_BAD_TABLE_ID = 6, /* Specified table does not exist. */
+    OFPMOFC_BAD_OUT = 7, /* Error in output port/group. */
+};
+
+enum ofp_bundle_failed_code(wire_type=uint16_t) {
+    OFPBFC_UNKNOWN = 0, /* Unspecified error. */
+    OFPBFC_EPERM = 1, /* Permissions error. */
+    OFPBFC_BAD_ID = 2, /* Bundle ID doesn’t exist. */
+    OFPBFC_BUNDLE_EXIST = 3, /* Bundle ID already exist. */
+    OFPBFC_BUNDLE_CLOSED = 4, /* Bundle ID is closed. */
+    OFPBFC_OUT_OF_BUNDLES = 5, /* Too many bundles IDs. */
+    OFPBFC_BAD_TYPE = 6, /* Unsupported or unknown message control type. */
+    OFPBFC_BAD_FLAGS = 7, /* Unsupported, unknown, or inconsistent flags. */
+    OFPBFC_MSG_BAD_LEN = 8, /* Length problem in included message. */
+    OFPBFC_MSG_BAD_XID = 9, /* Inconsistent or duplicate XID. */
+    OFPBFC_MSG_UNSUP = 10, /* Unsupported message in this bundle. */
+    OFPBFC_MSG_CONFLICT = 11, /* Unsupported message combination in this bundle. */
+    OFPBFC_MSG_TOO_MANY = 12, /* Cant handle this many messages in bundle. */
+    OFPBFC_MSG_FAILED = 13, /* One message in bundle failed. */
+    OFPBFC_TIMEOUT = 14, /* Bundle is taking too long. */
+    OFPBFC_BUNDLE_IN_PROGRESS = 15, /* Bundle is locking the resource. */
+};
+
+/* Port stats property types.
+ */
+enum ofp_port_stats_prop_type(wire_type=uint16_t) {
+    OFPPSPT_ETHERNET          = 0,      /* Ethernet property. */
+    OFPPSPT_OPTICAL           = 1,      /* Optical property. */
+    OFPPSPT_EXPERIMENTER      = 0xFFFF, /* Experimenter property. */
+};
+
+
+enum ofp_stats_type(wire_type=uint16_t) {
+    OFPST_DESC = 0,
+    OFPST_FLOW = 1,
+    OFPST_AGGREGATE = 2,
+    OFPST_TABLE = 3,
+    OFPST_PORT = 4,
+    OFPST_QUEUE = 5,
+    OFPST_GROUP = 6,
+    OFPST_GROUP_DESC = 7,
+    OFPST_GROUP_FEATURES = 8,
+    OFPST_METER = 9,
+    OFPST_METER_CONFIG = 10,
+    OFPST_METER_FEATURES = 11,
+    OFPST_TABLE_FEATURES = 12,
+    OFPST_PORT_DESC = 13,
+    OFPMP_TABLE_DESC = 14,
+    OFPMP_QUEUE_DESC = 15,
+    OFPMP_FLOW_MONITOR = 16,
+    OFPST_EXPERIMENTER = 0xffff,
+};
+
+enum ofp_stats_request_flags(wire_type=uint16_t, bitmask=True) {
+    OFPSF_REQ_MORE = 0x1,
+};
+
+enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
+    OFPSF_REPLY_MORE = 0x1,
+};
+
+enum ofp_table_feature_prop_type(wire_type=uint16_t) {
+    OFPTFPT_INSTRUCTIONS = 0,
+    OFPTFPT_INSTRUCTIONS_MISS = 1,
+    OFPTFPT_NEXT_TABLES = 2,
+    OFPTFPT_NEXT_TABLES_MISS = 3,
+    OFPTFPT_WRITE_ACTIONS = 4,
+    OFPTFPT_WRITE_ACTIONS_MISS = 5,
+    OFPTFPT_APPLY_ACTIONS = 6,
+    OFPTFPT_APPLY_ACTIONS_MISS = 7,
+    OFPTFPT_MATCH = 8,
+    OFPTFPT_WILDCARDS = 0xa,
+    OFPTFPT_WRITE_SETFIELD = 0xc,
+    OFPTFPT_WRITE_SETFIELD_MISS = 0xd,
+    OFPTFPT_APPLY_SETFIELD = 0xe,
+    OFPTFPT_APPLY_SETFIELD_MISS = 0xf,
+    OFPTFPT_TABLE_SYNC_FROM = 0x10,
+    OFPTFPT_EXPERIMENTER = 0xfffe,
+    OFPTFPT_EXPERIMENTER_MISS = 0xffff,
+};
+
+enum ofp_group_capabilities(wire_type=uint32_t, bitmask=True) {
+    OFPGFC_SELECT_WEIGHT = 0x1,
+    OFPGFC_SELECT_LIVENESS = 0x2,
+    OFPGFC_CHAINING = 0x4,
+    OFPGFC_CHAINING_CHECKS = 0x8,
+};
+
+enum ofp_controller_role(wire_type=uint32_t) {
+    OFPCR_ROLE_NOCHANGE = 0,
+    OFPCR_ROLE_EQUAL = 1,
+    OFPCR_ROLE_MASTER = 2,
+    OFPCR_ROLE_SLAVE = 3,
+};
+
+enum ofp_hello_elem_type(wire_type=uint16_t) {
+    OFPHET_VERSIONBITMAP = 1,
+};
+
+enum ofp_optical_port_features(wire_type=uint32_t, bitmask=True) {
+    OFPOPF_RX_TUNE = 0x1,
+    OFPOPF_TX_TUNE = 0x2,
+    OFPOPF_TX_PWR = 0x4,
+    OFPOPF_USE_FREQ = 0x8,
+};
+
+enum ofp_table_mod_prop_eviction_flag(wire_type=uint32_t, bitmask=True) {
+    OFPTMPEF_OTHER = 0x1,
+    OFPTMPEF_IMPORTANCE = 0x2,
+    OFPTMPEF_LIFETIME = 0x4,
+};
+
+enum ofp_port_stats_optical_flags(wire_type=uint32_t, bitmask=True) {
+    OFPOSF_RX_TUNE = 0x1,
+    OFPOSF_TX_TUNE = 0x2,
+    OFPOSF_TX_PWR = 0x4,
+    OFPOSF_RX_PWR = 0x10,
+    OFPOSF_TX_BIAS = 0x20,
+    OFPOSF_TX_TEMP = 0x40,
+};
+
+enum ofp_bundle_ctrl_type(wire_type=uint16_t) {
+    OFPBCT_OPEN_REQUEST = 0,
+    OFPBCT_OPEN_REPLY = 1,
+    OFPBCT_CLOSE_REQUEST = 2,
+    OFPBCT_CLOSE_REPLY = 3,
+    OFPBCT_COMMIT_REQUEST = 4,
+    OFPBCT_COMMIT_REPLY = 5,
+    OFPBCT_DISCARD_REQUEST = 6,
+    OFPBCT_DISCARD_REPLY = 7,
+};
+
+enum ofp_bundle_flags(wire_type=uint16_t, bitmask=True) {
+    OFPBF_ATOMIC = 1,
+    OFPBF_ORDERED = 2,
+};
+
+enum ofp_controller_role_reason(wire_type=uint8_t) {
+    OFPCRR_MASTER_REQUEST = 0,
+    OFPCRR_CONFIG = 1,
+    OFPCRR_EXPERIMENTER = 2,
+};
+
+enum ofp_table_reason(wire_type=uint8_t) {
+    OFPTR_VACANCY_DOWN = 3,
+    OFPTR_VACANCY_UP = 4,
+};
+
+enum ofp_requestforward_reason {
+    OFPRFR_GROUP_MOD = 0,
+    OFPRFR_METER_MOD = 1,
+};
+
+/* XXX rename to of_message */
+struct of_header {
+    uint8_t version;
+    uint8_t type == ?;
+    uint16_t length;
+    uint32_t xid;
+};
+
+struct of_uint64 {
+    uint64_t value;
+};
+
+// Special structures used for managing scalar list elements
+struct of_uint32 {
+    uint32_t value;
+};
+
+// Special structures used for managing scalar list elements
+struct of_uint8 {
+    uint8_t value;
+};
+
+struct of_hello_elem {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_hello_elem_versionbitmap : of_hello_elem {
+    uint16_t type == 1;
+    uint16_t length;
+    list(of_uint32_t) bitmaps;
+};
+
+struct of_hello : of_header {
+    uint8_t version;
+    uint8_t type == 0;
+    uint16_t length;
+    uint32_t xid;
+    list(of_hello_elem_t) elements;
+};
+
+struct of_echo_request : of_header {
+    uint8_t version;
+    uint8_t type == 2;
+    uint16_t length;
+    uint32_t xid;
+    of_octets_t data;
+};
+
+struct of_echo_reply : of_header {
+    uint8_t version;
+    uint8_t type == 3;
+    uint16_t length;
+    uint32_t xid;
+    of_octets_t data;
+};
+
+struct of_experimenter : of_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == ?;
+    uint32_t subtype;
+    of_octets_t data;
+};
+
+struct of_barrier_request : of_header {
+    uint8_t version;
+    uint8_t type == 20;
+    uint16_t length;
+    uint32_t xid;
+};
+
+struct of_barrier_reply : of_header {
+    uint8_t version;
+    uint8_t type == 21;
+    uint16_t length;
+    uint32_t xid;
+};
+
+struct of_get_config_request : of_header {
+    uint8_t version;
+    uint8_t type == 7;
+    uint16_t length;
+    uint32_t xid;
+};
+
+struct of_get_config_reply : of_header {
+    uint8_t version;
+    uint8_t type == 8;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_config_flags flags;
+    uint16_t miss_send_len;
+};
+
+struct of_set_config : of_header {
+    uint8_t version;
+    uint8_t type == 9;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_config_flags flags;
+    uint16_t miss_send_len;
+};
+
+struct of_table_mod_prop {
+    uint16_t type == ?; /* One of OFPTMPT_*. */
+    uint16_t length; /* Length in bytes of this property. */
+};
+
+struct of_table_mod_prop_eviction {
+    uint16_t type == 2;
+    uint16_t length;
+    enum ofp_table_mod_prop_eviction_flag flags;
+};
+
+struct of_table_mod_prop_vacancy {
+    uint16_t type == 3;
+    uint16_t length;
+    uint8_t vacancy_down;
+    uint8_t vacancy_up;
+    uint8_t vacancy;
+    pad(1);
+};
+
+struct of_table_mod_prop_experimenter {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_table_mod : of_header {
+    uint8_t version;
+    uint8_t type == 17;
+    uint16_t length;
+    uint32_t xid;
+    uint8_t table_id;
+    pad(3);
+    uint32_t config;
+    list(of_table_mod_prop_t) properties;
+};
+
+struct of_port_desc_prop {
+    uint16_t type == ?; /* One of OFPPDPT_*. */
+    uint16_t length; /* Length in bytes of this property. */
+};
+
+struct of_port_desc_prop_ethernet : of_port_desc_prop {
+    uint16_t type == 0;
+    uint16_t length;
+    pad(4);
+    uint32_t curr;
+    uint32_t advertised;
+    uint32_t supported;
+    uint32_t peer;
+    uint32_t curr_speed;
+    uint32_t max_speed;
+};
+
+struct of_port_desc_prop_optical : of_port_desc_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    pad(4);
+    uint32_t supported;
+    uint32_t tx_min_freq_lmda;
+    uint32_t tx_max_freq_lmda;
+    uint32_t tx_grid_freq_lmda;
+    uint32_t rx_min_freq_lmda;
+    uint32_t rx_max_freq_lmda;
+    uint32_t rx_grid_freq_lmda;
+    uint32_t tx_pwr_min;
+    uint32_t tx_pwr_max;
+};
+
+struct of_port_desc_prop_experimenter : of_port_desc_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_port_desc {
+    of_port_no_t port_no;
+    uint16_t length;
+    pad(2);
+    of_mac_addr_t hw_addr;
+    pad(2);
+    of_port_name_t name;
+    enum ofp_port_config config; /* Bitmap of OFPPC_* flags. */
+    enum ofp_port_state state; /* Bitmap of OFPPS_* flags. */
+    list(of_port_desc_prop_t) properties;
+};
+
+struct of_features_request : of_header {
+    uint8_t version;
+    uint8_t type == 5;
+    uint16_t length;
+    uint32_t xid;
+};
+
+struct of_features_reply : of_header {
+    uint8_t version;
+    uint8_t type == 6;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t datapath_id;
+    uint32_t n_buffers;
+    uint8_t n_tables;
+    uint8_t auxiliary_id;
+    pad(2);
+    enum ofp_capabilities capabilities;
+    uint32_t reserved;
+};
+
+struct of_port_status : of_header {
+    uint8_t version;
+    uint8_t type == 12;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_port_reason reason;
+    pad(7);
+    of_port_desc_t desc;
+};
+
+struct of_port_mod_prop {
+    uint16_t type == ?; /* One of OFPPMPT_*. */
+    uint16_t length; /* Length in bytes of this property. */
+};
+
+struct of_port_mod_prop_ethernet : of_port_mod_prop {
+    uint16_t type == 0;
+    uint16_t length;
+    uint32_t advertise;
+};
+
+struct of_port_mod_prop_optical : of_port_mod_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    uint32_t configure;
+    uint32_t freq_ldma;
+    uint32_t fl_offset; /* TODO signed */
+    uint32_t grid_span;
+    uint32_t tx_pwr;
+};
+
+struct of_port_mod_prop_experimenter : of_port_mod_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_port_mod : of_header {
+    uint8_t version;
+    uint8_t type == 16;
+    uint16_t length;
+    uint32_t xid;
+    of_port_no_t port_no;
+    pad(4);
+    of_mac_addr_t hw_addr;
+    pad(2);
+    uint32_t config;
+    uint32_t mask;
+    list(of_port_mod_prop_t) properties;
+};
+
+struct of_match_v3(align=8, length_includes_align=False) {
+    uint16_t type == 1;
+    uint16_t length;
+    list(of_oxm_t) oxm_list;
+};
+
+// This looks like an action header, but is standalone.  See
+// ofp_table_features_prop_actions
+struct of_action_id {
+    uint16_t type;
+    uint16_t len;
+    of_octets_t exp_data;
+};
+
+struct of_action_output : of_action {
+    uint16_t type == 0;
+    uint16_t len;
+    of_port_no_t port;
+    uint16_t max_len;
+    pad(6);
+};
+
+struct of_action_copy_ttl_out : of_action {
+    uint16_t type == 11;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_copy_ttl_in : of_action {
+    uint16_t type == 12;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_set_mpls_ttl : of_action {
+    uint16_t type == 15;
+    uint16_t len;
+    uint8_t mpls_ttl;
+    pad(3);
+};
+
+struct of_action_dec_mpls_ttl : of_action {
+    uint16_t type == 16;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_push_vlan : of_action {
+    uint16_t type == 17;
+    uint16_t len;
+    uint16_t ethertype;
+    pad(2);
+};
+
+struct of_action_pop_vlan : of_action {
+    uint16_t type == 18;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_push_mpls : of_action {
+    uint16_t type == 19;
+    uint16_t len;
+    uint16_t ethertype;
+    pad(2);
+};
+
+struct of_action_pop_mpls : of_action {
+    uint16_t type == 20;
+    uint16_t len;
+    uint16_t ethertype;
+    pad(2);
+};
+
+struct of_action_set_queue : of_action {
+    uint16_t type == 21;
+    uint16_t len;
+    uint32_t queue_id;
+};
+
+struct of_action_group : of_action {
+    uint16_t type == 22;
+    uint16_t len;
+    uint32_t group_id;
+};
+
+struct of_action_set_nw_ttl : of_action {
+    uint16_t type == 23;
+    uint16_t len;
+    uint8_t nw_ttl;
+    pad(3);
+};
+
+struct of_action_dec_nw_ttl : of_action {
+    uint16_t type == 24;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_set_field(align=8, length_includes_align=True) : of_action {
+    uint16_t type == 25;
+    uint16_t len;
+    of_oxm_t field;
+};
+
+struct of_action_experimenter(align=8, length_includes_align=True): of_action {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == ?;
+    of_octets_t data;
+};
+
+struct of_action_pop_pbb : of_action {
+    uint16_t type == 27;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_action_push_pbb : of_action {
+    uint16_t type == 26;
+    uint16_t len;
+    uint16_t ethertype;
+    pad(2);
+};
+
+struct of_action {
+    uint16_t type == ?;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_instruction_id {
+    uint16_t type;
+    uint16_t len;
+};
+
+struct of_instruction {
+    uint16_t type == ?;
+    uint16_t len;
+};
+
+struct of_instruction_goto_table : of_instruction {
+    uint16_t type == 1;
+    uint16_t len;
+    uint8_t table_id;
+    pad(3);
+};
+
+struct of_instruction_write_metadata : of_instruction {
+    uint16_t type == 2;
+    uint16_t len;
+    pad(4);
+    uint64_t metadata;
+    uint64_t metadata_mask;
+};
+
+struct of_instruction_write_actions : of_instruction {
+    uint16_t type == 3;
+    uint16_t len;
+    pad(4);
+    list(of_action_t) actions;
+};
+
+struct of_instruction_apply_actions : of_instruction {
+    uint16_t type == 4;
+    uint16_t len;
+    pad(4);
+    list(of_action_t) actions;
+};
+
+struct of_instruction_clear_actions : of_instruction {
+    uint16_t type == 5;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_instruction_meter : of_instruction {
+    uint16_t type == 6;
+    uint16_t len;
+    uint32_t meter_id;
+};
+
+struct of_instruction_experimenter : of_instruction {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == ?;
+    of_octets_t data;
+};
+
+struct of_flow_mod : of_header {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == ?;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    pad(2);
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_add : of_flow_mod {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == 0;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_modify : of_flow_mod {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == 1;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_modify_strict : of_flow_mod {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == 2;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_delete : of_flow_mod {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == 3;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_delete_strict : of_flow_mod {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command == 4;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_bucket {
+    uint16_t len;
+    uint16_t weight;
+    of_port_no_t watch_port;
+    uint32_t watch_group;
+    pad(4);
+    list(of_action_t) actions;
+};
+
+struct of_group_mod : of_header {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == ?;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_add : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 0;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_modify : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 1;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_delete : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 2;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_packet_out : of_header {
+    uint8_t version;
+    uint8_t type == 13;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t buffer_id;
+    of_port_no_t in_port;
+    uint16_t actions_len;
+    pad(6);
+    list(of_action_t) actions;
+    of_octets_t data;
+};
+
+struct of_packet_in : of_header {
+    uint8_t version;
+    uint8_t type == 10;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t buffer_id;
+    uint16_t total_len;
+    uint8_t reason;
+    uint8_t table_id;
+    uint64_t cookie;
+    of_match_t match;
+    pad(2);
+    of_octets_t data;
+};
+
+struct of_flow_removed : of_header {
+    uint8_t version;
+    uint8_t type == 11;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint16_t priority;
+    uint8_t reason;
+    uint8_t table_id;
+    uint32_t duration_sec;
+    uint32_t duration_nsec;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint64_t packet_count;
+    uint64_t byte_count;
+    of_match_t match;
+};
+
+struct of_meter_band {
+    uint16_t        type == ?;
+    uint16_t        len;
+//    uint32_t        rate;  // These are excluded b/c this is the header
+//    uint32_t        burst_size;  // These are excluded b/c this is the header
+};
+
+struct of_meter_band_drop : of_meter_band {
+    uint16_t        type == 1;
+    uint16_t        len;
+    uint32_t        rate;
+    uint32_t        burst_size;
+    pad(4);
+};
+
+struct of_meter_band_dscp_remark : of_meter_band {
+    uint16_t        type == 2;
+    uint16_t        len;
+    uint32_t        rate;
+    uint32_t        burst_size;
+    uint8_t         prec_level;
+    pad(3);
+};
+
+struct of_meter_band_experimenter : of_meter_band {
+    uint16_t        type == 65535;
+    uint16_t        len;
+    uint32_t        rate;
+    uint32_t        burst_size;
+    uint32_t        experimenter;
+};
+
+struct of_meter_mod : of_header {
+    uint8_t version;
+    uint8_t type == 29;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t command;
+    uint16_t flags;
+    uint32_t meter_id;
+    list(of_meter_band_t) bands;
+};
+
+struct of_error_msg : of_header {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == ?;
+};
+
+struct of_hello_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 0;
+    enum ofp_hello_failed_code code;
+    of_octets_t data;
+};
+
+struct of_bad_request_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 1;
+    enum ofp_bad_request_code code;
+    of_octets_t data;
+};
+
+struct of_bad_action_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 2;
+    enum ofp_bad_action_code code;
+    of_octets_t data;
+};
+
+struct of_bad_instruction_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 3;
+    enum ofp_bad_instruction_code code;
+    of_octets_t data;
+};
+
+struct of_bad_match_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 4;
+    enum ofp_bad_match_code code;
+    of_octets_t data;
+};
+
+struct of_flow_mod_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 5;
+    enum ofp_flow_mod_failed_code code;
+    of_octets_t data;
+};
+
+struct of_group_mod_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 6;
+    enum ofp_group_mod_failed_code code;
+    of_octets_t data;
+};
+
+struct of_port_mod_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 7;
+    enum ofp_port_mod_failed_code code;
+    of_octets_t data;
+};
+
+struct of_table_mod_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 8;
+    enum ofp_table_mod_failed_code code;
+    of_octets_t data;
+};
+
+struct of_queue_op_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 9;
+    enum ofp_queue_op_failed_code code;
+    of_octets_t data;
+};
+
+struct of_switch_config_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 10;
+    enum ofp_switch_config_failed_code code;
+    of_octets_t data;
+};
+
+struct of_role_request_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 11;
+    enum ofp_role_request_failed_code code;
+    of_octets_t data;
+};
+
+struct of_meter_mod_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 12;
+    enum ofp_meter_mod_failed_code code;
+    of_octets_t data;
+};
+
+struct of_table_features_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 13;
+    enum ofp_table_features_failed_code code;
+    of_octets_t data;
+};
+
+struct of_bad_property_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 14;
+    enum ofp_bad_property_code code;
+    of_octets_t data;
+};
+
+struct of_async_config_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 15;
+    enum ofp_async_config_failed_code code;
+    of_octets_t data;
+};
+
+struct of_flow_monitor_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 16;
+    enum ofp_flow_monitor_failed_code code;
+    of_octets_t data;
+};
+
+struct of_bundle_failed_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 17;
+    enum ofp_bundle_failed_code code;
+    of_octets_t data;
+};
+
+struct of_experimenter_error_msg : of_error_msg {
+    uint8_t version;
+    uint8_t type == 1;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t err_type == 0xffff;
+    uint16_t subtype;
+    uint32_t experimenter;
+    of_octets_t data;
+};
+
+// STATS ENTRIES: flow, table, port, queue, group stats, group desc stats
+
+struct of_flow_stats_entry {
+    uint16_t length;
+    uint8_t table_id;
+    pad(1);
+    uint32_t duration_sec;
+    uint32_t duration_nsec;
+    uint16_t priority;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    enum ofp_flow_mod_flags flags;
+    uint16_t importance;
+    pad(2);
+    uint64_t cookie;
+    uint64_t packet_count;
+    uint64_t byte_count;
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+
+struct of_table_stats_entry {
+    uint8_t table_id;
+    pad(3);
+    uint32_t active_count;
+    uint64_t lookup_count;
+    uint64_t matched_count;
+};
+
+/* Common header for all port stats properties. */
+struct of_port_stats_prop {
+    uint16_t         type == ?; /* One of OFPPSPT_*. */
+    uint16_t         length;  /* Length in bytes of this property. */
+};
+
+/* Ethernet port stats property. */
+struct of_port_stats_prop_ethernet : of_port_stats_prop {
+    uint16_t         type == 0; /* OFPPSPT_ETHERNET. */
+    uint16_t         length;  /* Length in bytes of this property. */
+    pad(4);
+
+    uint64_t rx_frame_err;   /* Number of frame alignment errors. */
+    uint64_t rx_over_err;    /* Number of packets with RX overrun. */
+    uint64_t rx_crc_err;     /* Number of CRC errors. */
+    uint64_t collisions;     /* Number of collisions. */
+};
+
+/* Optical port stats property. */
+struct of_port_stats_prop_optical : of_port_stats_prop {
+    uint16_t         type == 1;
+    uint16_t         length;
+    pad(4);
+
+    uint32_t flags;       
+    uint32_t tx_freq_lmda;
+    uint32_t tx_offset;
+    uint32_t tx_grid_span;
+    uint32_t rx_freq_lmda;
+    uint32_t rx_offset;
+    uint32_t rx_grid_span;
+    uint16_t tx_pwr;
+    uint16_t rx_pwr;
+    uint16_t bias_current;
+    uint16_t temperature;
+};
+
+/* Experimenter port stats property. */
+struct of_port_stats_prop_experimenter : of_port_stats_prop {
+    uint16_t         type == 0xffff;
+    uint16_t         length;
+    uint32_t         experimenter == ?;
+    uint32_t         exp_type;
+    of_octets_t      experimenter_data;
+};
+
+struct of_port_stats_entry {
+    uint16_t length;
+    pad(2);
+    of_port_no_t port_no;
+    uint32_t duration_sec;
+    uint32_t duration_nsec;
+    uint64_t rx_packets;
+    uint64_t tx_packets;
+    uint64_t rx_bytes;
+    uint64_t tx_bytes;
+    uint64_t rx_dropped;
+    uint64_t tx_dropped;
+    uint64_t rx_errors;
+    uint64_t tx_errors;
+    list(of_port_stats_prop_t) properties;
+};
+
+struct of_queue_stats_prop {
+    uint16_t         type == ?;
+    uint16_t         length;
+};
+
+struct of_queue_stats_prop_experimenter : of_queue_stats_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_queue_stats_entry {
+    uint16_t length;
+    pad(6);
+    of_port_no_t port_no;
+    uint32_t queue_id;
+    uint64_t tx_bytes;
+    uint64_t tx_packets;
+    uint64_t tx_errors;
+    uint32_t duration_sec;
+    uint32_t duration_nsec;
+    list(of_queue_stats_prop_t) properties;
+};
+
+struct of_bucket_counter {
+    uint64_t packet_count;
+    uint64_t byte_count;
+};
+
+struct of_group_stats_entry {
+    uint16_t length;
+    pad(2);
+    uint32_t group_id;
+    uint32_t ref_count;
+    pad(4);
+    uint64_t packet_count;
+    uint64_t byte_count;
+    uint32_t duration_sec;
+    uint32_t duration_nsec;
+    list(of_bucket_counter_t) bucket_stats;
+};
+
+struct of_group_desc_stats_entry {
+    uint16_t length;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+// STATS:
+//  Desc, flow, agg, table, port, queue, group, group_desc, group_feat, experi
+
+struct of_stats_request : of_header {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == ?;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_stats_reply : of_header {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == ?;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+};
+
+struct of_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    of_desc_str_t mfr_desc;
+    of_desc_str_t hw_desc;
+    of_desc_str_t sw_desc;
+    of_serial_num_t serial_num;
+    of_desc_str_t dp_desc;
+};
+
+struct of_flow_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 1;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint8_t table_id;
+    pad(3);
+    of_port_no_t out_port;
+    uint32_t out_group;
+    pad(4);
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    of_match_t match;
+};
+
+struct of_flow_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 1;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_flow_stats_entry_t) entries;
+};
+
+struct of_aggregate_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 2;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint8_t table_id;
+    pad(3);
+    of_port_no_t out_port;
+    uint32_t out_group;
+    pad(4);
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    of_match_t match;
+};
+
+struct of_aggregate_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 2;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint64_t packet_count;
+    uint64_t byte_count;
+    uint32_t flow_count;
+    pad(4);
+};
+
+struct of_table_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 3;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_table_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 3;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_table_stats_entry_t) entries;
+};
+
+struct of_experimenter_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == ?;
+    uint32_t subtype;
+};
+
+struct of_experimenter_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == ?;
+    uint32_t subtype;
+};
+
+// FIXME: These are padded to 8 byte align beyond the length indicated
+
+struct of_table_feature_prop {
+    uint16_t         type == ?;
+    uint16_t         length;
+};
+
+struct of_table_feature_prop_instructions : of_table_feature_prop {
+    uint16_t         type == 0;
+    uint16_t         length;
+    // FIXME Check if instruction_t is right for ids here
+    list(of_instruction_id_t)   instruction_ids;
+};
+
+struct of_table_feature_prop_instructions_miss : of_table_feature_prop {
+    uint16_t         type == 1;
+    uint16_t         length;
+    list(of_instruction_id_t)   instruction_ids;
+};
+
+struct of_table_feature_prop_next_tables : of_table_feature_prop {
+    uint16_t         type == 2;
+    uint16_t         length;
+    list(of_uint8_t) next_table_ids;
+};
+
+struct of_table_feature_prop_next_tables_miss : of_table_feature_prop {
+    uint16_t         type == 3;
+    uint16_t         length;
+    list(of_uint8_t) next_table_ids;
+};
+
+struct of_table_feature_prop_write_actions : of_table_feature_prop {
+    uint16_t         type == 4;
+    uint16_t         length;
+    list(of_action_id_t) action_ids;
+};
+
+struct of_table_feature_prop_write_actions_miss : of_table_feature_prop {
+    uint16_t         type == 5;
+    uint16_t         length;
+    list(of_action_id_t) action_ids;
+};
+
+struct of_table_feature_prop_apply_actions : of_table_feature_prop {
+    uint16_t         type == 6;
+    uint16_t         length;
+    list(of_action_id_t) action_ids;
+};
+
+struct of_table_feature_prop_apply_actions_miss : of_table_feature_prop {
+    uint16_t         type == 7;
+    uint16_t         length;
+    list(of_action_id_t) action_ids;
+};
+
+struct of_table_feature_prop_match : of_table_feature_prop {
+    uint16_t         type == 8;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_wildcards : of_table_feature_prop {
+    uint16_t         type == 10;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_write_setfield : of_table_feature_prop {
+    uint16_t         type == 12;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_write_setfield_miss : of_table_feature_prop {
+    uint16_t         type == 13;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_apply_setfield : of_table_feature_prop {
+    uint16_t         type == 14;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_apply_setfield_miss : of_table_feature_prop {
+    uint16_t         type == 15;
+    uint16_t         length;
+    list(of_uint32_t) oxm_ids;
+};
+
+struct of_table_feature_prop_table_sync_from : of_table_feature_prop {
+    uint16_t         type == 16;
+    uint16_t         length;
+    list(of_uint8_t) table_ids;
+};
+
+struct of_table_feature_prop_experimenter : of_table_feature_prop {
+    uint16_t         type == 65534;
+    uint16_t         length;
+    uint32_t         experimenter == ?;
+    uint32_t         subtype;
+    of_octets_t      experimenter_data;
+};
+
+struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
+    uint16_t         type == 65535;
+    uint16_t         length;
+    uint32_t         experimenter == ?;
+    uint32_t         subtype;
+    of_octets_t      experimenter_data;
+};
+
+struct of_table_features {
+    uint16_t length;
+    uint8_t table_id;
+    pad(5);
+    of_table_name_t name;
+    uint64_t metadata_match;
+    uint64_t metadata_write;
+    uint32_t config;
+    uint32_t max_entries;
+    list(of_table_feature_prop_t) properties;
+};
+
+struct of_meter_features {
+    uint32_t    max_meter;
+    uint32_t    band_types;
+    uint32_t    capabilities;
+    uint8_t     max_bands;
+    uint8_t     max_color;
+    pad(2);
+};
+
+struct of_port_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 4;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    of_port_no_t port_no;
+    pad(4);
+};
+
+struct of_port_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 4;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_port_stats_entry_t) entries;
+};
+
+struct of_queue_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 5;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    of_port_no_t port_no;
+    uint32_t queue_id;
+};
+
+struct of_queue_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 5;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_queue_stats_entry_t) entries;
+};
+
+struct of_group_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 6;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t group_id;
+    pad(4);
+};
+
+struct of_group_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 6;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_group_stats_entry_t) entries;
+};
+
+struct of_group_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 7;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_group_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 7;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_group_desc_stats_entry_t) entries;
+};
+
+struct of_group_features_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 8;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_group_features_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 8;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t types;
+    uint32_t capabilities;
+    uint32_t max_groups_all;
+    uint32_t max_groups_select;
+    uint32_t max_groups_indirect;
+    uint32_t max_groups_ff;
+    uint32_t actions_all;
+    uint32_t actions_select;
+    uint32_t actions_indirect;
+    uint32_t actions_ff;
+};
+
+struct of_meter_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 9;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t meter_id;
+    pad(4);
+};
+
+struct of_meter_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 9;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_meter_stats_t) entries;
+};
+
+struct of_meter_config_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 10;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t meter_id;
+    pad(4);
+};
+
+struct of_meter_config_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 10;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_meter_band_t) entries;
+};
+
+// FIXME stats added to get things working
+struct of_meter_features_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 11;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+// FIXME stats added to get things working
+struct of_meter_features_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 11;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    of_meter_features_t features;
+};
+
+// FIXME stats added to get things working
+struct of_table_features_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 12;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    list(of_table_features_t) entries;
+};
+
+// FIXME stats added to get things working
+struct of_table_features_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 12;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_table_features_t) entries;
+};
+
+// FIXME stats added to get things working
+struct of_port_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 13;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+// FIXME stats added to get things working
+struct of_port_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 13;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_port_desc_t) entries;
+};
+
+struct of_table_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 14;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_table_desc {
+    uint16_t length;
+    uint8_t table_id;
+    pad(1);
+    enum ofp_table_config config;
+};
+
+struct of_table_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 14;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_table_desc_t) entries;
+};
+
+struct of_queue_desc_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 15;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+};
+
+struct of_queue_desc_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_queue_desc_prop_min_rate : of_queue_desc_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    uint16_t rate;
+    pad(2);
+};
+
+struct of_queue_desc_prop_max_rate : of_queue_desc_prop {
+    uint16_t type == 2;
+    uint16_t length;
+    uint16_t rate;
+    pad(2);
+};
+
+struct of_queue_desc_prop_experimenter : of_queue_desc_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_queue_desc {
+    uint32_t port_no;
+    uint32_t queue_id;
+    uint16_t length;
+    pad(6);
+    list(of_queue_desc_prop_t) properties;
+};
+
+struct of_queue_desc_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 15;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    list(of_queue_desc_t) entries;
+};
+
+/*
+ * Not supporting the flow monitor multipart messages. This message is
+ * poorly designed because it includes a variable length match inside a
+ * struct (ofp_flow_monitor_request) with no explicit length member.
+ * I'm not writing the special case code to figure out the total length.
+ */
+
+struct of_meter_band_stats {
+    uint64_t        packet_band_count;
+    uint64_t        byte_band_count;
+};
+
+struct of_meter_stats {
+    uint32_t        meter_id;
+    uint16_t        len;
+    pad(6);
+    uint32_t        flow_count;
+    uint64_t        packet_in_count;
+    uint64_t        byte_in_count;
+    uint32_t   duration_sec;
+    uint32_t   duration_nsec;
+    list(of_meter_band_stats_t) band_stats;
+};
+
+struct of_meter_config {
+    uint16_t        length;
+    uint16_t        flags;
+    uint32_t        meter_id;
+    list(of_meter_band_t) entries;
+};
+
+// END OF STATS OBJECTS
+
+struct of_queue_prop {
+    uint16_t type == ?;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_queue_prop_min_rate : of_queue_prop {
+    uint16_t type == 1;
+    uint16_t len;
+    pad(4);
+    uint16_t rate;
+    pad(6);
+};
+
+struct of_queue_prop_max_rate : of_queue_prop {
+    uint16_t type == 2;
+    uint16_t len;
+    pad(4);
+    uint16_t rate;
+    pad(6);
+};
+
+struct of_queue_prop_experimenter : of_queue_prop {
+    uint16_t type == 65535;
+    uint16_t len;
+    pad(4);
+    uint32_t experimenter == ?;
+    pad(4);
+    of_octets_t data;
+};
+
+struct of_packet_queue {
+    uint32_t queue_id;
+    of_port_no_t port;
+    uint16_t len;
+    pad(6);
+    list(of_queue_prop_t) properties;
+};
+
+struct of_role_request : of_header {
+    uint8_t version;
+    uint8_t type == 24;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_controller_role role;
+    pad(4);
+    uint64_t generation_id;
+};
+
+struct of_role_reply : of_header {
+    uint8_t version;
+    uint8_t type == 25;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_controller_role role;
+    pad(4);
+    uint64_t generation_id;
+};
+
+/* Bundle messages */
+
+struct of_bundle_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_bundle_prop_experimenter : of_bundle_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_bundle_ctrl_msg : of_header {
+    uint8_t version;
+    uint8_t type == 33;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t bundle_id;
+    enum ofp_bundle_ctrl_type bundle_ctrl_type;
+    enum ofp_bundle_flags flags;
+    list(of_bundle_prop_t) properties;
+};
+
+struct of_bundle_add_msg : of_header {
+    uint8_t version;
+    uint8_t type == 34;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t bundle_id;
+    pad(2);
+    enum ofp_bundle_flags flags;
+    // TODO support embedding of_header
+    of_octets_t data;
+    // TODO support trailing properties
+};
+
+/* Async config messages */
+
+struct of_async_config_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_async_config_prop_packet_in_slave : of_async_config_prop {
+    uint16_t type == 0;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_packet_in_master : of_async_config_prop {
+    uint16_t type == 1;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_port_status_slave : of_async_config_prop {
+    uint16_t type == 2;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_port_status_master : of_async_config_prop {
+    uint16_t type == 3;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_flow_removed_slave : of_async_config_prop {
+    uint16_t type == 4;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_flow_removed_master : of_async_config_prop {
+    uint16_t type == 5;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_role_status_slave : of_async_config_prop {
+    uint16_t type == 6;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_role_status_master : of_async_config_prop {
+    uint16_t type == 7;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_table_status_slave : of_async_config_prop {
+    uint16_t type == 8;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_table_status_master : of_async_config_prop {
+    uint16_t type == 9;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_requestforward_slave : of_async_config_prop {
+    uint16_t type == 10;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_requestforward_master : of_async_config_prop {
+    uint16_t type == 11;
+    uint16_t length;
+    uint32_t mask;
+};
+
+struct of_async_config_prop_experimenter_slave : of_async_config_prop {
+    uint16_t type == 0xfffe;
+    uint16_t length;
+};
+
+struct of_async_config_prop_experimenter_master : of_async_config_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+};
+
+struct of_async_get_request : of_header {
+    uint8_t version;
+    uint8_t type == 26;
+    uint16_t length;
+    uint32_t xid;
+    list(of_async_config_prop_t) properties;
+};
+
+struct of_async_get_reply : of_header {
+    uint8_t version;
+    uint8_t type == 27;
+    uint16_t length;
+    uint32_t xid;
+    list(of_async_config_prop_t) properties;
+};
+
+struct of_async_set : of_header {
+    uint8_t version;
+    uint8_t type == 28;
+    uint16_t length;
+    uint32_t xid;
+    list(of_async_config_prop_t) properties;
+};
+
+/* Role status message */
+
+struct of_role_prop {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+struct of_role_prop_experimenter : of_role_prop {
+    uint16_t type == 0xffff;
+    uint16_t length;
+    uint32_t experimenter == ?;
+    uint32_t exp_type;
+};
+
+struct of_role_status : of_header {
+    uint8_t version;
+    uint8_t type == 30;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    enum ofp_controller_role_reason reason;
+    pad(3);
+    uint64_t generation_id;
+    list(of_role_prop_t) properties;
+};
+
+/* Table status messages */
+
+struct of_table_status : of_header {
+    uint8_t version;
+    uint8_t type == 31;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    enum ofp_table_reason reason;
+    pad(7);
+    of_table_desc_t table;
+};
+
+/* Request forward message */
+
+struct of_requestforward : of_header {
+    uint8_t version;
+    uint8_t type == 32;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t role;
+    // TODO support embedding of_header
+    of_octets_t data;
+};
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index 9c32e7f..9c741d2 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -26,16 +26,13 @@
 # under the EPL.
 
 from collections import defaultdict
+import os
 import loxi_globals
-import struct
 import template_utils
 import loxi_utils.loxi_utils as utils
 import util
-import oftype
 from loxi_ir import *
 
-modules_by_version = {}
-
 # Map from inheritance root to module name
 roots = {
     'of_header': 'message',
@@ -46,6 +43,18 @@
     'of_instruction_id': 'instruction_id',
     'of_meter_band': 'meter_band',
     'of_bsn_tlv': 'bsn_tlv',
+    'of_port_desc_prop': 'port_desc_prop',
+    'of_port_stats_prop': 'port_stats_prop',
+    'of_port_mod_prop': 'port_mod_prop',
+    'of_table_mod_prop': 'table_mod_prop',
+    'of_queue_desc_prop': 'queue_desc_prop',
+    'of_queue_stats_prop': 'queue_stats_prop',
+    'of_async_config_prop': 'async_config_prop',
+    'of_bundle_prop': 'bundle_prop',
+    #'of_queue_prop': 'queue_prop',
+    'of_role_prop': 'role_prop',
+    #'of_table_feature_prop': 'table_feature_prop',
+    'of_table_mod_prop': 'table_mod_prop',
 }
 
 # Return the module and class names for the generated Python class
@@ -69,63 +78,36 @@
         modules[module_name].append(ofclass)
     return modules
 
-def generate_init(out, name, version):
-    util.render_template(out, 'init.py', version=version)
+def codegen(install_dir):
+    def render(name, template_name=None, **ctx):
+        if template_name is None:
+            template_name = os.path.basename(name)
+        with template_utils.open_output(install_dir, name) as out:
+            util.render_template(out, template_name, **ctx)
 
-def generate_action(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['action'],
-                         version=version)
+    render('__init__.py', template_name='toplevel_init.py')
+    render('pp.py')
+    render('generic_util.py')
 
-def generate_action_id(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['action_id'],
-                         version=version)
+    for version in loxi_globals.OFVersions.all_supported:
+        subdir = 'of' + version.version.replace('.', '')
+        modules = build_ofclasses(version)
 
-def generate_oxm(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['oxm'],
-                         version=version)
+        render(os.path.join(subdir, '__init__.py'), template_name='init.py',
+               version=version, modules=modules.keys())
 
-def generate_common(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['common'],
-                         version=version,
-                         extra_template='_common_extra.py')
+        render(os.path.join(subdir, 'util.py'), version=version)
 
-def generate_const(out, name, version):
-    util.render_template(out, 'const.py', version=version,
-                         enums=loxi_globals.ir[version].enums)
+        render(os.path.join(subdir, 'const.py'), version=version,
+               enums=loxi_globals.ir[version].enums)
 
-def generate_instruction(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['instruction'],
-                         version=version)
+        args_by_module = {
+            'common': { 'extra_template' : '_common_extra.py' },
+            'message': { 'extra_template' : '_message_extra.py' },
+        }
 
-def generate_instruction_id(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['instruction_id'],
-                         version=version)
-
-def generate_message(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['message'],
-                         version=version,
-                         extra_template='_message_extra.py')
-
-def generate_meter_band(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['meter_band'],
-                         version=version)
-
-def generate_util(out, name, version):
-    util.render_template(out, 'util.py', version=version)
-
-def generate_bsn_tlv(out, name, version):
-    util.render_template(out, 'module.py',
-                         ofclasses=modules_by_version[version]['bsn_tlv'],
-                         version=version)
-
-def init():
-    for version in loxi_globals.OFVersions.target_versions:
-        modules_by_version[version] = build_ofclasses(version)
+        for name, ofclasses in modules.items():
+            args = args_by_module.get(name, {})
+            render(os.path.join(subdir, name + '.py'), template_name='module.py',
+                   version=version, ofclasses=ofclasses, subdir=subdir,
+                   **args)
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 7bd242e..76eebd0 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -110,12 +110,17 @@
     'of_oxm_t': OFTypeData(
         init='None',
         pack='%s.pack()',
-        unpack='oxm.oxm.unpack(%s)'),
+        unpack='ofp.oxm.oxm.unpack(%s)'),
 
     'of_checksum_128_t': OFTypeData(
         init='0',
         pack='util.pack_checksum_128(%s)',
         unpack="util.unpack_checksum_128(%s)"),
+
+    'of_bitmap_512_t': OFTypeData(
+        init='set()',
+        pack='util.pack_bitmap_512(%s)',
+        unpack="util.unpack_bitmap_512(%s)"),
 }
 
 ## Fixed length strings
@@ -139,10 +144,11 @@
 
 # Map from class name to Python class name
 embedded_structs = {
-    'of_match_t': 'common.match',
-    'of_port_desc_t': 'common.port_desc',
-    'of_meter_features_t': 'common.meter_features',
-    'of_bsn_vport_t': 'common.bsn_vport',
+    'of_match_t': 'ofp.match',
+    'of_port_desc_t': 'ofp.port_desc',
+    'of_meter_features_t': 'ofp.meter_features',
+    'of_bsn_vport_t': 'ofp.bsn_vport',
+    'of_table_desc_t': 'ofp.table_desc',
 }
 
 for (cls, pyclass) in embedded_structs.items():
@@ -190,8 +196,9 @@
     elif oftype_is_list(oftype):
         ofproto = loxi_globals.ir[version]
         ofclass = ofproto.class_by_name(oftype_list_elem(oftype))
+        assert ofclass, "No class named %r" % oftype_list_elem(oftype)
         module_name, class_name = py_gen.codegen.generate_pyname(ofclass)
-        return 'loxi.generic_util.unpack_list(%s, %s.%s.unpack)' % \
+        return 'loxi.generic_util.unpack_list(%s, ofp.%s.%s.unpack)' % \
             (reader_expr, module_name, class_name)
     else:
         return "loxi.unimplemented('unpack %s')" % oftype
diff --git a/py_gen/templates/_common_extra.py b/py_gen/templates/_common_extra.py
index 8639dc4..f801965 100644
--- a/py_gen/templates/_common_extra.py
+++ b/py_gen/templates/_common_extra.py
@@ -35,4 +35,7 @@
 :: elif version == OFVersions.VERSION_1_3:
 :: # HACK
 match = match_v3
+:: elif version == OFVersions.VERSION_1_4:
+:: # HACK
+match = match_v3
 :: #endif
diff --git a/py_gen/templates/_message_extra.py b/py_gen/templates/_message_extra.py
index 9fc2f5e..adfd0e7 100644
--- a/py_gen/templates/_message_extra.py
+++ b/py_gen/templates/_message_extra.py
@@ -32,8 +32,8 @@
 
 def parse_message(buf):
     msg_ver, msg_type, msg_len, msg_xid = parse_header(buf)
-    if msg_ver != const.OFP_VERSION and msg_type != const.OFPT_HELLO:
-        raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
+    if msg_ver != ofp.OFP_VERSION and msg_type != ofp.OFPT_HELLO:
+        raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (ofp.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
     return message.unpack(loxi.generic_util.OFReader(buf))
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
index cce9de3..f5c4e34 100644
--- a/py_gen/templates/_unpack.py
+++ b/py_gen/templates/_unpack.py
@@ -35,7 +35,7 @@
 ::     elif type(m) == OFLengthMember:
         _${m.name} = ${gen_unpack_expr(m.oftype, 'reader', version=version)}
         orig_reader = reader
-        reader = orig_reader.slice(_${m.name} - (${m.offset} + ${m.length}))
+        reader = orig_reader.slice(_${m.name}, ${m.offset + m.length})
 ::     elif type(m) == OFFieldLengthMember:
 ::         field_length_members[m.field_name] = m
         _${m.name} = ${gen_unpack_expr(m.oftype, 'reader', version=version)}
diff --git a/py_gen/templates/generic_util.py b/py_gen/templates/generic_util.py
index 039d82a..02f1c0e 100644
--- a/py_gen/templates/generic_util.py
+++ b/py_gen/templates/generic_util.py
@@ -105,7 +105,7 @@
         self.offset += length
 
     def skip_align(self):
-        new_offset = ((self.start + self.offset + 7) / 8 * 8) - self.start
+        new_offset = (self.offset + 7) / 8 * 8
         if new_offset > self.length:
             raise loxi.ProtocolError("Buffer too short")
         self.offset = new_offset
@@ -114,9 +114,10 @@
         return self.offset == self.length
 
     # Used when parsing objects that have their own length fields
-    def slice(self, length):
-        if self.offset + length > self.length:
+    def slice(self, length, rewind=0):
+        if self.offset + length - rewind > self.length:
             raise loxi.ProtocolError("Buffer too short")
-        reader = OFReader(self.buf, self.start + self.offset, length)
-        self.offset += length
+        reader = OFReader(self.buf, self.start + self.offset - rewind, length)
+        reader.skip(rewind)
+        self.offset += length - rewind
         return reader
diff --git a/py_gen/templates/init.py b/py_gen/templates/init.py
index 3b73baa..aa968b6 100644
--- a/py_gen/templates/init.py
+++ b/py_gen/templates/init.py
@@ -29,17 +29,10 @@
 
 :: include('_autogen.py')
 
-import action, common, const, message
-:: if version >= 2:
-import instruction
-:: #endif
-:: if version >= 3:
-import oxm
-:: #endif
-:: if version >= 4:
-import meter_band
-import bsn_tlv
-:: #endif
+import const
+:: for module in modules:
+import ${module}
+:: #endfor
 from const import *
 from common import *
 from loxi import ProtocolError
diff --git a/py_gen/templates/module.py b/py_gen/templates/module.py
index dfe23e8..32baac9 100644
--- a/py_gen/templates/module.py
+++ b/py_gen/templates/module.py
@@ -33,24 +33,12 @@
 
 import struct
 import loxi
-import const
-import common
-import action
-:: if version >= OFVersions.VERSION_1_1:
-import instruction
-:: #endif
-:: if version >= OFVersions.VERSION_1_2:
-import oxm
-:: #endif
-:: if version >= OFVersions.VERSION_1_3:
-import action_id
-import instruction_id
-import meter_band
-import bsn_tlv
-:: #endif
 import util
 import loxi.generic_util
 
+import sys
+ofp = sys.modules['loxi.${subdir}']
+
 :: for ofclass in ofclasses:
 :: include('_ofclass.py', ofclass=ofclass)
 
diff --git a/py_gen/templates/toplevel_init.py b/py_gen/templates/toplevel_init.py
index e5493a5..0393169 100644
--- a/py_gen/templates/toplevel_init.py
+++ b/py_gen/templates/toplevel_init.py
@@ -39,20 +39,13 @@
     """
     Import and return the protocol module for the given wire version.
     """
-    if ver == 1:
-        import of10
-        return of10
-    elif ver == 2:
-        import of11
-        return of11
-    elif ver == 3:
-        import of12
-        return of12
-    elif ver == 4:
-        import of13
-        return of13
-    else:
-        raise ValueError
+:: for v in loxi_globals.OFVersions.all_supported:
+    if ver == ${v.wire_version}:
+        import of${v.version.replace('.', '')}
+        return of${v.version.replace('.', '')}
+
+:: #endfor
+    raise ValueError
 
 class ProtocolError(Exception):
     """
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
index 85181dc..7558576 100644
--- a/py_gen/templates/util.py
+++ b/py_gen/templates/util.py
@@ -173,6 +173,28 @@
         x >>= 1
     return value
 
+def pack_bitmap_512(value):
+    words = [0] * 8
+    for v in value:
+        assert v < 512
+        words[7-v/64] |= 1 << (v % 64)
+    return struct.pack("!8Q", *words)
+
+def unpack_bitmap_512(reader):
+    words = reader.read("!8Q")
+    x = 0l
+    for word in words:
+        x <<= 64
+        x |= word
+    i = 0
+    value = set()
+    while x != 0:
+        if x & 1 == 1:
+            value.add(i)
+        i += 1
+        x >>= 1
+    return value
+
 def pack_checksum_128(value):
     return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64)
 
diff --git a/py_gen/tests/generic_util.py b/py_gen/tests/generic_util.py
index 03885a2..20a23a4 100644
--- a/py_gen/tests/generic_util.py
+++ b/py_gen/tests/generic_util.py
@@ -102,17 +102,17 @@
         self.assertEquals(reader.is_empty(), True)
 
     def test_skip_align(self):
-        reader = OFReader("abcd" + "efgh" + "ijkl" + "mnop" + "qr")
+        reader = OFReader("abcd" + "efgh" + "ijkl" + "mnop" + "qrst")
         reader.skip_align()
         self.assertEquals(reader.peek('2s')[0], 'ab')
         self.assertEquals(reader.read('2s')[0], "ab")
         reader.skip_align()
         self.assertEquals(reader.peek('2s')[0], 'ij')
         self.assertEquals(reader.read('2s')[0], 'ij')
-        child = reader.slice(8)
-        self.assertEquals(child.peek('2s')[0], 'kl')
+        child = reader.slice(10)
+        self.assertEquals(child.read('2s')[0], 'kl')
         child.skip_align()
-        self.assertEquals(child.peek('2s')[0], 'qr')
+        self.assertEquals(child.peek('2s')[0], 'st')
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/py_gen/tests/of13.py b/py_gen/tests/of13.py
index c5a16b2..c99ee34 100644
--- a/py_gen/tests/of13.py
+++ b/py_gen/tests/of13.py
@@ -126,5 +126,18 @@
             else:
                 fn()
 
+class TestUtils(unittest.TestCase):
+    def check_bitmap_512(self, value, data):
+        self.assertEquals(data, ofp.util.pack_bitmap_512(set(value)))
+        self.assertEquals(ofp.util.unpack_bitmap_512(OFReader(data)), set(value))
+
+    def test_bitmap_512(self):
+        self.check_bitmap_512([0], "\x00" * 63 + "\x01")
+        self.check_bitmap_512([8], "\x00" * 62 + "\x01\x00")
+        self.check_bitmap_512([63], "\x00" * 56 + "\x80" + "\x00" * 7)
+        self.check_bitmap_512([64], "\x00" * 55 + "\x01" + "\x00" * 8)
+        self.check_bitmap_512([511], "\x80" + "\x00" * 63)
+        self.check_bitmap_512([5, 67, 90], "\x00" * 52 + "\x04\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x20")
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/py_gen/tests/of14.py b/py_gen/tests/of14.py
new file mode 100644
index 0000000..3fdfb8e
--- /dev/null
+++ b/py_gen/tests/of14.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# Copyright 2014, Big Switch Networks, Inc.
+#
+# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+# the following special exception:
+#
+# LOXI Exception
+#
+# As a special exception to the terms of the EPL, you may distribute libraries
+# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+# that copyright and licensing notices generated by LoxiGen are not altered or removed
+# from the LoxiGen Libraries and the notice provided below is (i) included in
+# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+# documentation for the LoxiGen Libraries, if distributed in binary form.
+#
+# Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+#
+# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+# a copy of the EPL at:
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# 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
+# EPL for the specific language governing permissions and limitations
+# under the EPL.
+import unittest
+from testutil import test_serialization
+from testutil import add_datafiles_tests
+
+try:
+    import loxi
+    import loxi.of14 as ofp
+    from loxi.generic_util import OFReader
+except ImportError:
+    exit("loxi package not found. Try setting PYTHONPATH.")
+
+class TestImports(unittest.TestCase):
+    def test_toplevel(self):
+        import loxi
+        self.assertTrue(hasattr(loxi, "ProtocolError"))
+        self.assertEquals(loxi.version_names[5], "1.4")
+        ofp = loxi.protocol(5)
+        self.assertEquals(ofp.OFP_VERSION, 5)
+        self.assertTrue(hasattr(ofp, "action"))
+        self.assertTrue(hasattr(ofp, "common"))
+        self.assertTrue(hasattr(ofp, "const"))
+        self.assertTrue(hasattr(ofp, "message"))
+        self.assertTrue(hasattr(ofp, "oxm"))
+
+    def test_version(self):
+        import loxi
+        self.assertTrue(hasattr(loxi.of14, "ProtocolError"))
+        self.assertTrue(hasattr(loxi.of14, "OFP_VERSION"))
+        self.assertEquals(loxi.of14.OFP_VERSION, 5)
+        self.assertTrue(hasattr(loxi.of14, "action"))
+        self.assertTrue(hasattr(loxi.of14, "common"))
+        self.assertTrue(hasattr(loxi.of14, "const"))
+        self.assertTrue(hasattr(loxi.of14, "message"))
+        self.assertTrue(hasattr(loxi.of14, "oxm"))
+
+# The majority of the serialization tests are created here using the files in
+# the test_data directory.
+class TestDataFiles(unittest.TestCase):
+    pass
+add_datafiles_tests(TestDataFiles, 'of14/', ofp)
+
+class TestAllof14(unittest.TestCase):
+    """
+    Round-trips every class through serialization/deserialization.
+    Not a replacement for handcoded tests because it only uses the
+    default member values.
+    """
+
+    def setUp(self):
+        mods = [ofp.action,ofp.message,ofp.common,ofp.oxm]
+        self.klasses = [klass for mod in mods
+                              for klass in mod.__dict__.values()
+                              if isinstance(klass, type) and
+                                 issubclass(klass, loxi.OFObject) and
+                                 not hasattr(klass, 'subtypes')]
+        self.klasses.sort(key=lambda x: str(x))
+
+    def test_serialization(self):
+        expected_failures = [
+            ofp.action.set_field, # field defaults to None
+        ]
+        for klass in self.klasses:
+            def fn():
+                obj = klass()
+                if hasattr(obj, "xid"): obj.xid = 42
+                buf = obj.pack()
+                obj2 = klass.unpack(OFReader(buf))
+                self.assertEquals(obj, obj2)
+            if klass in expected_failures:
+                self.assertRaises(Exception, fn)
+            else:
+                fn()
+
+    def test_parse_message(self):
+        expected_failures = [
+        ]
+        for klass in self.klasses:
+            if not issubclass(klass, ofp.message.message):
+                continue
+            def fn():
+                obj = klass(xid=42)
+                buf = obj.pack()
+                obj2 = ofp.message.parse_message(buf)
+                self.assertEquals(obj, obj2)
+            if klass in expected_failures:
+                self.assertRaises(Exception, fn)
+            else:
+                fn()
+
+    def test_show(self):
+        expected_failures = []
+        for klass in self.klasses:
+            def fn():
+                obj = klass()
+                if hasattr(obj, "xid"): obj.xid = 42
+                obj.show()
+            if klass in expected_failures:
+                self.assertRaises(Exception, fn)
+            else:
+                fn()
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test_data/of10/flow_add.data b/test_data/of10/flow_add.data
index 60fd780..275a40e 100644
--- a/test_data/of10/flow_add.data
+++ b/test_data/of10/flow_add.data
@@ -117,19 +117,19 @@
     of_list_action_t actions;
     of_flow_add_actions_bind(obj, &actions);
     {
-        of_action_t action;
-        of_action_output_init(&action.output, OF_VERSION_1_0, -1, 1);
+        of_object_t action;
+        of_action_output_init(&action, OF_VERSION_1_0, -1, 1);
         of_list_action_append_bind(&actions, &action);
-        of_action_output_port_set(&action.output, OF_PORT_DEST_FLOOD);
+        of_action_output_port_set(&action, OF_PORT_DEST_FLOOD);
     }
     {
-        of_action_t action;
-        of_action_nicira_dec_ttl_init(&action.nicira_dec_ttl, OF_VERSION_1_0, -1, 1);
+        of_object_t action;
+        of_action_nicira_dec_ttl_init(&action, OF_VERSION_1_0, -1, 1);
         of_list_action_append_bind(&actions, &action);
     }
     {
-        of_action_t action;
-        of_action_bsn_set_tunnel_dst_init(&action.bsn_set_tunnel_dst, OF_VERSION_1_0, -1, 1);
+        of_object_t action;
+        of_action_bsn_set_tunnel_dst_init(&action, OF_VERSION_1_0, -1, 1);
         of_list_action_append_bind(&actions, &action);
     }
 }
diff --git a/test_data/of13/oxm_bsn_in_ports_masked_512.data b/test_data/of13/oxm_bsn_in_ports_masked_512.data
new file mode 100644
index 0000000..82cc45c
--- /dev/null
+++ b/test_data/of13/oxm_bsn_in_ports_masked_512.data
@@ -0,0 +1,36 @@
+-- binary
+00 03 # class
+27 # type/masked
+80 # length
+00 00 00 00 00 00 00 00 # value
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+7f ff ff ff ff ff ff ff # mask - Only ports 0, 17, 96, 511 are selected (and thus are zero)
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff fe ff ff ff ff # ...
+ff ff ff ff ff fd ff fe # ...
+-- python
+ofp.oxm.bsn_in_ports_512_masked(set(), set(range(0,512)) - set((0, 17, 96, 511)))
+-- c
+obj = of_oxm_bsn_in_ports_512_masked_new(OF_VERSION_1_3);
+{
+    of_bitmap_512_t bmap = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
+    of_oxm_bsn_in_ports_512_masked_value_set(obj, bmap);
+}
+{
+    of_bitmap_512_t bmap = { { 0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffeffffffff, 0xfffffffffffdfffe } };
+    of_oxm_bsn_in_ports_512_masked_value_mask_set(obj, bmap);
+}
+-- java
+OFPortMap portmap = OFPortMap.ofPorts(OFPort.of(0), OFPort.of(17), OFPort.of(96));
+builder.setValue(portmap.getValue());
+builder.setMask(portmap.getMask());
diff --git a/test_data/of13/oxm_mpls_bos.data b/test_data/of13/oxm_mpls_bos.data
new file mode 100644
index 0000000..8d43f33
--- /dev/null
+++ b/test_data/of13/oxm_mpls_bos.data
@@ -0,0 +1,7 @@
+-- binary
+80 00 # class
+48 # type/masked
+01 # length
+01 # value
+-- python
+ofp.oxm.mpls_bos(value=01)
diff --git a/test_data/of13/port_status.data b/test_data/of13/port_status.data
index 10f7c16..e56705f 100644
--- a/test_data/of13/port_status.data
+++ b/test_data/of13/port_status.data
@@ -34,3 +34,24 @@
         peer=ofp.OFPPF_100MB_FD,
         curr_speed=10,
         max_speed=20))
+-- c
+obj = of_port_status_new(OF_VERSION_1_3);
+of_port_status_xid_set(obj, 0x12345678);
+of_port_status_reason_set(obj, OF_PORT_CHANGE_REASON_MODIFY);
+{
+    of_object_t desc;
+    of_port_status_desc_bind(obj, &desc);
+    of_port_desc_port_no_set(&desc, 4);
+    of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
+    of_port_desc_hw_addr_set(&desc, hw_addr);
+    of_port_name_t name = "foo";
+    of_port_desc_name_set(&desc, name);
+    of_port_desc_config_set(&desc, OF_PORT_CONFIG_FLAG_NO_FWD|OF_PORT_CONFIG_FLAG_NO_RECV);
+    of_port_desc_state_set(&desc, OF_PORT_STATE_FLAG_BLOCKED);
+    of_port_desc_curr_set(&desc, OF_PORT_FEATURE_FLAG_10MB_HD);
+    of_port_desc_advertised_set(&desc, OF_PORT_FEATURE_FLAG_10MB_FD);
+    of_port_desc_supported_set(&desc, OF_PORT_FEATURE_FLAG_100MB_HD);
+    of_port_desc_peer_set(&desc, OF_PORT_FEATURE_FLAG_100MB_FD);
+    of_port_desc_curr_speed_set(&desc, 10);
+    of_port_desc_max_speed_set(&desc, 20);
+}
diff --git a/test_data/of14/flow_add.data b/test_data/of14/flow_add.data
new file mode 100644
index 0000000..88cf939
--- /dev/null
+++ b/test_data/of14/flow_add.data
@@ -0,0 +1,104 @@
+-- binary
+05 0e # version, type
+00 80 # length
+12 34 56 78 # xid
+
+fe dc ba 98 76 54 32 10 # cookie
+
+ff 00 ff 00 ff 00 ff 00 # cookie_mask
+
+03 # table_id
+00 # _command
+00 05 # idle_timeout
+00 0a # hard_timeout
+17 70 # priority
+
+00 00 00 32 # buffer_id
+00 00 00 06 # out_port
+
+00 00 00 08 # out_group
+00 00 # flags
+aa bb # importance
+
+00 01 # match.type
+00 3F # match.length # 59 bytes OXMs + 4 bytes match header
+
+80 00 01 08 # match.oxm_list[0].type_len - IN_PORT
+00 00 00 04 # match.oxm_list[0].value
+00 00 00 05 # match.oxm_list[0].mask
+
+80 00 0A 02 # match.oxm_list[1].type_len - ETH_TYPE
+86 DD # match.oxm_list[1].value - ETH_TYPE = IPv6
+
+80 00 14 01 # match.oxm_list[2].type_len - IP Proto
+06 # match.oxm_list[2].value = IP_PROTO = TCP
+
+80 00 35 20 # match.oxm_list[3].type_len - IPV6_SRC
+1C CA FE 1C B1 10 1C 00 00 28 00 00 00 00 00 00 # match.oxm_list[3].value
+FF FF FF FF FF F0 FF FF 1C 2C 3C 00 00 00 00 00 # match.oxm_list[3].mask
+
+00 # match.pad
+
+00 01 # instructions[0].type
+00 08 # instructions[0].length
+04 # instructions[0].table_id
+00 00 00 # pad
+
+00 01 # instructions[1].type
+00 08 # instructions[1].length
+07 # instructions[1].table_id
+00 00 00 # pad
+-- python
+ofp.message.flow_add(
+    xid=0x12345678,
+    cookie=0xFEDCBA9876543210,
+    cookie_mask=0xFF00FF00FF00FF00,
+    table_id=3,
+    idle_timeout=5,
+    hard_timeout=10,
+    priority=6000,
+    buffer_id=50,
+    out_port=6,
+    out_group=8,
+    flags=0,
+    importance=0xaabb,
+    match=ofp.match(oxm_list=[
+        ofp.oxm.in_port_masked(value=4, value_mask=5),
+        ofp.oxm.eth_type(value=0x86dd),
+        ofp.oxm.ip_proto(value=6),
+        ofp.oxm.ipv6_src_masked(
+            value     ='\x1C\xCA\xFE\x1C\xB1\x10\x1C\x00\x00\x28\x00\x00\x00\x00\x00\x00',
+            value_mask='\xFF\xFF\xFF\xFF\xFF\xF0\xFF\xFF\x1C\x2C\x3C\x00\x00\x00\x00\x00')
+        ]),
+    instructions=[
+        ofp.instruction.goto_table(table_id=4),
+        ofp.instruction.goto_table(table_id=7)])
+-- java
+builder.setXid(0x12345678)
+    .setCookie(U64.parseHex("FEDCBA9876543210"))
+    .setCookieMask(U64.parseHex("FF00FF00FF00FF00"))
+    .setTableId(TableId.of(3))
+    .setIdleTimeout(5)
+    .setHardTimeout(10)
+    .setPriority(6000)
+    .setBufferId(OFBufferId.of(50))
+    .setOutPort(OFPort.of(6))
+    .setOutGroup(OFGroup.of(8))
+    .setFlags(ImmutableSet.<OFFlowModFlags>of())
+    .setImportance(0xaabb)
+    .setMatch(
+        factory.buildMatch()
+            .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
+            .setExact(MatchField.ETH_TYPE, EthType.IPv6)
+            .setExact(MatchField.IP_PROTO, IpProtocol.TCP)
+            .setMasked(MatchField.IPV6_SRC, 
+                       IPv6Address.of(0x1CCAFE1CB1101C00l, 0x0028000000000000l),
+                       IPv6Address.of(0xFFFFFFFFFFF0FFFFl, 0x1C2C3C0000000000l))
+        	.build()
+    )
+    .setInstructions(
+        ImmutableList.<OFInstruction>of(
+                factory.instructions().gotoTable(TableId.of(4)),
+                factory.instructions().gotoTable(TableId.of(7))
+        )
+    );
diff --git a/test_data/of14/port_desc_stats_reply.data b/test_data/of14/port_desc_stats_reply.data
new file mode 100644
index 0000000..8e38975
--- /dev/null
+++ b/test_data/of14/port_desc_stats_reply.data
@@ -0,0 +1,54 @@
+-- binary
+05 13 # version/type
+00 58 # length
+00 00 00 05 # xid
+00 0d # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 00 00 01 # entries[0].port_no
+00 48 # entries[0].length
+00 00 # pad
+01 02 03 04 05 06 # entries[0].hw_addr
+00 00 # pad
+69 6e 74 65 72 66 61 63 65 31 32 33 34 35 36 37 # entries[0].name
+00 00 00 60 # entries[0].config
+00 00 00 03 # entries[0].state
+00 00 # entries[0].properties[0].type (ethernet)
+00 20 # entries[0].properties[0].length 
+00 00 00 00 # pad
+00 00 00 70 # entries[0].properties[0].curr
+00 00 00 00 # entries[0].properties[0].advertised
+00 00 00 00 # entries[0].properties[0].supported
+00 00 00 00 # entries[0].properties[0].peer
+00 00 00 00 # entries[0].properties[0].curr_speed
+00 00 00 80 # entries[0].properties[0].max_speed
+-- python
+ofp.message.port_desc_stats_reply(
+    xid=5, flags=0, entries=[
+        ofp.port_desc(
+            port_no=1,
+            hw_addr=[1,2,3,4,5,6],
+            name="interface1234567",
+            config=0x60,
+            state=0x03,
+            properties=[
+                ofp.port_desc_prop.ethernet(
+                    curr=0x70,
+                    max_speed=0x80)])])
+-- java
+builder
+        .setXid(5)
+        .setFlags(ImmutableSet.<OFStatsReplyFlags>of())
+        .setEntries(ImmutableList.of(
+                factory.buildPortDesc()
+                   .setPortNo(OFPort.of(1))
+                   .setHwAddr(MacAddress.of("01:02:03:04:05:06"))
+                   .setName("interface1234567")
+                   .setConfig(Sets.immutableEnumSet(OFPortConfig.NO_FWD, OFPortConfig.NO_PACKET_IN))
+                   .setState(Sets.immutableEnumSet(OFPortState.LINK_DOWN, OFPortState.BLOCKED))
+                   .setProperties(ImmutableList.<OFPortDescProp>of(factory.buildPortDescPropEthernet()
+                                                         .setCurr(0x70)
+                                                         .setMaxSpeed(0x80)
+                                                         .build()))
+                   .build())
+         );
diff --git a/test_data/of14/port_stats_reply.data b/test_data/of14/port_stats_reply.data
new file mode 100644
index 0000000..0ff4902
--- /dev/null
+++ b/test_data/of14/port_stats_reply.data
@@ -0,0 +1,104 @@
+-- binary
+05 13 # version/type
+00 d8 # length
+00 00 00 05 # xid
+00 04 # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 78 # entries[0].length
+00 00 # pad
+00 00 00 01 # entries[0].port_no
+00 00 00 00 # entries[0].duration_sec
+00 00 00 00 # entries[0].duration_nsec
+00 00 00 00 00 00 00 01 # entries[0].rx_packets
+00 00 00 00 00 00 00 00 # entries[0].tx_packets
+00 00 00 00 00 00 00 00 # entries[0].rx_bytes
+00 00 00 00 00 00 00 00 # entries[0].tx_bytes
+00 00 00 00 00 00 00 00 # entries[0].rx_dropped
+00 00 00 00 00 00 00 00 # entries[0].tx_dropped
+00 00 00 00 00 00 00 00 # entries[0].rx_errors
+00 00 00 00 00 00 00 02 # entries[0].tx_errors
+00 00 # entries[0].properties[0].type (ethernet)
+00 28 # entries[0].properties[0].length 
+00 00 00 00 # pad
+00 00 00 00 00 00 00 01 # entries[0].properties[0].rx_frame_err
+00 00 00 00 00 00 00 02 # entries[0].properties[0].rx_over_err
+00 00 00 00 00 00 00 03 # entries[0].properties[0].rx_crc_err
+00 00 00 00 00 00 00 04 # entries[0].properties[0].collisions
+00 50 # entries[1].length
+00 00 # pad
+ff ff ff fe # entries[1].port_no
+00 00 00 00 # entries[1].duration_sec
+00 00 00 00 # entries[1].duration_nsec
+00 00 00 00 00 00 00 03 # entries[1].rx_packets
+00 00 00 00 00 00 00 00 # entries[1].tx_packets
+00 00 00 00 00 00 00 00 # entries[1].rx_bytes
+00 00 00 00 00 00 00 00 # entries[1].tx_bytes
+00 00 00 00 00 00 00 00 # entries[1].rx_dropped
+00 00 00 00 00 00 00 00 # entries[1].tx_dropped
+00 00 00 00 00 00 00 00 # entries[1].rx_errors
+00 00 00 00 00 00 00 04 # entries[1].tx_errors
+-- python
+ofp.message.port_stats_reply(
+    xid=5, flags=0, entries=[
+        ofp.port_stats_entry(port_no=1, rx_packets=1, tx_errors=2,
+            properties=[
+                ofp.port_stats_prop.ethernet(
+                    rx_frame_err=1,
+                    rx_over_err=2,
+                    rx_crc_err=3,
+                    collisions=4)]),
+        ofp.port_stats_entry(port_no=ofp.OFPP_LOCAL, rx_packets=3, tx_errors=4)])
+-- c
+obj = of_port_stats_reply_new(OF_VERSION_1_4);
+{
+    of_object_t list;
+    of_port_stats_reply_entries_bind(obj, &list);
+    {
+        of_object_t *obj = of_port_stats_entry_new(OF_VERSION_1_4);
+        of_port_stats_entry_port_no_set(obj, 1);
+        of_port_stats_entry_rx_packets_set(obj, 1);
+        of_port_stats_entry_tx_packets_set(obj, 0);
+        of_port_stats_entry_rx_bytes_set(obj, 0);
+        of_port_stats_entry_tx_bytes_set(obj, 0);
+        of_port_stats_entry_rx_dropped_set(obj, 0);
+        of_port_stats_entry_tx_dropped_set(obj, 0);
+        of_port_stats_entry_rx_errors_set(obj, 0);
+        of_port_stats_entry_tx_errors_set(obj, 2);
+
+        /* Append property */
+        {
+            of_object_t list;
+            of_port_stats_entry_properties_bind(obj, &list);
+            {
+                of_object_t *obj = of_port_stats_prop_ethernet_new(OF_VERSION_1_4);
+                of_port_stats_prop_ethernet_rx_frame_err_set(obj, 1);
+                of_port_stats_prop_ethernet_rx_over_err_set(obj, 2);
+                of_port_stats_prop_ethernet_rx_crc_err_set(obj, 3);
+                of_port_stats_prop_ethernet_collisions_set(obj, 4);
+                of_list_append(&list, obj);
+                of_object_delete(obj);
+            }
+        }
+
+
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+    {
+        of_object_t *obj = of_port_stats_entry_new(OF_VERSION_1_4);
+        of_port_stats_entry_port_no_set(obj, OF_PORT_DEST_LOCAL);
+        of_port_stats_entry_rx_packets_set(obj, 3);
+        of_port_stats_entry_tx_packets_set(obj, 0);
+        of_port_stats_entry_rx_bytes_set(obj, 0);
+        of_port_stats_entry_tx_bytes_set(obj, 0);
+        of_port_stats_entry_rx_dropped_set(obj, 0);
+        of_port_stats_entry_tx_dropped_set(obj, 0);
+        of_port_stats_entry_rx_errors_set(obj, 0);
+        of_port_stats_entry_tx_errors_set(obj, 4);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+}
+of_port_stats_reply_flags_set(obj, 0);
+of_port_stats_reply_xid_set(obj, 5);
diff --git a/test_data/of14/port_status.data b/test_data/of14/port_status.data
new file mode 100644
index 0000000..9fb5bde
--- /dev/null
+++ b/test_data/of14/port_status.data
@@ -0,0 +1,72 @@
+-- binary
+05 0c # version, type
+00 58 # length
+12 34 56 78 # xid
+02 # reason
+00 00 00 00 00 00 00 # pad
+00 00 00 04 # port_no
+00 48 # length
+00 00 # pad
+01 02 03 04 05 06 # hw_addr
+00 00 # pad
+66 6f 6f 00 00 00 00 00 # name
+00 00 00 00 00 00 00 00 # ...
+00 00 00 24 # config
+00 00 00 02 # state
+00 00 # properties[0].type (ethernet)
+00 20 # properties[0].length
+00 00 00 00 # pad
+00 00 00 01 # properties[0].curr
+00 00 00 02 # properties[0].advertised
+00 00 00 04 # properties[0].supported
+00 00 00 08 # properties[0].peer
+00 00 00 0a # properties[0].curr_speed
+00 00 00 14 # properties[0].max_speed
+-- python
+ofp.message.port_status(
+    xid=0x12345678,
+    reason=ofp.OFPPR_MODIFY,
+    desc=ofp.port_desc(
+        port_no=4,
+        hw_addr=[1,2,3,4,5,6],
+        name="foo",
+        config=ofp.OFPPC_NO_FWD|ofp.OFPPC_NO_RECV,
+        state=ofp.OFPPS_BLOCKED,
+        properties=[
+            ofp.port_desc_prop.ethernet(
+                curr=ofp.OFPPF_10MB_HD,
+                advertised=ofp.OFPPF_10MB_FD,
+                supported=ofp.OFPPF_100MB_HD,
+                peer=ofp.OFPPF_100MB_FD,
+                curr_speed=10,
+                max_speed=20)]))
+-- c
+obj = of_port_status_new(OF_VERSION_1_4);
+of_port_status_xid_set(obj, 0x12345678);
+of_port_status_reason_set(obj, OF_PORT_CHANGE_REASON_MODIFY);
+{
+    of_object_t desc;
+    of_port_status_desc_bind(obj, &desc);
+    of_port_desc_port_no_set(&desc, 4);
+    of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
+    of_port_desc_hw_addr_set(&desc, hw_addr);
+    of_port_name_t name = "foo";
+    of_port_desc_name_set(&desc, name);
+    of_port_desc_config_set(&desc, OF_PORT_CONFIG_FLAG_NO_FWD|OF_PORT_CONFIG_FLAG_NO_RECV);
+    of_port_desc_state_set(&desc, OF_PORT_STATE_FLAG_BLOCKED);
+    {
+        of_list_port_desc_prop_t list;
+        of_port_desc_properties_bind(&desc, &list);
+        {
+            of_object_t *obj = of_port_desc_prop_ethernet_new(OF_VERSION_1_4);
+            of_port_desc_prop_ethernet_curr_set(obj, OF_PORT_FEATURE_FLAG_10MB_HD);
+            of_port_desc_prop_ethernet_advertised_set(obj, OF_PORT_FEATURE_FLAG_10MB_FD);
+            of_port_desc_prop_ethernet_supported_set(obj, OF_PORT_FEATURE_FLAG_100MB_HD);
+            of_port_desc_prop_ethernet_peer_set(obj, OF_PORT_FEATURE_FLAG_100MB_FD);
+            of_port_desc_prop_ethernet_curr_speed_set(obj, 10);
+            of_port_desc_prop_ethernet_max_speed_set(obj, 20);
+            of_list_append(&list, obj);
+            of_object_delete(obj);
+        }
+    }
+}
diff --git a/wireshark_gen/__init__.py b/wireshark_gen/__init__.py
index a610f3f..75918f8 100644
--- a/wireshark_gen/__init__.py
+++ b/wireshark_gen/__init__.py
@@ -38,7 +38,7 @@
 
 DissectorField = namedtuple("DissectorField", ["fullname", "name", "type", "base", "enum_table"])
 
-proto_names = { 1: 'of10', 2: 'of11', 3: 'of12', 4: 'of13' }
+proto_names = { 1: 'of10', 2: 'of11', 3: 'of12', 4: 'of13', 5: 'of14' }
 def make_field_name(version, ofclass_name, member_name):
     return "%s.%s.%s" % (proto_names[version.wire_version],
                          ofclass_name[3:],
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index f7eb79c..ad0f0c2 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -49,6 +49,10 @@
     read_scalar(reader, subtree, field_name, 16)
 end
 
+function read_of_bitmap_512_t(reader, version, subtree, field_name)
+    read_scalar(reader, subtree, field_name, 64)
+end
+
 function read_of_checksum_128_t(reader, version, subtree, field_name)
     read_scalar(reader, subtree, field_name, 16)
 end
@@ -68,8 +72,12 @@
         dissect_of_match_v1_v1(reader, subtree:add("of_match"))
     elseif version == 2 then
         dissect_of_match_v2_v2(reader, subtree:add("of_match"))
-    elseif version >= 3 then
+    elseif version == 3 then
         dissect_of_match_v3_v3(reader, subtree:add("of_match"))
+    elseif version == 4 then
+        dissect_of_match_v3_v4(reader, subtree:add("of_match"))
+    else
+        error("Unsupported match version")
     end
 end
 
diff --git a/wireshark_gen/templates/openflow.lua b/wireshark_gen/templates/openflow.lua
index 9ce51d2..f96fccf 100644
--- a/wireshark_gen/templates/openflow.lua
+++ b/wireshark_gen/templates/openflow.lua
@@ -52,7 +52,7 @@
 
 :: for version, ofproto in ir.items():
 :: for enum in ofproto.enums:
-local enum_v${version.wire_version}_${enum.name} = {
+enum_v${version.wire_version}_${enum.name} = {
 :: for (name, value) in enum.values:
     [${value}] = "${name}",
 :: #endfor
@@ -159,8 +159,8 @@
             local msg_len = buf(offset+2,2):uint()
 
             -- Detect obviously broken messages
-            if msg_version == 0 or msg_version > 4 then break end
-            if msg_type > 29 then break end
+            if msg_version == 0 or msg_version > 5 then break end
+            if msg_type > 34 then break end
             if msg_len < 8 then break end
 
             if offset + msg_len > buf:len() then