Merge into master from pull request #154:
java_gen: dedicated factories for (action|instruction)_id, erromsg (https://github.com/floodlight/loxigen/pull/154)
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index e2bb467..640687f 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -37,6 +37,7 @@
 from c_gen import flags, type_maps, c_type_maps
 import c_gen.loxi_utils_legacy as loxi_utils
 from c_gen.loxi_utils_legacy import config_check
+import loxi_globals
 
 import c_gen.identifiers as identifiers
 
@@ -425,7 +426,6 @@
                                     of_match_t *match);
 extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
                                     of_match_t *match, int cur_len);
-extern void of_extension_object_id_set(of_object_t *obj, of_object_id_t id);
 """)
 
     # gen_base_types(out)
@@ -785,6 +785,7 @@
 #include <loci/loci.h>
 #include <loci/of_object.h>
 #include "loci_log.h"
+#include "loci_push_wire_types.h"
 
 """)
     gen_object_enum_str(out)
@@ -2501,7 +2502,7 @@
 typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
 typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
 typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
-typedef void (*of_wire_type_set_f)(of_object_t *obj, of_object_id_t id);
+typedef void (*of_wire_type_set_f)(of_object_t *obj);
 """)
     # If not using function pointers in classes, don't gen typedefs below
     if not config_check("gen_fn_ptrs"):
@@ -2687,62 +2688,30 @@
 {
 """ % 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; push version, length and type to wire */
+    /* Message obj; set length */
     of_message_t msg;
 
     if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
-        of_message_version_set(msg, obj->version);
         of_message_length_set(msg, obj->length);
-        OF_TRY(of_wire_message_object_id_set(OF_OBJECT_TO_WBUF(obj),
-                 %(name)s));
     }
 """ % dict(name = enum_name(cls)))
 
-        for version in of_g.of_version_range:
-            if type_maps.class_is_extension(cls, version):
-                exp_name = type_maps.extension_to_experimenter_macro_name(cls)
-                subtype = type_maps.extension_message_to_subtype(cls, version)
-                if subtype is None or exp_name is None:
-                    print "Error in mapping extension message"
-                    print cls, version
-                    sys.exit(1)
-                out.write("""
-    if (obj->version == %(version)s) {
-        of_message_experimenter_id_set(OF_OBJECT_TO_MESSAGE(obj),
-                                       %(exp_name)s);
-        of_message_experimenter_subtype_set(OF_OBJECT_TO_MESSAGE(obj),
-                                            %(subtype)s);
-    }
-""" % dict(exp_name=exp_name, version=of_g.wire_ver_map[version],
-           subtype=str(subtype)))
-
     else: # Not a message
         if loxi_utils.class_is_tlv16(cls):
             out.write("""
-    /* TLV obj; set length and type */
+    /* TLV obj; set length */
     of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
-    of_tlv16_wire_object_id_set((of_object_t *)obj,
-           %(enum)s);
 """ % dict(enum=enum_name(cls)))
-            # Some tlv16 types may be extensions requiring more work
-            if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
-                       "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
-                       "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl",
-                       "of_instruction_bsn_disable_src_mac_check"]:
-                out.write("""
-    /* Extended TLV obj; Call specific accessor */
-    of_extension_object_id_set(obj, %(enum)s);
-""" % dict(cls=cls, enum=enum_name(cls)))
 
-
-        if loxi_utils.class_is_oxm(cls):
-            out.write("""\
-    /* OXM obj; set length and type */
-    of_oxm_wire_length_set((of_object_t *)obj, obj->length);
-    of_oxm_wire_object_id_set((of_object_t *)obj, %(enum)s);
-""" % dict(enum=enum_name(cls)))
         if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
             out.write("""
     obj->wire_length_set((of_object_t *)obj, obj->length);
@@ -3050,6 +3019,12 @@
     /* Set up the object's function pointers */
 """)
 
+    uclass = loxi_globals.unified.class_by_name(cls)
+    if uclass and not uclass.virtual and uclass.has_type_members:
+        out.write("""
+    obj->wire_type_set = %(cls)s_push_wire_types;
+""" % dict(cls=cls))
+
     if loxi_utils.class_is_message(cls):
         out.write("""
     obj->wire_length_get = of_object_message_wire_length_get;
@@ -3060,7 +3035,6 @@
             if not (cls in type_maps.inheritance_map): # Don't set for super
                 out.write("""
     obj->wire_length_set = of_tlv16_wire_length_set;
-    obj->wire_type_set = of_tlv16_wire_object_id_set;\
 """)
             out.write("""
     obj->wire_length_get = of_tlv16_wire_length_get;
@@ -3096,9 +3070,7 @@
         if loxi_utils.class_is_oxm(cls):
             out.write("""
     obj->wire_length_get = of_oxm_wire_length_get;
-    obj->wire_length_set = of_oxm_wire_length_set;
     obj->wire_type_get = of_oxm_wire_object_id_get;
-    obj->wire_type_set = of_oxm_wire_object_id_set;
 """)
         if loxi_utils.class_is_u16_len(cls):
             out.write("""
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 09ee486..b0775d1 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -1094,92 +1094,6 @@
 
 """)
 
-    # Generate the function that sets the object type fields
-    out.write("""
-
-/**
- * Map a message in a wire buffer object to its OF object id.
- * @param wbuf Pointer to a wire buffer object, populated with an OF message
- * @returns The object ID of the message
- * @returns OF_OBJECT_INVALID if unable to parse the message type
- *
- * Version must be set in the buffer prior to calling this routine
- */
-
-static inline int
-of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
-{
-    int type;
-    of_version_t ver;
-    of_message_t msg;
-
-    msg = (of_message_t)WBUF_BUF(wbuf);
-
-    ver = of_message_version_get(msg);
-
-    /* ASSERT(id is a message object) */
-
-    if ((type = of_object_to_wire_type(id, ver)) < 0) {
-        return OF_ERROR_PARAM;
-    }
-    of_message_type_set(msg, type);
-
-    if ((type = of_object_to_stats_type(id, ver)) >= 0) {
-        /* It's a stats obj */
-        of_message_stats_type_set(msg, type);
-        if (type == OF_STATS_TYPE_EXPERIMENTER) {
-            switch (id) {
-            case OF_BSN_LACP_STATS_REQUEST:
-            case OF_BSN_LACP_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 1);
-                break;
-            case OF_BSN_SWITCH_PIPELINE_STATS_REQUEST:
-            case OF_BSN_SWITCH_PIPELINE_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 6);
-                break;
-            case OF_BSN_PORT_COUNTER_STATS_REQUEST:
-            case OF_BSN_PORT_COUNTER_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 8);
-                break;
-            case OF_BSN_VLAN_COUNTER_STATS_REQUEST:
-            case OF_BSN_VLAN_COUNTER_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 9);
-                break;
-            default:
-                break;
-            }
-        }
-    }
-    if ((type = of_object_to_error_type(id, ver)) >= 0) {
-        /* It's an error obj */
-        of_message_error_type_set(msg, type);
-    }
-    if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
-        /* It's a flow mod obj */
-        of_message_flow_mod_command_set(msg, ver, type);
-    }
-    if ((type = of_object_to_group_mod_command(id, ver)) >= 0) {
-        /* It's a group mod obj */
-        of_message_group_mod_command_set(msg, type);
-    }
-    if (of_object_id_is_extension(id, ver)) {
-        uint32_t val32;
-
-        /* Set the experimenter and subtype codes */
-        val32 = of_extension_to_experimenter_id(id, ver);
-        of_message_experimenter_id_set(msg, val32);
-        val32 = of_extension_to_experimenter_subtype(id, ver);
-        of_message_experimenter_subtype_set(msg, val32);
-    }
-
-    return OF_ERROR_NONE;
-}
-""")
-
 def gen_type_data_header(out):
 
     out.write("""
@@ -1249,15 +1163,11 @@
 extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
 
 extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
-extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
 extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
-extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
 
 extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
 
-extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
-
 /* Wire length is uint16 at front of structure */
 extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
new file mode 100644
index 0000000..0d7832a
--- /dev/null
+++ b/c_gen/codegen.py
@@ -0,0 +1,79 @@
+# 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.
+
+"""
+Code generation
+
+These functions extract data from the IR and render templates with it.
+"""
+
+from collections import namedtuple
+from itertools import groupby
+import template_utils
+import loxi_globals
+import loxi_ir.ir as ir
+import util
+
+PushWireTypesFn = namedtuple('PushWireTypesFn',
+    ['class_name', 'versioned_type_members'])
+PushWireTypesMember = namedtuple('PushWireTypesMember',
+    ['name', 'offset', 'length', 'value'])
+
+def gen_push_wire_types(install_dir):
+    fns = []
+    for uclass in loxi_globals.unified.classes:
+        if uclass.virtual or not uclass.has_type_members:
+            continue
+
+        # Generate a dict of version -> list of PushWireTypesMember
+        type_members_by_version = {}
+        for version, ofclass in sorted(uclass.version_classes.items()):
+            pwtms = []
+            for m in ofclass.members:
+                if isinstance(m, ir.OFTypeMember):
+                    if m.name == "version" and m.value == version.wire_version:
+                        # Special case for version
+                        pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
+                    else:
+                        pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, m.value))
+            type_members_by_version[version] = pwtms
+
+        # Merge versions with identical type members
+        all_versions = sorted(type_members_by_version.keys())
+        versioned_type_members = []
+        for pwtms, versions in groupby(all_versions, type_members_by_version.get):
+            versioned_type_members.append((pwtms, list(versions)))
+
+        fns.append(PushWireTypesFn(
+            class_name=uclass.name,
+            versioned_type_members=versioned_type_members))
+
+    with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.c") as out:
+        util.render_template(out, "loci_push_wire_types.c", fns=fns)
+
+    with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.h") as out:
+        util.render_template(out, "loci_push_wire_types.h", fns=fns)
diff --git a/c_gen/templates/loci_push_wire_types.c b/c_gen/templates/loci_push_wire_types.c
new file mode 100644
index 0000000..2103aad
--- /dev/null
+++ b/c_gen/templates/loci_push_wire_types.c
@@ -0,0 +1,83 @@
+:: # 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.
+::
+:: include('_copyright.c')
+
+/****************************************************************
+ *
+ * Functions for each concrete class that set the type fields
+ *
+ ****************************************************************/
+
+#include <loci/loci.h>
+#include <loci/of_message.h>
+#include <endian.h>
+
+#ifdef __GNUC__
+#define UNREACHABLE() __builtin_unreachable()
+#else
+#define UNREACHABLE()
+#endif
+
+/*
+ * In a separate function to give the compiler the choice of whether to inline.
+ */
+static unsigned char *
+loci_object_to_buffer(of_object_t *obj)
+{
+    return OF_OBJECT_BUFFER_INDEX(obj, 0);
+}
+
+:: for fn in fns:
+
+void
+${fn.class_name}_push_wire_types(of_object_t *obj)
+{
+    unsigned char *buf = loci_object_to_buffer(obj);
+    switch (obj->version) {
+:: for ms, versions in fn.versioned_type_members:
+:: for version in versions:
+    case ${version.constant_version(prefix='OF_VERSION_')}:
+:: #endfor
+:: for m in ms:
+:: if m.length == 1:
+        *(uint8_t *)(buf + ${m.offset}) = ${m.value}; /* ${m.name} */
+:: elif m.length == 2:
+        *(uint16_t *)(buf + ${m.offset}) = htobe16(${m.value}); /* ${m.name} */
+:: elif m.length == 4:
+        *(uint32_t *)(buf + ${m.offset}) = htobe32(${m.value}); /* ${m.name} */
+:: else:
+:: raise("unsupported push_wire_types length %d" % m.length)
+:: #endif
+:: #endfor
+        break;
+:: #endfor
+    default:
+        UNREACHABLE();
+    }
+}
+:: #endfor
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/loci_push_wire_types.h
new file mode 100644
index 0000000..5b2c1e8
--- /dev/null
+++ b/c_gen/templates/loci_push_wire_types.h
@@ -0,0 +1,40 @@
+:: # 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.
+::
+:: include('_copyright.c')
+#ifndef LOCI_PUSH_WIRE_TYPES_H
+#define LOCI_PUSH_WIRE_TYPES_H
+
+#include <loci/loci.h>
+
+/* Declarations of public functions from loci_push_wire_types.c */
+
+:: for fn in fns:
+void ${fn.class_name}_push_wire_types(of_object_t *obj);
+:: #endfor
+
+#endif
diff --git a/c_gen/templates/of_message.h b/c_gen/templates/of_message.h
index befda2f..df74231 100644
--- a/c_gen/templates/of_message.h
+++ b/c_gen/templates/of_message.h
@@ -105,11 +105,6 @@
     return (of_version_t)msg[OF_MESSAGE_VERSION_OFFSET];
 }
 
-static inline void
-of_message_version_set(of_message_t msg, of_version_t version) {
-    buf_u8_set(msg, (uint8_t)version);
-}
-
 /**
  * @brief Get/set OpenFlow type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -122,11 +117,6 @@
     return msg[OF_MESSAGE_TYPE_OFFSET];
 }
 
-static inline void
-of_message_type_set(of_message_t msg, uint8_t value) {
-    buf_u8_set(msg + OF_MESSAGE_TYPE_OFFSET, value);
-}
-
 /**
  * @brief Get/set in-buffer length of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -161,11 +151,6 @@
     return val;
 }
 
-static inline void
-of_message_xid_set(of_message_t msg, uint32_t xid) {
-    buf_u32_set(msg + OF_MESSAGE_XID_OFFSET, xid);
-}
-
 /**
  * @brief Get/set stats type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -180,11 +165,6 @@
     return val;
 }
 
-static inline void
-of_message_stats_type_set(of_message_t msg, uint16_t type) {
-    buf_u16_set(msg + OF_MESSAGE_STATS_TYPE_OFFSET, type);
-}
-
 /**
  * @brief Get/set error type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -199,11 +179,6 @@
     return val;
 }
 
-static inline void
-of_message_error_type_set(of_message_t msg, uint16_t type) {
-    buf_u16_set(msg + OF_MESSAGE_ERROR_TYPE_OFFSET, type);
-}
-
 
 /**
  * @brief Get/set experimenter ID of a message
@@ -219,11 +194,6 @@
     return val;
 }
 
-static inline void
-of_message_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
-    buf_u32_set(msg + OF_MESSAGE_EXPERIMENTER_ID_OFFSET, experimenter_id);
-}
-
 
 /**
  * @brief Get/set experimenter message type (subtype) of a message
@@ -239,13 +209,6 @@
     return val;
 }
 
-static inline void
-of_message_experimenter_subtype_set(of_message_t msg,
-                                    uint32_t subtype) {
-    buf_u32_set(msg + OF_MESSAGE_EXPERIMENTER_SUBTYPE_OFFSET,
-                subtype);
-}
-
 /**
  * Flow mod command changed from 16 to 8 bits on the wire from 1.0 to 1.1
  */
@@ -263,19 +226,6 @@
     return val8;
 }
 
-static inline void
-of_message_flow_mod_command_set(of_message_t msg, of_version_t version, 
-                                uint8_t command) {
-    uint16_t val16;
-
-    if (version == OF_VERSION_1_0) {
-        val16 = command;
-        buf_u16_set(msg + OF_MESSAGE_FLOW_MOD_COMMAND_OFFSET(version), val16);
-    } else {
-        buf_u8_set(msg + OF_MESSAGE_FLOW_MOD_COMMAND_OFFSET(version), command);
-    }
-}
-
 /**
  * @brief Get/set stats request/reply experimenter ID of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -290,11 +240,6 @@
     return val;
 }
 
-static inline void
-of_message_stats_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
-    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, experimenter_id);
-}
-
 /**
  * @brief Get/set stats request/reply experimenter subtype of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -309,11 +254,6 @@
     return val;
 }
 
-static inline void
-of_message_stats_experimenter_subtype_set(of_message_t msg, uint32_t subtype) {
-    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, subtype);
-}
-
 /**
  * @brief Get/set group mod command of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -328,9 +268,4 @@
     return val;
 }
 
-static inline void
-of_message_group_mod_command_set(of_message_t msg, uint16_t command) {
-    buf_u16_set(msg + OF_MESSAGE_GROUP_MOD_COMMAND_OFFSET, command);
-}
-
 #endif /* _OF_MESSAGE_H_ */
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 0b3ec3a..ae22f64 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -510,7 +510,7 @@
     }
 
     if (child->wire_type_set) {
-        child->wire_type_set(child, child->object_id);
+        child->wire_type_set(child);
     }
 
     /* Update the parent's length */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 2314d67..4b35dcc 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -139,30 +139,6 @@
 }
 
 /**
- * Set the object ID based on the wire buffer for any TLV object
- * @param obj The object being referenced
- * @param id The ID value representing what should be stored.
- */
-
-void
-of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    int wire_type;
-    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
-
-    wire_type = of_object_to_type_map[obj->version][id];
-    ASSERT(wire_type >= 0);
-
-    of_wire_buffer_u16_set(wbuf, 
-        OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_TYPE_OFFSET), wire_type);
-
-    if (wire_type == OF_EXPERIMENTER_TYPE) {
-        of_extension_object_id_set(obj, id);
-    }
-}
-
-/**
  * Get the object ID of an extended action
  * @param obj The object being referenced
  * @param id Where to store the object ID
@@ -209,44 +185,6 @@
 }
 
 /**
- * Set wire data for extension objects, not messages.
- */
-
-void
-of_extension_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    uint8_t *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
-    
-    switch (id) {
-    case OF_ACTION_BSN_MIRROR:
-    case OF_ACTION_ID_BSN_MIRROR:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 1);
-        break;
-    case OF_ACTION_BSN_SET_TUNNEL_DST:
-    case OF_ACTION_ID_BSN_SET_TUNNEL_DST:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 2);
-        break;
-    case OF_ACTION_NICIRA_DEC_TTL:
-    case OF_ACTION_ID_NICIRA_DEC_TTL:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_NICIRA);
-        buf_u16_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 18);
-        break;
-    case OF_INSTRUCTION_BSN_DISABLE_SRC_MAC_CHECK:
-        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, 0);
-        break;
-    default:
-        break;
-    }
-}
-
-/**
  * Get the object ID of an extended action
  * @param obj The object being referenced
  * @param id Where to store the object ID
@@ -551,27 +489,6 @@
 }
 
 /**
- * Set the length of an OXM object in the wire buffer
- * @param obj The object whose wire buffer is an OXM type
- * @param bytes Value to store in wire buffer
- */
-
-void
-of_oxm_wire_length_set(of_object_t *obj, int bytes)
-{
-    uint32_t type_len;
-    of_wire_buffer_t *wbuf;
-
-    ASSERT(bytes >= 0 && bytes < 256);
-
-    /* Read-modify-write */
-    _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-    OF_OXM_LENGTH_SET(type_len, bytes);
-    of_wire_buffer_u32_set(wbuf, 
-           OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), type_len);
-}
-
-/**
  * Get the object ID of an OXM object based on the wire buffer type
  * @param obj The object whose wire buffer is an OXM type
  * @param id (out) Where the ID is stored 
@@ -587,80 +504,6 @@
     *id = of_oxm_to_object_id(type_len, obj->version);
 }
 
-/**
- * Set the wire type of an OXM object based on the object ID passed
- * @param obj The object whose wire buffer is an OXM type
- * @param id The object ID mapped to an OXM wire type which is stored
- */
-
-void
-of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    uint32_t type_len;
-    int wire_type;
-    of_wire_buffer_t *wbuf;
-
-    ASSERT(OF_OXM_VALID_ID(id));
-
-    /* Read-modify-write */
-    _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-
-    switch (id) {
-    case OF_OXM_BSN_IN_PORTS_128:
-        type_len = 0x00030000 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_IN_PORTS_128_MASKED:
-        type_len = 0x00030100 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_LAG_ID:
-        type_len = 0x00030200 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_LAG_ID_MASKED:
-        type_len = 0x00030300 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_VRF:
-        type_len = 0x00030400 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_VRF_MASKED:
-        type_len = 0x00030500 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_GLOBAL_VRF_ALLOWED:
-        type_len = 0x00030600 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED:
-        type_len = 0x00030700 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_INTERFACE_CLASS_ID:
-        type_len = 0x00030800 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED:
-        type_len = 0x00030900 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_SRC_CLASS_ID:
-        type_len = 0x00030a00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED:
-        type_len = 0x00030b00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_DST_CLASS_ID:
-        type_len = 0x00030c00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_DST_CLASS_ID_MASKED:
-        type_len = 0x00030d00 | (type_len & 0xff);
-        break;
-    default:
-        wire_type = of_object_to_wire_type(id, obj->version);
-        ASSERT(wire_type >= 0);
-        type_len = 0x80000000 | (wire_type << 8) | (type_len & 0xff);
-        break;
-    }
-
-    of_wire_buffer_u32_set(wbuf, 
-           OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), type_len);
-}
-
-
-
 #define OF_U16_LEN_LENGTH_OFFSET 0
 
 /**
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index e709b70..f285a33 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -38,6 +38,7 @@
 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"
 invalid_value = "0xeeee"  # Note, as a string
@@ -154,16 +155,11 @@
     """
     Returns True if cls is a virtual class
     """
-    if cls in inheritance_map:
-        return True
     if cls.find("header") > 0:
         return True
     if loxi_utils.class_is_list(cls):
         return True
-    # TODO get this from the input file when we have virtual class syntax
-    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira", "of_bsn_stats_request", "of_bsn_stats_reply", "of_experimenter_stats_request", "of_experimenter_stats_reply", "of_instruction_experimenter", "of_instruction_bsn", "of_group_mod"]:
-        return True
-    return False
+    return loxi_globals.unified.class_by_name(cls).virtual
 
 ################################################################
 #
diff --git a/lang_c.py b/lang_c.py
index 762f82c..7718d48 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -41,6 +41,7 @@
 import c_gen.c_show_gen as c_show_gen
 import c_gen.c_validator_gen as c_validator_gen
 import c_gen.util
+import c_gen.codegen
 import loxi_utils.loxi_utils as loxi_utils
 import template_utils
 
@@ -173,3 +174,4 @@
     for (name, fn) in targets.items():
         with template_utils.open_output(install_dir, name) as outfile:
             fn(outfile, os.path.basename(name))
+    c_gen.codegen.gen_push_wire_types(install_dir)
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index ebd4f85..6fae92b 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -183,6 +183,10 @@
     def has_external_alignment(self):
         return self.params.get('length_includes_align') == 'False'
 
+    @property
+    def has_type_members(self):
+        return find(lambda m: isinstance(m, OFTypeMember), self.members) is not None
+
 """ one class unified across openflow versions. Keeps around a map version->versioned_class """
 class OFUnifiedClass(OFClass):
     def __new__(cls, version_classes, *a, **kw):
diff --git a/openflow_input/bsn_global_vrf_allowed b/openflow_input/bsn_global_vrf_allowed
index 543c6fd..ee26308 100644
--- a/openflow_input/bsn_global_vrf_allowed
+++ b/openflow_input/bsn_global_vrf_allowed
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_global_vrf_allowed_masked : of_oxm {
-    uint32_t type_len == 0x00030701;
+    uint32_t type_len == 0x00030702;
     uint8_t value;
     uint8_t value_mask;
 };
diff --git a/openflow_input/bsn_in_ports b/openflow_input/bsn_in_ports
index 05003b9..b23df63 100644
--- a/openflow_input/bsn_in_ports
+++ b/openflow_input/bsn_in_ports
@@ -50,7 +50,7 @@
  */
 
 struct of_oxm_bsn_in_ports_128 : of_oxm {
-    uint32_t type_len == 0x00030020;
+    uint32_t type_len == 0x00030010;
     of_bitmap_128_t value;
 };
 
diff --git a/openflow_input/bsn_l3_dst_class_id b/openflow_input/bsn_l3_dst_class_id
index 385add7..8d324a1 100644
--- a/openflow_input/bsn_l3_dst_class_id
+++ b/openflow_input/bsn_l3_dst_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_dst_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030d04;
+    uint32_t type_len == 0x00030d08;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_l3_interface_class_id b/openflow_input/bsn_l3_interface_class_id
index efeb949..80d1e37 100644
--- a/openflow_input/bsn_l3_interface_class_id
+++ b/openflow_input/bsn_l3_interface_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_interface_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030904;
+    uint32_t type_len == 0x00030908;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_l3_src_class_id b/openflow_input/bsn_l3_src_class_id
index f18aab9..58f60c6 100644
--- a/openflow_input/bsn_l3_src_class_id
+++ b/openflow_input/bsn_l3_src_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_src_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030b04;
+    uint32_t type_len == 0x00030b08;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_lag_id b/openflow_input/bsn_lag_id
index c96c1d6..63645a3 100644
--- a/openflow_input/bsn_lag_id
+++ b/openflow_input/bsn_lag_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_lag_id_masked : of_oxm {
-    uint32_t type_len == 0x00030304;
+    uint32_t type_len == 0x00030308;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_vrf b/openflow_input/bsn_vrf
index 3641faa..26959bd 100644
--- a/openflow_input/bsn_vrf
+++ b/openflow_input/bsn_vrf
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_vrf_masked : of_oxm {
-    uint32_t type_len == 0x00030504;
+    uint32_t type_len == 0x00030508;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index 9a5e4fa..10f13ca 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -135,7 +135,7 @@
         local action_len = reader2.peek(2, 2):uint()
         local child_reader = reader2.slice(action_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_action(child_reader, child_subtree, version)
+        local info = of_action_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
     list:set_text("List of actions")
@@ -151,7 +151,7 @@
         local port_desc_len = 64
         local child_reader = reader.slice(port_desc_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_port_desc(child_reader, child_subtree, version)
+        local info = of_port_desc_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -166,7 +166,7 @@
         local stats_len = reader.peek(0,2):uint()
         local child_reader = reader.slice(stats_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_flow_stats_entry(child_reader, child_subtree, version)
+        local info = of_flow_stats_entry_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -181,7 +181,7 @@
         local stats_len = 112
         local child_reader = reader.slice(stats_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_port_stats_entry(child_reader, child_subtree, version)
+        local info = of_port_stats_entry_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -196,7 +196,7 @@
         local stats_len = 24
         local child_reader = reader.slice(stats_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_table_stats_entry(child_reader, child_subtree, version)
+        local info = of_table_stats_entry_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -211,7 +211,7 @@
         local stats_len = 40
         local child_reader = reader.slice(stats_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_queue_stats_entry(child_reader, child_subtree, version)
+        local info = of_queue_stats_entry_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -244,7 +244,7 @@
         local match_len = 4 + reader2.peek(3,1):uint()
         local child_reader = reader2.slice(match_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_oxm(child_reader, child_subtree, version)
+        local info = of_oxm_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
     subtree:set_text("OXM")
@@ -256,7 +256,7 @@
         return
     end
     local child_subtree = subtree:add(fields[field_name], reader.peek_all(0))
-    local info = dissect_of_instruction(reader, child_subtree, version)
+    local info = of_instruction_dissectors[version](reader, child_subtree)
     child_subtree:set_text("Instructions")
 end
 
@@ -270,7 +270,7 @@
         local bucket_len = reader.peek(0,2):uint()
         local child_reader = reader.slice(bucket_len)
         local child_subtree = bucket_list_subtree:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_bucket(child_reader, child_subtree, version)
+        local info = of_bucket_dissectors[version](child_reader, child_subtree)
         child_subtree:set_text(info)
     end
 end
@@ -280,6 +280,6 @@
         return
     end
     local child_subtree = subtree:add(fields[field_name], reader.peek_all(0))
-    local info = dissect_of_oxm(reader, child_subtree, version)
+    local info = of_oxm_dissectors[version](reader, child_subtree)
     child_subtree:set_text(info)
 end
diff --git a/wireshark_gen/templates/openflow.lua b/wireshark_gen/templates/openflow.lua
index 931843d..bdbe2ec 100644
--- a/wireshark_gen/templates/openflow.lua
+++ b/wireshark_gen/templates/openflow.lua
@@ -39,8 +39,6 @@
 
 :: include('_ofreader.lua')
 
-:: include('_oftype_readers.lua')
-
 p_of = Proto ("of", "OpenFlow")
 
 local openflow_versions = {
@@ -104,25 +102,25 @@
 
 local of_message_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_header_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_header_v${version.wire_version},
 :: #endfor
 }
 
 local of_oxm_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_oxm_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_oxm_v${version.wire_version},
 :: #endfor
 }
 
 local of_action_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_action_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_action_v${version.wire_version},
 :: #endfor
 }
 
 local of_instruction_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_instruction_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_instruction_v${version.wire_version},
 :: #endfor
 }
 
@@ -140,13 +138,13 @@
 
 local of_stats_reply_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_stats_reply_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_stats_reply_v${version.wire_version},
 :: #endfor
 }
 
 local of_stats_request_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = of_stats_request_v${version.wire_version}_dissectors,
+    [${version.wire_version}] = dissect_of_stats_request_v${version.wire_version},
 :: #endfor
 }
 
@@ -174,6 +172,8 @@
 :: #endfor
 }
 
+:: include('_oftype_readers.lua')
+
 function dissect_of_message(buf, root)
     local reader = OFReader.new(buf)
     local subtree = root:add(p_of, buf(0))
@@ -186,95 +186,11 @@
     end
 
     local info = "unknown"
-    info = of_message_dissectors[version_val][type_val](reader, subtree)
+    info = of_message_dissectors[version_val](reader, subtree)
 
     return protocol, info
 end
 
-function dissect_of_oxm(reader, subtree, version_val)
-    local type_val = reader.peek(0,4):uint()
-    local info = "unknown"
-    if of_oxm_dissectors[version_val] and of_oxm_dissectors[version_val][type_val] then
-        info = of_oxm_dissectors[version_val][type_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_action(reader, subtree, version_val)
-    local type_val = reader.peek(0,2):uint()
-    local info = "unknown"
-    if of_action_dissectors[version_val] and of_action_dissectors[version_val][type_val] then
-        info = of_action_dissectors[version_val][type_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_instruction(reader, subtree, version_val)
-    local type_val = reader.peek(0,2):uint()
-    local info = "unknown"
-    if of_instruction_dissectors[version_val] and of_instruction_dissectors[version_val][type_val] then
-        info = of_instruction_dissectors[version_val][type_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_bucket(reader, subtree, version_val)
-    local info = "unknown"
-    if of_bucket_dissectors[version_val] then
-        info = of_bucket_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_port_desc(reader, subtree, version_val)
-    local info = "unknown"
-    if of_port_desc_dissectors[version_val] then
-        info = of_port_desc_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_flow_stats_entry(reader, subtree, version_val)
-    local info = "unknown"
-    if of_flow_stats_entry_dissectors[version_val] then
-        info = of_flow_stats_entry_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_port_stats_entry(reader, subtree, version_val)
-    local info = "unknown"
-    if of_port_stats_entry_dissectors[version_val] then
-        info = of_port_stats_entry_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_table_stats_entry(reader, subtree, version_val)
-    local info = "unknown"
-    if of_table_stats_entry_dissectors[version_val] then
-        info = of_table_stats_entry_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
-function dissect_of_queue_stats_entry(reader, subtree, version_val)
-    local info = "unknown"
-    if of_queue_stats_entry_dissectors[version_val] then
-        info = of_queue_stats_entry_dissectors[version_val](reader, subtree)
-    end
-
-    return info
-end
-
 -- of dissector function
 function p_of.dissector (buf, pkt, root)
     local offset = 0