Merge into master from pull request #239:
loci: only mask partially wildcarded fields (https://github.com/floodlight/loxigen/pull/239)
diff --git a/.gitignore b/.gitignore
index c0b10be..f4243d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,5 @@
 *.cache
 openflowj-loxi
 /bin
+*,cover
+/.coverage
diff --git a/Makefile b/Makefile
index 3767fba..018db0b 100644
--- a/Makefile
+++ b/Makefile
@@ -142,4 +142,13 @@
 ctags:
 	ctags ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES} ${TEST_DATA}
 
-.PHONY: all clean debug check pylint c python
+coverage:
+	find -name '*,cover' -exec rm {} \;
+	coverage erase
+	coverage run -a ./loxigen.py --lang=c
+	coverage run -a ./loxigen.py --lang=python
+	coverage run -a ./loxigen.py --lang=java
+	coverage run -a ./loxigen.py --lang=wireshark
+	coverage annotate -i --omit tenjin.py,pyparsing.py
+
+.PHONY: all clean debug check pylint c python coverage
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index f117bfd..4d37b36 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -153,6 +153,16 @@
             # 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:
@@ -281,10 +291,6 @@
     for cls in of_g.ordered_list_objects:
         of_g.unified[cls]["object_id"] = of_g.object_id
         of_g.object_id += 1
-    for cls in of_g.ordered_pseudo_objects:
-        of_g.unified[cls] = {}
-        of_g.unified[cls]["object_id"] = of_g.object_id
-        of_g.object_id += 1
 
 
 def initialize_versions():
@@ -330,7 +336,10 @@
                 else:
                     # HACK the C backend does not yet support of_oxm_t
                     if m.oftype == 'of_oxm_t':
-                        m_type = 'of_octets_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'
                     else:
                         enum = find(lambda e: e.name == m.oftype, protocol.enums)
                         if enum and "wire_type" in enum.params:
@@ -466,70 +475,3 @@
         classes = versions[version]["classes"]
         for cls in of_g.ordered_classes[wire_version]:
             add_class(wire_version, cls, classes[cls])
-
-
-def log_all_class_info():
-    """
-    Log the results of processing the input
-
-    Debug function
-    """
-
-    for cls in of_g.unified:
-        for v in of_g.unified[cls]:
-            if type(v) == type(0):
-                log("cls: %s. ver: %d. base len %d. %s" %
-                    (str(cls), v, of_g.base_length[(cls, v)],
-                     loxi_utils.class_is_var_len(cls,v) and "not fixed"
-                     or "fixed"))
-                if "use_version" in of_g.unified[cls][v]:
-                    log("cls %s: v %d mapped to %d" % (str(cls), v,
-                           of_g.unified[cls][v]["use_version"]))
-                if "members" in of_g.unified[cls][v]:
-                    for member in of_g.unified[cls][v]["members"]:
-                        log("   %-20s: type %-20s. offset %3d" %
-                            (member["name"], member["m_type"],
-                             member["offset"]))
-
-def generate_all_files():
-    """
-    Create the files for the language target
-    """
-    for (name, fn) in lang_module.targets.items():
-        path = of_g.options.install_dir + '/' + name
-        os.system("mkdir -p %s" % os.path.dirname(path))
-        with open(path, "w") as outfile:
-            fn(outfile, os.path.basename(name))
-        print("Wrote contents for " + name)
-
-if __name__ == '__main__':
-    of_g.loxigen_log_file = open("loxigen.log", "w")
-    of_g.loxigen_dbg_file = sys.stdout
-
-    of_g.process_commandline()
-    # @fixme Use command line params to select log
-
-    if not config_sanity_check():
-        debug("Config sanity check failed\n")
-        sys.exit(1)
-
-    # Import the language file
-    lang_file = "lang_%s" % of_g.options.lang
-    lang_module = __import__(lang_file)
-
-    # If list files, just list auto-gen files to stdout and exit
-    if of_g.options.list_files:
-        for name in lang_module.targets:
-            print of_g.options.install_dir + '/' + name
-        sys.exit(0)
-
-    log("\nGenerating files for target language %s\n" % of_g.options.lang)
-
-    initialize_versions()
-    read_input()
-    populate_type_maps()
-    analyze_input()
-    unify_input()
-    order_and_assign_object_ids()
-    log_all_class_info()
-    generate_all_files()
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 81f5a1a..3fa4f3a 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -306,20 +306,6 @@
     log("Generated %d identifiers" % (count - 1))
     out.write("\n#endif /* Loci identifiers header file */\n")
 
-def base_h_external(out, filename):
-    """
-    Copy contents of external file to base header
-
-    The contents of the filename are copied literally into the
-    out file handler.  This allows openflow common defines to
-    be entered into the LoxiGen code base.  The content of this
-    code must depend only on standard C headers.
-    """
-    infile = open(filename, "r")
-    contents = infile.read()
-    out.write(contents)
-    infile.close()
-
 def match_h_gen(out, name):
     """
     Generate code for
@@ -330,7 +316,6 @@
     c_match.gen_incompat_members(out)
     c_match.gen_match_struct(out)
     c_match.gen_match_comp(out)
-#    c_match.gen_match_accessors(out)
     out.write("\n#endif /* Match header file */\n")
 
 def top_h_gen(out, name):
@@ -375,7 +360,7 @@
  * Treat as private
  */
 #define OF_OBJECT_TO_MESSAGE(obj) \\
-    ((of_message_t)(WBUF_BUF((obj)->wire_object.wbuf)))
+    ((of_message_t)(WBUF_BUF((obj)->wbuf)))
 
 /**
  * Macro for the fixed length part of an object
@@ -469,8 +454,8 @@
  */
 #define OF_LENGTH_CHECK_ASSERT(obj) \\
     LOCI_ASSERT(((obj)->parent != NULL) || \\
-     ((obj)->wire_object.wbuf == NULL) || \\
-     (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
+     ((obj)->wbuf == NULL) || \\
+     (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
 
 #define OF_DEBUG_DUMP
 #if defined(OF_DEBUG_DUMP)
@@ -803,6 +788,7 @@
 #include <loci/of_match.h>
 #include <loci/of_object.h>
 #include <loci/loci_classes.h>
+#include <loci/loci_class_metadata.h>
 
 /****************************************************************
  *
@@ -908,12 +894,6 @@
                                    of_g.unified[cls]["object_id"]))
         last = of_g.unified[cls]["object_id"]
 
-    out.write("\n    /* Generic stats request/reply types; pseudo objects */\n")
-    for cls in of_g.ordered_pseudo_objects:
-        out.write("    %s = %d,\n" % (enum_name(cls),
-                                   of_g.unified[cls]["object_id"]))
-        last = of_g.unified[cls]["object_id"]
-
     out.write("""
     OF_OBJECT_COUNT = %d
 } of_object_id_t;
@@ -1037,23 +1017,6 @@
         sys.exit(1)
     return params
 
-def typed_function_base(cls, m_name):
-    """
-    Generate the core name for accessors based on the type
-    @param cls The class name
-    @param m_name The member name
-    """
-    (m_type, get_rv) = get_acc_rv(cls, m_name)
-    return "%s_%s" % (cls, m_type)
-
-def member_function_base(cls, m_name):
-    """
-    Generate the core name for accessors based on the member name
-    @param cls The class name
-    @param m_name The member name
-    """
-    return "%s_%s" % (cls, m_name)
-
 def field_ver_get(cls, m_name):
     """
     Generate a dict, indexed by wire version, giving a pair (type, offset)
@@ -1106,13 +1069,6 @@
 #
 ################################################################
 
-
-def gen_of_object_defs(out):
-    """
-    Generate low level of_object core operations
-    @param out The file for output, already open
-    """
-
 def gen_generics(out):
     for (cls, subclasses) in type_maps.inheritance_map.items():
         out.write("""
@@ -1313,58 +1269,6 @@
 }
 """ % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
 
-
-def gen_bind(out, cls, m_name, m_type):
-    """
-    Generate the body of a bind function
-    @param out The file to which to write
-    @param cls The class name for which code is being generated
-    @param m_name The name of the data member
-    @param m_type The type of the data member
-    """
-
-    bparams = ",\n    ".join(param_list(cls, m_name, "bind"))
-
-    i_call = init_call(e_type, "child", "parent->version", "0", "1")
-
-    out.write("""
-/**
- * Bind the child object to the parent object for read processing
- * @param parent The parent object
- * @param child The child object
- *
- * The child obj instance is completely initialized.
- */
-
-int
-%(cls)s_%(m_name)_bind(%(cls)s_t *parent,
-    %(e_type)s_t *child)
-{
-    int rv;
-
-    %(i_call)s;
-
-    /* Derive offset and length of child in parent */
-    OF_TRY(of_object_child_attach(parent, child,
-    if ((rv = of_list_first((of_object_t *)list, (of_object_t *)obj)) < 0) {
-        return rv;
-    }
-""" % dict(cls=cls, e_type=e_type, i_call=i_call))
-
-    # Special case flow_stats_entry lists
-
-    out.write("""
-    rv = of_object_wire_init((of_object_t *) obj, %(u_type)s,
-                               list->length);
-    if ((rv == OF_ERROR_NONE) && (%(len_str)s == 0)) {
-        return OF_ERROR_PARSE;
-    }
-
-    return rv;
-}
-""" % dict(cls=cls, e_type=e_type, u_type=enum_name(e_type), len_str=len_str))
-
-
 def gen_list_next(out, cls, e_type):
     """
     Generate the body of a list_next operation
@@ -1670,15 +1574,36 @@
     match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
     OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
 """ % dict(m_name=m_name))
+    elif m_type == "of_oxm_header_t":
+        out.write("""
+    /* Initialize child */
+    %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
+    /* Attach to parent */
+    %(m_name)s->parent = (of_object_t *)obj;
+    %(m_name)s->wbuf = obj->wbuf;
+    %(m_name)s->obj_offset = abs_offset;
+    %(m_name)s->length = 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":
+        out.write("""
+    /* Initialize child */
+    %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
+    /* Attach to parent */
+    %(m_name)s->parent = (of_object_t *)obj;
+    %(m_name)s->wbuf = obj->wbuf;
+    %(m_name)s->obj_offset = abs_offset;
+    %(m_name)s->length = cur_len;
+    of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
+""" % dict(m_type=m_type[:-2], m_name=m_name))
     else:
         out.write("""
     /* Initialize child */
     %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
     /* Attach to parent */
     %(m_name)s->parent = (of_object_t *)obj;
-    %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
-    %(m_name)s->wire_object.obj_offset = abs_offset;
-    %(m_name)s->wire_object.owned = 0;
+    %(m_name)s->wbuf = obj->wbuf;
+    %(m_name)s->obj_offset = abs_offset;
     %(m_name)s->length = cur_len;
 """ % dict(m_type=m_type[:-2], m_name=m_name))
 
@@ -1720,7 +1645,7 @@
         out.write("""
     new_len = %(m_name)s->length;
     /* If underlying buffer already shared; nothing to do */
-    if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
+    if (obj->wbuf == %(m_name)s->wbuf) {
         of_wire_buffer_grow(wbuf, abs_offset + new_len);
         /* Verify that the offsets are correct */
         LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
@@ -1752,9 +1677,7 @@
         elif m_type not in ["of_match_t", "of_octets_t"]:
             out.write("""
     /* @fixme Shouldn't this precede copying value's data to buffer? */
-    if (%(m_name)s->wire_length_set != NULL) {
-        %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
-    }
+    of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
 """ % dict(m_name=m_name))
         out.write("""
     /* Not scalar, update lengths if needed */
@@ -1985,20 +1908,6 @@
 #
 ################################################################
 
-
-################################################################
-# First, some utility functions for new/delete
-################################################################
-
-def del_function_proto(cls):
-    """
-    Return the prototype for the delete operator for the given class
-    @param cls The class name
-    """
-    fn = "void\n"
-    return fn
-
-
 ################################################################
 # Routines to generate the body of new/delete functions
 ################################################################
@@ -2058,15 +1967,14 @@
     obj->length = bytes;
     obj->object_id = %(enum)s;
 """ % dict(cls=cls, enum=enum_name(cls)))
-    gen_coerce_ops(out, cls)
 
     out.write("""
     /* Grow the wire buffer */
-    if (obj->wire_object.wbuf != NULL) {
+    if (obj->wbuf != NULL) {
         int tot_bytes;
 
-        tot_bytes = bytes + obj->wire_object.obj_offset;
-        of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
+        tot_bytes = bytes + obj->obj_offset;
+        of_wire_buffer_grow(obj->wbuf, tot_bytes);
     }
 }
 
@@ -2117,7 +2025,7 @@
 
         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);
+    of_object_wire_length_set((of_object_t *)obj, obj->length);
 """)
 
         if cls == "of_meter_stats":
@@ -2146,6 +2054,10 @@
     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"
+
     out.write("""
 /**
  * Create a new %(cls)s object
@@ -2170,13 +2082,12 @@
 
     bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
 
-    /* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
-    if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
+    if ((obj = (%(cls)s_t *)of_object_new(%(max_length)s)) == NULL) {
         return NULL;
     }
 
     %(cls)s_init(obj, version, bytes, 0);
-""" % dict(cls=cls, enum=enum_name(cls)))
+""" % 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) {
@@ -2329,99 +2240,6 @@
  ****************************************************************/
 """)
 
-#
-# @fixme Not clear that these should all be set for virtual fns
-#
-# @fixme Clean up.  should have a (language specific) map from class
-# to length and type get/set functions
-#
-
-def gen_coerce_ops(out, cls):
-    out.write("""
-    /* 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;
-    obj->wire_length_set = of_object_message_wire_length_set;
-""")
-    else:
-        if loxi_utils.class_is_tlv16(cls):
-            if not (cls in type_maps.inheritance_map): # Don't set for super
-                out.write("""
-    obj->wire_length_set = of_tlv16_wire_length_set;
-""")
-            out.write("""
-    obj->wire_length_get = of_tlv16_wire_length_get;
-""")
-            if loxi_utils.class_is_action(cls):
-                out.write("""
-    obj->wire_type_get = of_action_wire_object_id_get;
-""")
-            if loxi_utils.class_is_action_id(cls):
-                out.write("""
-    obj->wire_type_get = of_action_id_wire_object_id_get;
-""")
-            if loxi_utils.class_is_instruction(cls):
-                out.write("""
-    obj->wire_type_get = of_instruction_wire_object_id_get;
-""")
-            if loxi_utils.class_is_instruction_id(cls):
-                out.write("""
-    obj->wire_type_get = of_instruction_id_wire_object_id_get;
-""")
-            if loxi_utils.class_is_queue_prop(cls):
-                    out.write("""
-    obj->wire_type_get = of_queue_prop_wire_object_id_get;
-""")
-            if loxi_utils.class_is_table_feature_prop(cls):
-                    out.write("""
-    obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
-""")
-            if loxi_utils.class_is_meter_band(cls):
-                    out.write("""
-    obj->wire_type_get = of_meter_band_wire_object_id_get;
-""")
-            if loxi_utils.class_is_hello_elem(cls):
-                    out.write("""
-    obj->wire_type_get = of_hello_elem_wire_object_id_get;
-""")
-            if loxi_utils.class_is_bsn_tlv(cls):
-                    out.write("""
-    obj->wire_type_get = of_bsn_tlv_wire_object_id_get;
-""")
-        if loxi_utils.class_is_oxm(cls):
-            out.write("""
-    obj->wire_length_get = of_oxm_wire_length_get;
-    obj->wire_type_get = of_oxm_wire_object_id_get;
-""")
-        if loxi_utils.class_is_u16_len(cls):
-            out.write("""
-    obj->wire_length_get = of_u16_len_wire_length_get;
-    obj->wire_length_set = of_u16_len_wire_length_set;
-""")
-        if cls == "of_packet_queue":
-            out.write("""
-    obj->wire_length_get = of_packet_queue_wire_length_get;
-    obj->wire_length_set = of_packet_queue_wire_length_set;
-""")
-#        if cls == "of_list_meter_band_stats":
-#            out.write("""
-#    obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
-#""")
-        if cls == "of_meter_stats":
-            out.write("""
-    obj->wire_length_get = of_meter_stats_wire_length_get;
-    obj->wire_length_set = of_meter_stats_wire_length_set;
-""")
-
 def gen_new_function_definitions(out, cls):
     """
     Generate the new operator for all classes
@@ -2502,201 +2320,3 @@
 """ % dict(cls=cls))
 
     out.write("#endif /* _LOCI_DOC_H_ */\n")
-
-################################################################
-#
-# For fun, here are some unified, traditional C structure representation
-#
-################################################################
-
-def gen_cof_to_wire(out):
-    pass
-
-def gen_wire_to_cof(out):
-    pass
-
-def gen_cof_instance(out, cls):
-    out.write("struct c%s_s {\n" % cls)
-    for m in of_g.ordered_members[cls]:
-        if m in of_g.skip_members:
-            continue
-        entry = of_g.unified[cls]["union"][m]
-        cof_type = type_to_cof_type(entry["m_type"])
-        out.write("    %-20s %s;\n" % (cof_type, m))
-    out.write("};\n\n");
-
-def gen_cof_structs(out):
-    """
-    Generate non-version specific (common) representation of structures
-
-    @param out The file to which to write the functions
-    """
-
-    out.write("\n/* Common, unified OpenFlow structure representations */\n")
-    for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            continue
-        gen_cof_instance(out, cls)
-
-################################################################
-#
-# Generate code samples for applications.
-#
-################################################################
-
-def gen_code_samples(out, name):
-    out.write("""
-#if 0 /* Do not compile in */
-/**
- * @file %(name)s
- *
- * These are code samples for inclusion in other components
- */
-
-""" % dict(name=name))
-
-    gen_jump_table_template(out)
-    # These are messages that a switch might expect.
-    msg_list = ["of_echo_request",
-                "of_hello",
-                "of_packet_in",
-                "of_packet_out",
-                "of_port_mod",
-                "of_port_stats_request",
-                "of_queue_get_config_request",
-                "of_queue_stats_request",
-                "of_flow_add",
-                "of_flow_modify",
-                "of_flow_modify_strict",
-                "of_flow_delete",
-                "of_flow_delete_strict",
-                "of_get_config_request",
-                "of_flow_stats_request",
-                "of_barrier_request",
-                "of_echo_reply",
-                "of_aggregate_stats_request",
-                "of_desc_stats_request",
-                "of_table_stats_request",
-                "of_features_request",
-                "of_table_mod",
-                "of_set_config",
-                "of_experimenter",
-                "of_experimenter_stats_request",
-                "of_group_desc_stats_request",
-                "of_group_features_stats_request",
-                "of_role_request"]
-
-    gen_message_handler_templates(out, msgs=msg_list)
-
-    out.write("""
-#endif
-""")
-
-def gen_jump_table_template(out=sys.stdout, all_unhandled=True,
-                            cxn_type="ls_cxn_handle_t",
-                            unhandled="unhandled_message"):
-    """
-    Generate a template for a jump table.
-    @param out The file to which to write the functions
-    """
-    out.write("""
-/*
- * Simple jump table definition for message handling
- */
-typedef int (*msg_handler_f)(%(cxn_type)s cxn, of_object_t *obj);
-typedef msg_handler_f msg_jump_table_t[OF_MESSAGE_OBJECT_COUNT];
-
-/* Jump table template for message objects */
-extern msg_jump_table_t jump_table;
-
-/* C-code template */
-msg_jump_table_t jump_table = {
-    %(unhandled)s, /* OF_OBJECT; place holder for generic object  */
-""" % dict(unhandled=unhandled, cxn_type=cxn_type))
-    count = 0
-    fn_name = unhandled
-    for cls in of_g.ordered_messages:
-        comma = ","
-        count += 1
-        if count == len(of_g.ordered_messages):
-            comma = " "
-        if not all_unhandled:
-            fn_name = "%s_handler" % cls[3:]
-        out.write("    %s%s /* %s */\n" % (fn_name, comma, enum_name(cls)))
-
-    out.write("};\n")
-
-def gen_message_switch_stmt_tmeplate(out=sys.stdout, all_unhandled=True,
-                                     cxn_type="ls_cxn_handle_t",
-                                     unhandled="unhandled_message"):
-    out.write("""
-/*
- * Simple switch statement for message handling
- */
-
-    switch (obj->object_id):
-""")
-    fn_name = unhandled
-    for cls in of_g.ordered_messages:
-        if not all_unhandled:
-            fn_name = "%s_handler" % cls[3:]
-        out.write("""
-    case %(enum)s:
-        rv = %(fn_name)s(cxn, obj);
-        break;
-""" % dict(fn_name=fn_name, cls=cls, enum=enum_name(cls)))
-    out.write("""
-    default:
-        rv = LS_ERROR_PARAM;
-        break;
-    }
-
-    TRACE("Handled msg %p with rv %d (%s)", obj, rv, ls_error_strings[rv]);
-
-    return rv;
-""")
-
-
-def gen_message_handler_templates(out=sys.stdout, cxn_type="ls_cxn_handle_t",
-                                  unhandled="unhandled_message", msgs=None):
-    gen_jump_table_template(out, False, cxn_type)
-    out.write("""
-/**
- * Function for unhandled message
- */
-static int
-unhandled_message(%(cxn_type)s cxn, of_object_t *obj)
-{
-    (void)cxn;
-    (void)obj;
-    TRACE("Unhandled message %%p.  Object id %%d", obj, obj->object_id);
-
-    return LS_ERROR_UNAVAIL;
-}
-""" % dict(unhandled=unhandled, cxn_type=cxn_type))
-
-    if not msgs:
-        msgs = of_g.ordered_messages
-    for cls in msgs:
-        out.write("""
-/**
- * Handle a %(s_cls)s message
- * @param cxn Connection handler for the owning connection
- * @param _obj Generic type object for the message to be coerced
- * @returns Error code
- */
-
-static int
-%(s_cls)s_handler(%(cxn_type)s cxn, of_object_t *_obj)
-{
-    %(cls)s_t *obj;
-
-    TRACE("Handling %(cls)s message: %%p.", obj);
-    obj = (%(cls)s_t *)_obj;
-
-    /* Handle object of type %(cls)s_t */
-
-    return LS_ERROR_NONE;
-}
-""" % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
-    gen_message_switch_stmt_tmeplate(out, False, cxn_type)
diff --git a/c_gen/c_dump_gen.py b/c_gen/c_dump_gen.py
index a0af14e..d4a016c 100644
--- a/c_gen/c_dump_gen.py
+++ b/c_gen/c_dump_gen.py
@@ -86,9 +86,6 @@
 
 """)
 
-    type_to_emitter = dict(
-
-        )
     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):
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index b5ef80a..7fd6a21 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -622,7 +622,6 @@
     /* For each active member, add an OXM entry to the list */
 """)
     for key in match.match_keys_sorted:
-        entry = match.of_match_members[key]
         out.write("""\
     if (OF_MATCH_MASK_%(ku)s_ACTIVE_TEST(src)) {
         if (!OF_MATCH_MASK_%(ku)s_EXACT_TEST(src)) {
@@ -874,7 +873,8 @@
                 of_match_v%(version)s_delete(wire_match);
                 return rv;
             }
-            octets->bytes = OF_MATCH_BYTES(wire_match->length);
+            of_wire_buffer_grow(wire_match->wbuf, OF_MATCH_BYTES(wire_match->length));
+            octets->bytes = wire_match->wbuf->current_bytes;
             of_object_wire_buffer_steal((of_object_t *)wire_match,
                                         &octets->data);
             of_match_v%(version)s_delete(wire_match);
@@ -929,7 +929,7 @@
 
             /* Free the wire buffer control block without freeing
              * octets->bytes. */
-            of_wire_buffer_steal(wire_match.wire_object.wbuf, &tmp);
+            of_wire_buffer_steal(wire_match.wbuf, &tmp);
         }
         break;
 """ % dict(version=version, ver_name=of_g.of_version_wire2name[version]))
diff --git a/c_gen/c_show_gen.py b/c_gen/c_show_gen.py
index fc3edb8..9d84477 100644
--- a/c_gen/c_show_gen.py
+++ b/c_gen/c_show_gen.py
@@ -87,9 +87,6 @@
 
 """)
 
-    type_to_emitter = dict(
-
-        )
     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):
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 6cc9612..8537f66 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -99,6 +99,8 @@
         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",
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
@@ -348,7 +350,6 @@
 extern int run_scalar_acc_tests(void);
 extern int run_list_tests(void);
 extern int run_message_tests(void);
-extern int run_setup_from_add_tests(void);
 
 extern int run_validator_tests(void);
 
@@ -384,9 +385,6 @@
 
     for version in of_g.of_version_range:
         for cls in of_g.ordered_list_objects:
-            if cls in type_maps.inheritance_map:
-                continue
-
             if version in of_g.unified[cls]:
                out.write("""
 extern int
@@ -565,10 +563,10 @@
 
     if not type_maps.class_is_virtual(cls):
         out.write("""
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
 
-        obj->wire_length_get((of_object_t *)obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
         TEST_ASSERT(length == %(length)d);
     }
 
@@ -692,7 +690,7 @@
 
 
 # Helper function to set up a subclass instance for a test
-def setup_instance(out, cls, subcls, instance, v_name, inst_len, version):
+def setup_instance(out, cls, subcls, instance, v_name, version):
     base_type = loxi_utils.list_to_entry_type(cls)
     setup_template = """
     %(subcls)s_init(%(inst)s, %(v_name)s, -1, 1);
@@ -709,23 +707,11 @@
     for i in range(2):
         out.write(setup_template %
                   dict(inst=instance, subcls=subcls, v_name=v_name,
-                       base_type=base_type, cls=cls, inst_len=inst_len,
+                       base_type=base_type, cls=cls,
                        version=version))
 
-def check_instance(out, cls, subcls, instance, v_name, inst_len, version, last):
-    check_template = ""
-    if inst_len >= 0:
-        check_template = """
-    TEST_ASSERT(%(inst)s->length == %(inst_len)d);
-    if (%(inst)s->wire_length_get != NULL) {
-        int length;
-
-        %(inst)s->wire_length_get(
-            (of_object_t *)&elt, &length);
-        TEST_ASSERT(length == %(inst_len)d);
-    }
-"""
-    check_template += """
+def check_instance(out, cls, subcls, instance, v_name, version, last):
+    check_template = """
     TEST_ASSERT(%(inst)s->object_id == %(elt_name)s);
     value = %(subcls)s_%(v_name)s_check(
         %(inst)s, value);
@@ -734,7 +720,7 @@
     out.write("\n    /* Check two instances of type %s */" % instance)
 
     out.write(check_template %
-              dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
+              dict(elt_name=loxi_utils.enum_name(subcls),
                    inst=instance, subcls=subcls,
                    v_name=loxi_utils.version_to_name(version)))
     out.write("""\
@@ -742,7 +728,7 @@
 """ % dict(cls=cls))
 
     out.write(check_template %
-              dict(elt_name=loxi_utils.enum_name(subcls), inst_len=inst_len,
+              dict(elt_name=loxi_utils.enum_name(subcls),
                    inst=instance, subcls=subcls,
                    v_name=loxi_utils.version_to_name(version)))
     if last:
@@ -791,12 +777,10 @@
             out.write("    %s = &elt.%s;\n" % (instance, instance))
 
     if len(sub_classes) == 0: # No inheritance case
-        inst_len = loxi_utils.base_type_to_length(base_type, version)
-        setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
+        setup_instance(out, cls, base_type, "elt_p", v_name, version)
     else:
         for instance, subcls in sub_classes:
-            inst_len = of_g.base_length[(subcls, version)]
-            setup_instance(out, cls, subcls, instance, v_name, inst_len, version)
+            setup_instance(out, cls, subcls, instance, v_name, version)
     out.write("""
 
     return value;
@@ -840,21 +824,12 @@
 
     out.write("    TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
     if len(sub_classes) == 0: # No inheritance case
-        if loxi_utils.class_is_var_len(base_type, version):
-            inst_len = -1
-        else:
-            inst_len = loxi_utils.base_type_to_length(base_type, version)
-        check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
-                       version, True)
+        check_instance(out, cls, base_type, "elt_p", v_name, version, True)
     else:
         count = 0
         for instance, subcls in sub_classes:
             count += 1
-            if loxi_utils.class_is_var_len(subcls, version):
-                inst_len = -1
-            else:
-                inst_len = of_g.base_length[(subcls, version)]
-            check_instance(out, cls, subcls, instance, v_name, inst_len,
+            check_instance(out, cls, subcls, instance, v_name,
                            version, count==len(sub_classes))
 
     out.write("""
@@ -865,9 +840,6 @@
 def gen_list_set_check_funs(out):
     for version in of_g.of_version_range:
         for cls in of_g.ordered_list_objects:
-            if cls in type_maps.inheritance_map:
-                continue
-
             if version in of_g.unified[cls]:
                 setup_list_fn(out, version, cls)
                 check_list_fn(out, version, cls)
@@ -939,8 +911,6 @@
  */
 """ % v_name)
         for cls in of_g.ordered_list_objects:
-            if cls in type_maps.inheritance_map:
-                continue
             if version in of_g.unified[cls]:
                 list_test(out, version, cls)
 
@@ -952,8 +922,6 @@
     for version in of_g.of_version_range:
         v_name = loxi_utils.version_to_name(version)
         for cls in of_g.ordered_list_objects:
-            if cls in type_maps.inheritance_map:
-                continue
             if version in of_g.unified[cls]:
                 test_name = "%s_%s" % (cls, v_name)
                 out.write("    RUN_TEST(%s);\n" % test_name)
@@ -1221,24 +1189,11 @@
         for instance, subcls in sub_classes:
             out.write("    %s = &elt.%s;\n" % (instance, instance))
 
-#     if type_maps.class_is_virtual(base_type):
-#         out.write("""\
-#     TEST_OK(%(base_type)s_header_init(
-#         (%(base_type)s_header_t *)&elt, %(v_name)s, -1, 1));
-# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
-#     else:
-#         out.write("""\
-#     TEST_OK(%(base_type)s_init(&elt, %(v_name)s, -1, 1));
-# """ % dict(base_type=base_type, v_name=loxi_utils.version_to_name(version)))
-
     if len(sub_classes) == 0: # No inheritance case
-        inst_len = loxi_utils.base_type_to_length(base_type, version)
-        setup_instance(out, cls, base_type, "elt_p", v_name, inst_len, version)
+        setup_instance(out, cls, base_type, "elt_p", v_name, version)
     else:
         for instance, subcls in sub_classes:
-            inst_len = of_g.base_length[(subcls, version)]
-            setup_instance(out, cls, subcls, instance, v_name,
-                           inst_len, version)
+            setup_instance(out, cls, subcls, instance, v_name, version)
     out.write("""
     return value;
 }
@@ -1284,21 +1239,13 @@
 
     out.write("    TEST_OK(%(cls)s_first(list, &elt));\n" % dict(cls=cls))
     if len(sub_classes) == 0: # No inheritance case
-        if loxi_utils.class_is_var_len(base_type, version):
-            inst_len = -1
-        else:
-            inst_len = loxi_utils.base_type_to_length(base_type, version)
-        check_instance(out, cls, base_type, "elt_p", v_name, inst_len,
+        check_instance(out, cls, base_type, "elt_p", v_name,
                        version, True)
     else:
         count = 0
         for instance, subcls in sub_classes:
             count += 1
-            if loxi_utils.class_is_var_len(subcls, version):
-                inst_len = -1
-            else:
-                inst_len = of_g.base_length[(subcls, version)]
-            check_instance(out, cls, subcls, instance, v_name, inst_len,
+            check_instance(out, cls, subcls, instance, v_name,
                            version, count==len(sub_classes))
     out.write("""
 """ % dict(base_type=base_type))
@@ -1417,6 +1364,19 @@
         FREE(octets.data);
     }
 """ % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
+        elif m_type == "of_bsn_vport_t": # FIXME: tests only q_in_q
+            out.write("""\
+    %(var_name)s = %(sub_cls)s_new(%(v_name)s);
+    TEST_ASSERT(%(var_name)s != NULL);
+    value = %(sub_cls)s_q_in_q_%(v_name)s_populate(
+        &%(var_name)s->q_in_q, value);
+    TEST_ASSERT(value != 0);
+    %(cls)s_%(m_name)s_set(
+        obj, %(var_name)s);
+    %(sub_cls)s_delete(%(var_name)s);
+""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
+           var_name=var_name_map(m_type),
+           v_name=loxi_utils.version_to_name(version)))
         else:
             sub_cls = m_type[:-2] # Trim _t
             out.write("""
@@ -1483,6 +1443,22 @@
     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_t": # FIXME: tests only q_in_q
+            sub_cls = m_type[:-2] # Trim _t
+            out.write("""
+    { /* Use get/delete to access on check */
+        %(m_type)s *%(m_name)s_ptr;
+
+        %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
+        TEST_ASSERT(%(m_name)s_ptr != NULL);
+        value = %(sub_cls)s_q_in_q_%(v_name)s_check(
+            &%(m_name)s_ptr->q_in_q, value);
+        TEST_ASSERT(value != 0);
+        %(sub_cls)s_delete(%(m_name)s_ptr);
+    }
+""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
+           var_name=var_name_map(m_type),
+           v_name=loxi_utils.version_to_name(version)))
         else:
             sub_cls = m_type[:-2] # Trim _t
             out.write("""
@@ -1552,16 +1528,16 @@
            v_name=v_name, length=length, version=version))
     if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
         out.write("""
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
 
-        obj->wire_length_get((of_object_t *)obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
         TEST_ASSERT(length == %(length)d);
     }
-    if (obj->wire_type_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t obj_id;
 
-        obj->wire_type_get((of_object_t *)obj, &obj_id);
+        loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
         TEST_ASSERT(obj_id == %(u_cls)s);
     }
 
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 2b46932..6e6f3fe 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -367,7 +367,6 @@
 
     /* Do a simple if/else search for the ver, experimenter and subtype */
 """
-    first = True
     for version, experimenter_lists in type_maps.extension_message_subtype.items():
         for exp, subtypes in experimenter_lists.items():
             experimenter_function += """
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index af4dfa4..fe5e2ad 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -180,3 +180,153 @@
 
     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())
+
+ClassMetadata = namedtuple('ClassMetadata',
+    ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
+
+def generate_class_metadata(install_dir):
+    with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
+        util.render_template(out, "loci_class_metadata.h")
+
+    with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
+        class_metadata = []
+        for uclass in loxi_globals.unified.classes:
+            wire_length_get = 'NULL'
+            wire_length_set = 'NULL'
+            wire_type_get = 'NULL'
+            wire_type_set = 'NULL'
+
+            if uclass and not uclass.virtual and uclass.has_type_members:
+                wire_type_set = '%s_push_wire_types' % uclass.name
+
+            if uclass.is_message and uclass.name != "of_header":
+                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_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"]:
+                wire_length_get = "of_u16_len_wire_length_get"
+                wire_length_set = "of_u16_len_wire_length_set"
+            elif uclass.name == 'of_match_v3':
+                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'
+
+            class_metadata.append(ClassMetadata(
+                name=uclass.name,
+                wire_length_get=wire_length_get,
+                wire_length_set=wire_length_set,
+                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_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'),
+        ])
+
+        util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)
diff --git a/c_gen/identifiers.py b/c_gen/identifiers.py
index 5862967..a3304c9 100644
--- a/c_gen/identifiers.py
+++ b/c_gen/identifiers.py
@@ -65,15 +65,6 @@
         if name not in idents_by_group[ofp_group]:
             idents_by_group[ofp_group].append(name)
 
-def all_versions_agree(all_idents, version_list, name):
-    val_list = all_idents[name]["values_by_version"]
-    for version in version_list:
-        if not version in val_list:
-            return False
-        if str(val_list[version]) != str(all_idents[name]["common_value"]):
-            return False
-    return True
-
 def defined_versions_agree(all_idents, version_list, name):
     val_list = all_idents[name]["values_by_version"]
     for version in version_list:
diff --git a/c_gen/loci_utils.py b/c_gen/loci_utils.py
deleted file mode 100644
index 686fb0f..0000000
--- a/c_gen/loci_utils.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import c_gen.of_g_legacy as of_g
-
-def class_signature(members):
-    """
-    Generate a signature string for a class in canonical form
-
-    @param cls The class whose signature is to be generated
-    """
-    return ";".join([",".join([x["m_type"], x["name"], str(x["offset"])])
-                     for x in members])
-
-def type_dec_to_count_base(m_type):
-    """
-    Resolve a type declaration like uint8_t[4] to a count (4) and base_type
-    (uint8_t)
-
-    @param m_type The string type declaration to process
-    """
-    count = 1
-    chk_ar = m_type.split('[')
-    if len(chk_ar) > 1:
-        count_str = chk_ar[1].split(']')[0]
-        if count_str in of_g.ofp_constants:
-            count = of_g.ofp_constants[count_str]
-        else:
-            count = int(count_str)
-        base_type = chk_ar[0]
-    else:
-        base_type = m_type
-    return count, base_type
-
-def list_to_entry_type(cls):
-    """
-    Return the entry type for a list
-    """
-    slen = len("of_list_")
-    return "of_" + cls[slen:]
-
-def type_to_short_name(m_type):
-    if m_type in of_g.of_base_types:
-        tname = of_g.of_base_types[m_type]["short_name"]
-    elif m_type in of_g.of_mixed_types:
-        tname = of_g.of_mixed_types[m_type]["short_name"]
-    else:
-        tname = "unknown"
-    return tname
-
-def type_to_name_type(cls, member_name):
-    """
-    Generate the root name of a member for accessor functions, etc
-    @param cls The class name
-    @param member_name The member name
-    """
-    members = of_g.unified[cls]["union"]
-    if not member_name in members:
-        debug("Error:  %s is not in class %s for acc_name defn" %
-              (member_name, cls))
-        os.exit()
-
-    mem = members[member_name]
-    m_type = mem["m_type"]
-    id = mem["memid"]
-    tname = type_to_short_name(m_type)
-
-    return "o%d_m%d_%s" % (of_g.unified[cls]["object_id"], id, tname)
-
-
-def member_to_index(m_name, members):
-    """
-    Given a member name, return the index in the members dict
-    @param m_name The name of the data member to search for
-    @param members The dict of members
-    @return Index if found, -1 not found
-
-    Note we could generate an index when processing the original input
-    """
-    count = 0
-    for d in members:
-        if d["name"] == m_name:
-            return count
-        count += 1
-    return -1
-
-def member_base_type(cls, m_name):
-    """
-    Map a member to its of_ type
-    @param cls The class name
-    @param m_name The name of the member being gotten
-    @return The of_ type of the member
-    """
-    rv = of_g.unified[cls]["union"][m_name]["m_type"]
-    if rv[-2:] == "_t":
-        return rv
-    return rv + "_t"
-
-def member_type_is_octets(cls, m_name):
-    return member_base_type(cls, m_name) == "of_octets_t"
-
-def h_file_to_define(name):
-    """
-    Convert a .h file name to the define used for the header
-    """
-    h_name = name[:-2].upper()
-    h_name = "_" + h_name + "_H_"
-    return h_name
-
-def type_to_cof_type(m_type):
-    if m_type in of_g.of_base_types:
-        if "cof_type" in of_g.of_base_types[m_type]:
-            return of_g.of_base_types[m_type]["cof_type"]
-    return m_type
-
-
-def member_is_scalar(cls, m_name):
-    return of_g.unified[cls]["union"][m_name]["m_type"] in of_g.of_scalar_types
-
-def type_is_scalar(m_type):
-    return m_type in of_g.of_scalar_types
-
-def skip_member_name(name):
-    return name.find("pad") == 0 or name in of_g.skip_members
-
-def enum_name(cls):
-    """
-    Return the name used for an enum identifier for the given class
-    @param cls The class name
-    """
-    return cls.upper()
-
-def class_in_version(cls, ver):
-    """
-    Return boolean indicating if cls is defined for wire version ver
-    """
-
-    return (cls, ver) in of_g.base_length
-
-def instance_to_class(instance, parent):
-    """
-    Return the name of the class for an instance of inheritance type parent
-    """
-    return parent + "_" + instance
-
-def sub_class_to_var_name(cls):
-    """
-    Given a subclass name like of_action_output, generate the
-    name of a variable like 'output'
-    @param cls The class name
-    """
-    pass
-
-def class_is_var_len(cls, version):
-    # Match is special case.  Only version 1.2 (wire version 3) is var
-    if cls == "of_match":
-        return version == 3
-
-    return not (cls, version) in of_g.is_fixed_length
-
-def base_type_to_length(base_type, version):
-    if base_type + "_t" in of_g.of_base_types:
-        inst_len = of_g.of_base_types[base_type + "_t"]["bytes"]
-    else:
-        inst_len = of_g.base_length[(base_type, version)]
-
-def version_to_name(version):
-    """
-    Convert an integer version to the C macro name
-    """
-    return "OF_" + of_g.version_names[version]
-
-##
-# Is class a flow modify of some sort?
-
-def cls_is_flow_mod(cls):
-    return cls in ["of_flow_mod", "of_flow_modify", "of_flow_add", "of_flow_delete",
-                   "of_flow_modify_strict", "of_flow_delete_strict"]
-
-def all_member_types_get(cls, version):
-    """
-    Get the members and list of types for members of a given class
-    @param cls The class name to process
-    @param version The version for the class
-    """
-    member_types = []
-
-    if not version in of_g.unified[cls]:
-        return ([], [])
-
-    if "use_version" in of_g.unified[cls][version]:
-        v = of_g.unified[cls][version]["use_version"]
-        members = of_g.unified[cls][v]["members"]
-    else:
-        members = of_g.unified[cls][version]["members"]
-    # Accumulate variables that are supported
-    for member in members:
-        m_type = member["m_type"]
-        m_name = member["name"]
-        if skip_member_name(m_name):
-            continue
-        if not m_type in member_types:
-            member_types.append(m_type)
-
-    return (members, member_types)
-
-def list_name_extract(list_type):
-    """
-    Return the base name for a list object of the given type
-    @param list_type The type of the list as appears in the input,
-    for example list(of_port_desc_t).
-    @return A pair, (list-name, base-type) where list-name is the
-    base name for the list, for example of_list_port_desc, and base-type
-    is the type of list elements like of_port_desc_t
-    """
-    base_type = list_type[5:-1]
-    list_name = base_type
-    if list_name.find("of_") == 0:
-        list_name = list_name[3:]
-    if list_name[-2:] == "_t":
-        list_name = list_name[:-2]
-    list_name = "of_list_" + list_name
-    return (list_name, base_type)
-
-def version_to_name(version):
-    """
-    Convert an integer version to the C macro name
-    """
-    return "OF_" + of_g.version_names[version]
-
-def gen_c_copy_license(out):
-    """
-    Generate the top comments for copyright and license
-    """
-    import c_gen.util
-    c_gen.util.render_template(out, '_copyright.c')
-
-def accessor_returns_error(a_type, m_type):
-    is_var_len = (not type_is_scalar(m_type)) and \
-        [x for x in of_g.of_version_range if class_is_var_len(m_type[:-2], x)] != []
-    if a_type == "set" and is_var_len:
-        return True
-    elif m_type == "of_match_t":
-        return True
-    else:
-        return False
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index df93c2b..220d043 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -120,6 +120,8 @@
         return True
     if cls.find("of_bsn_tlv") == 0:
         return True
+    if cls.find("of_bsn_vport") == 0:
+        return True
     return False
 
 def class_is_u16_len(cls):
@@ -161,122 +163,12 @@
 
     return False
 
-def class_is_action_id(cls):
-    """
-    Return True if cls_name is an action object
-
-    Note that action_id is not an action object, though it has
-    the same header.  It looks like an action header, but the type
-    is used to identify a kind of action, it does not indicate the
-    type of the object following.
-    """
-    if cls.find("of_action_id") == 0:
-        return True
-
-    # For each vendor, check for vendor specific action
-    for exp in of_g.experimenter_name_to_id:
-        if cls.find("of_action_id_" + exp) == 0:
-            return True
-
-    return False
-
-def class_is_instruction(cls):
-    """
-    Return True if cls_name is an instruction object
-    """
-    if cls.find("of_instruction_id") == 0:
-        return False
-    if cls.find("of_instruction") == 0:
-        return True
-
-    # For each vendor, check for vendor specific action
-    for exp in of_g.experimenter_name_to_id:
-        if cls.find("of_instruction" + exp) == 0:
-            return True
-
-    return False
-
-def class_is_instruction_id(cls):
-    """
-    Return True if cls_name is an action object
-
-    Note that instruction_id is not an instruction object, though it has
-    the same header.  It looks like an instruction header, but the type
-    is used to identify a kind of instruction, it does not indicate the
-    type of the object following.
-    """
-    if cls.find("of_instruction_id") == 0:
-        return True
-
-    # For each vendor, check for vendor specific action
-    for exp in of_g.experimenter_name_to_id:
-        if cls.find("of_instruction_id_" + exp) == 0:
-            return True
-
-    return False
-
-def class_is_meter_band(cls):
-    """
-    Return True if cls_name is an instruction object
-    """
-    # meter_band_stats is not a member of meter_band class hierarchy
-    if cls.find("of_meter_band_stats") == 0:
-        return False
-    if cls.find("of_meter_band") == 0:
-        return True
-    return False
-
-def class_is_hello_elem(cls):
-    """
-    Return True if cls_name is an instruction object
-    """
-    if cls.find("of_hello_elem") == 0:
-        return True
-    return False
-
-def class_is_queue_prop(cls):
-    """
-    Return True if cls_name is a queue_prop object
-    """
-    if cls.find("of_queue_prop") == 0:
-        return True
-
-    # For each vendor, check for vendor specific action
-    for exp in of_g.experimenter_name_to_id:
-        if cls.find("of_queue_prop_" + exp) == 0:
-            return True
-
-    return False
-
-def class_is_table_feature_prop(cls):
-    """
-    Return True if cls_name is a queue_prop object
-    """
-    if cls.find("of_table_feature_prop") == 0:
-        return True
-    return False
-
-def class_is_stats_message(cls):
-    """
-    Return True if cls_name is a message object based on info in unified
-    """
-
-    return "stats_type" in of_g.unified[cls]["union"]
-
 def class_is_list(cls):
     """
     Return True if cls_name is a list object
     """
     return (cls.find("of_list_") == 0)
 
-def class_is_bsn_tlv(cls):
-    """
-    Return True if cls_name is a BSN TLV object
-    """
-    if cls.find("of_bsn_tlv") == 0:
-        return True
-    return False
-
 def type_is_of_object(m_type):
     """
     Return True if m_type is an OF object type
@@ -302,26 +194,6 @@
         tname = "unknown"
     return tname
 
-def type_to_name_type(cls, member_name):
-    """
-    Generate the root name of a member for accessor functions, etc
-    @param cls The class name
-    @param member_name The member name
-    """
-    members = of_g.unified[cls]["union"]
-    if not member_name in members:
-        debug("Error:  %s is not in class %s for acc_name defn" %
-              (member_name, cls))
-        os.exit()
-
-    mem = members[member_name]
-    m_type = mem["m_type"]
-    id = mem["memid"]
-    tname = type_to_short_name(m_type)
-
-    return "o%d_m%d_%s" % (of_g.unified[cls]["object_id"], id, tname)
-
-
 def member_to_index(m_name, members):
     """
     Given a member name, return the index in the members dict
@@ -350,27 +222,6 @@
         return rv
     return rv + "_t"
 
-def member_type_is_octets(cls, m_name):
-    return member_base_type(cls, m_name) == "of_octets_t"
-
-def h_file_to_define(name):
-    """
-    Convert a .h file name to the define used for the header
-    """
-    h_name = name[:-2].upper()
-    h_name = "_" + h_name + "_H_"
-    return h_name
-
-def type_to_cof_type(m_type):
-    if m_type in of_g.of_base_types:
-        if "cof_type" in of_g.of_base_types[m_type]:
-            return of_g.of_base_types[m_type]["cof_type"]
-    return m_type
-
-
-def member_is_scalar(cls, m_name):
-    return of_g.unified[cls]["union"][m_name]["m_type"] in of_g.of_scalar_types
-
 def type_is_scalar(m_type):
     return m_type in of_g.of_scalar_types
 
@@ -397,14 +248,6 @@
     """
     return parent + "_" + instance
 
-def sub_class_to_var_name(cls):
-    """
-    Given a subclass name like of_action_output, generate the
-    name of a variable like 'output'
-    @param cls The class name
-    """
-    pass
-
 def class_is_var_len(cls, version):
     # Match is special case.  Only version 1.2 (wire version 3) is var
     if cls == "of_match":
@@ -412,18 +255,6 @@
 
     return not (cls, version) in of_g.is_fixed_length
 
-def base_type_to_length(base_type, version):
-    if base_type + "_t" in of_g.of_base_types:
-        inst_len = of_g.of_base_types[base_type + "_t"]["bytes"]
-    else:
-        inst_len = of_g.base_length[(base_type, version)]
-
-def version_to_name(version):
-    """
-    Convert an integer version to the C macro name
-    """
-    return "OF_" + of_g.version_names[version]
-
 ##
 # Is class a flow modify of some sort?
 
@@ -499,31 +330,3 @@
         return True
     else:
         return False
-
-def render_template(out, name, path, context, prefix = None):
-    """
-    Render a template using tenjin.
-    out: a file-like object
-    name: name of the template
-    path: array of directories to search for the template
-    context: dictionary of variables to pass to the template
-    prefix: optional prefix to use for embedding (for other languages than python)
-    """
-    pp = [ tenjin.PrefixedLinePreprocessor(prefix=prefix) if prefix else tenjin.PrefixedLinePreprocessor() ] # support "::" syntax
-    template_globals = { "to_str": str, "escape": str } # disable HTML escaping
-    engine = TemplateEngine(path=path, pp=pp)
-    out.write(engine.render(name, context, template_globals))
-
-def render_static(out, name, path):
-    """
-    Write out a static template.
-    out: a file-like object
-    name: name of the template
-    path: array of directories to search for the template
-    """
-    # Reuse the tenjin logic for finding the template
-    template_filename = tenjin.FileSystemLoader().find(name, path)
-    if not template_filename:
-        raise ValueError("template %s not found" % name)
-    with open(template_filename) as infile:
-        out.write(infile.read())
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index 3311282..b58ca08 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -292,47 +292,12 @@
 VERSION_1_2 = 3
 VERSION_1_3 = 4
 
-# Ignore version for some functions
-VERSION_ANY = -1
-
-## @var supported_wire_protos
-# The wire protocols this version of LoxiGen supports
-supported_wire_protos = set([1, 2, 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"}
-param_version_names = {1:"1.0", 2:"1.1", 3:"1.2", 4:"1.3"}
-
-##
-# Maps and ranges related to versioning
-
-# For parameter version indications
-of_param_version_map = {
-    "1.0":VERSION_1_0,
-    "1.1":VERSION_1_1,
-    "1.2":VERSION_1_2,
-    "1.3":VERSION_1_3
-    }
-
-# For parameter version indications
-of_version_map = {
-    "1.0":VERSION_1_0,
-    "1.1":VERSION_1_1,
-    "1.2":VERSION_1_2,
-    "1.3":VERSION_1_3
-    }
 
 # 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_max = VERSION_1_3
-
-
-of_version_name2wire = dict(
-    OF_VERSION_1_0=VERSION_1_0,
-    OF_VERSION_1_1=VERSION_1_1,
-    OF_VERSION_1_2=VERSION_1_2,
-    OF_VERSION_1_3=VERSION_1_3
-    )
 
 of_version_wire2name = {
     VERSION_1_0:"OF_VERSION_1_0",
@@ -367,21 +332,3 @@
     nicira = 0x00002320,
     openflow = 0x000026e1
     )
-
-def experimenter_name_lookup(experimenter_id):
-    """
-    Map an experimenter ID to its LOXI recognized name string
-    """
-    for name, id in of_g.experimenter_name_to_id.items():
-        if id == experimenter_id:
-            return name
-    return None
-
-################################################################
-#
-# Debug
-#
-################################################################
-
-loxigen_dbg_file = sys.stdout
-loxigen_log_file = sys.stdout
diff --git a/c_gen/templates/_push_wire_types.c b/c_gen/templates/_push_wire_types.c
index fd2536c..96a9111 100644
--- a/c_gen/templates/_push_wire_types.c
+++ b/c_gen/templates/_push_wire_types.c
@@ -25,7 +25,7 @@
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
 ::
-static void
+void
 ${data.class_name}_push_wire_types(of_object_t *obj)
 {
     unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
diff --git a/c_gen/templates/loci_class_metadata.c b/c_gen/templates/loci_class_metadata.c
new file mode 100644
index 0000000..1aca773
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.c
@@ -0,0 +1,51 @@
+:: # 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.
+::
+:: include('_copyright.c')
+:: import loxi_globals
+
+/****************************************************************
+ *
+ * loci_class_metadata.c
+ *
+ * Tables with information for each class
+ *
+ ****************************************************************/
+
+#include "loci_log.h"
+#include <loci/loci.h>
+
+struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT] = {
+:: for data in class_metadata:
+    [${data.name.upper()}] = {
+        .wire_length_get=${data.wire_length_get},
+        .wire_length_set=${data.wire_length_set},
+        .wire_type_get=${data.wire_type_get},
+        .wire_type_set=${data.wire_type_set},
+    },
+:: #endfor
+};
diff --git a/c_gen/templates/loci_class_metadata.h b/c_gen/templates/loci_class_metadata.h
new file mode 100644
index 0000000..37962e3
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.h
@@ -0,0 +1,63 @@
+:: # 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.
+::
+:: include('_copyright.c')
+::
+#ifndef __LOCI_CLASS_METADATA_H__
+#define __LOCI_CLASS_METADATA_H__
+
+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);
+
+struct loci_class_metadata {
+    of_wire_length_get_f wire_length_get;
+    of_wire_length_set_f wire_length_set;
+    of_wire_type_get_f wire_type_get;
+    of_wire_type_set_f wire_type_set;
+};
+
+extern struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT];
+
+static inline void
+of_object_wire_length_set(of_object_t *obj, int bytes)
+{
+    if (loci_class_metadata[obj->object_id].wire_length_set) {
+        loci_class_metadata[obj->object_id].wire_length_set(obj, bytes);
+    }
+}
+
+static inline void
+of_object_wire_type_set(of_object_t *obj)
+{
+    if (loci_class_metadata[obj->object_id].wire_type_set) {
+        loci_class_metadata[obj->object_id].wire_type_set(obj);
+    }
+}
+
+#endif
diff --git a/c_gen/templates/loci_classes.h b/c_gen/templates/loci_classes.h
index 12c07d1..c5147cb 100644
--- a/c_gen/templates/loci_classes.h
+++ b/c_gen/templates/loci_classes.h
@@ -33,6 +33,7 @@
 
 :: for uclass in loxi_globals.unified.classes:
 void ${uclass.name}_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
+void ${uclass.name}_push_wire_types(of_object_t *obj);
 :: #endfor
 
 ${legacy_code}
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index c57371a..1ea9eeb 100644
--- a/c_gen/templates/loci_int.h
+++ b/c_gen/templates/loci_int.h
@@ -67,8 +67,8 @@
 of_object_u16_get(of_object_t *obj, int offset) {
     uint16_t val16;
 
-    of_wire_buffer_u16_get(obj->wire_object.wbuf,
-        obj->wire_object.obj_offset + offset, &val16);
+    of_wire_buffer_u16_get(obj->wbuf,
+        obj->obj_offset + offset, &val16);
 
     return (int)val16;
 }
@@ -86,8 +86,8 @@
     uint16_t val16;
 
     val16 = (uint16_t)value;
-    of_wire_buffer_u16_set(obj->wire_object.wbuf,
-        obj->wire_object.obj_offset + offset, val16);
+    of_wire_buffer_u16_set(obj->wbuf,
+        obj->obj_offset + offset, val16);
 }
 
 /**
diff --git a/c_gen/templates/loci_setup_from_add_fns.c b/c_gen/templates/loci_setup_from_add_fns.c
deleted file mode 100644
index 5f63d29..0000000
--- a/c_gen/templates/loci_setup_from_add_fns.c
+++ /dev/null
@@ -1,250 +0,0 @@
-:: # 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')
-#include <loci/loci.h>
-#include <loci/of_object.h>
-#include "loci_log.h"
-#include "loci_int.h"
-
-/* Flow stats entry setup for all versions */
-
-static int
-flow_stats_entry_setup_from_flow_add_common(of_flow_stats_entry_t *obj,
-                                            of_flow_add_t *flow_add,
-                                            of_object_t *effects,
-                                            int entry_match_offset,
-                                            int add_match_offset)
-{
-    int entry_len, add_len;
-    of_wire_buffer_t *wbuf;
-    int abs_offset;
-    int delta;
-    uint16_t val16;
-    uint64_t cookie;
-    of_octets_t match_octets;
-
-    /* Transfer the match underlying object from add to stats entry */
-    wbuf = OF_OBJECT_TO_WBUF(obj);
-    entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset);
-    add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
-
-    match_octets.bytes = add_len;
-    match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
-
-    /* Copy data into flow entry */
-    abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, entry_match_offset);
-    of_wire_buffer_replace_data(wbuf, abs_offset, entry_len,
-                                match_octets.data, add_len);
-
-    /* Not scalar, update lengths if needed */
-    delta = add_len - entry_len;
-    if (delta != 0) {
-        /* Update parent(s) */
-        of_object_parent_length_update((of_object_t *)obj, delta);
-    }
-
-    of_flow_add_cookie_get(flow_add, &cookie);
-    of_flow_stats_entry_cookie_set(obj, cookie);
-
-    of_flow_add_priority_get(flow_add, &val16);
-    of_flow_stats_entry_priority_set(obj, val16);
-
-    of_flow_add_idle_timeout_get(flow_add, &val16);
-    of_flow_stats_entry_idle_timeout_set(obj, val16);
-
-    of_flow_add_hard_timeout_get(flow_add, &val16);
-    of_flow_stats_entry_hard_timeout_set(obj, val16);
-
-    /* Effects may come from different places */
-    if (effects != NULL) {
-        if (obj->version == OF_VERSION_1_0) {
-            OF_TRY(of_flow_stats_entry_actions_set(obj,
-                (of_list_action_t *)effects));
-        } else {
-            OF_TRY(of_flow_stats_entry_instructions_set(obj,
-                (of_list_instruction_t *)effects));
-        }
-    } else {
-        if (obj->version == OF_VERSION_1_0) {
-            of_list_action_t actions;
-            of_flow_add_actions_bind(flow_add, &actions);
-            OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
-        } else {
-            of_list_instruction_t instructions;
-            of_flow_add_instructions_bind(flow_add, &instructions);
-            OF_TRY(of_flow_stats_entry_instructions_set(obj, &instructions));
-        }
-    }
-
-    return OF_ERROR_NONE;
-}
-
-/* Flow removed setup for all versions */
-
-static int
-flow_removed_setup_from_flow_add_common(of_flow_removed_t *obj,
-                                        of_flow_add_t *flow_add,
-                                        int removed_match_offset,
-                                        int add_match_offset)
-{
-    int add_len, removed_len;
-    of_wire_buffer_t *wbuf;
-    int abs_offset;
-    int delta;
-    uint16_t val16;
-    uint64_t cookie;
-    of_octets_t match_octets;
-
-    /* Transfer the match underlying object from add to removed obj */
-    wbuf = OF_OBJECT_TO_WBUF(obj);
-    removed_len = _WIRE_MATCH_PADDED_LEN(obj, removed_match_offset);
-    add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
-
-    match_octets.bytes = add_len;
-    match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
-
-    /* Copy data into flow removed */
-    abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, removed_match_offset);
-    of_wire_buffer_replace_data(wbuf, abs_offset, removed_len,
-                                match_octets.data, add_len);
-
-    /* Not scalar, update lengths if needed */
-    delta = add_len - removed_len;
-    if (delta != 0) {
-        /* Update parent(s) */
-        of_object_parent_length_update((of_object_t *)obj, delta);
-    }
-
-    of_flow_add_cookie_get(flow_add, &cookie);
-    of_flow_removed_cookie_set(obj, cookie);
-
-    of_flow_add_priority_get(flow_add, &val16);
-    of_flow_removed_priority_set(obj, val16);
-
-    of_flow_add_idle_timeout_get(flow_add, &val16);
-    of_flow_removed_idle_timeout_set(obj, val16);
-
-    if (obj->version >= OF_VERSION_1_2) {
-        of_flow_add_hard_timeout_get(flow_add, &val16);
-        of_flow_removed_hard_timeout_set(obj, val16);
-    }
-
-    return OF_ERROR_NONE;
-}
-
-/* Set up a flow removed message from the original add */
-
-int
-of_flow_removed_setup_from_flow_add(of_flow_removed_t *obj,
-                                    of_flow_add_t *flow_add)
-{
-    switch (obj->version) {
-    case OF_VERSION_1_0:
-        return flow_removed_setup_from_flow_add_common(obj, flow_add,
-                                                       8, 8);
-        break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
-        return flow_removed_setup_from_flow_add_common(obj, flow_add,
-                                                       48, 48);
-        break;
-    default:
-        return OF_ERROR_VERSION;
-        break;
-    }
-
-    return OF_ERROR_NONE;
-}
-
-
-/* Set up a packet in message from the original add */
-
-int
-of_packet_in_setup_from_flow_add(of_packet_in_t *obj,
-                                 of_flow_add_t *flow_add)
-{
-    int add_len, pkt_in_len;
-    of_wire_buffer_t *wbuf;
-    int abs_offset;
-    int delta;
-    const int pkt_in_match_offset = 16;
-    const int add_match_offset = 48;
-    of_octets_t match_octets;
-
-    if (obj->version < OF_VERSION_1_2) {
-        /* Nothing to be done before OF 1.2 */
-        return OF_ERROR_NONE;
-    }
-
-    /* Transfer match struct from flow add to packet in object */
-    wbuf = OF_OBJECT_TO_WBUF(obj);
-    pkt_in_len = _WIRE_MATCH_PADDED_LEN(obj, pkt_in_match_offset);
-    add_len = _WIRE_MATCH_PADDED_LEN(flow_add, add_match_offset);
-
-    match_octets.bytes = add_len;
-    match_octets.data = OF_OBJECT_BUFFER_INDEX(flow_add, add_match_offset);
-
-    /* Copy data into pkt_in msg */
-    abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, pkt_in_match_offset);
-    of_wire_buffer_replace_data(wbuf, abs_offset, pkt_in_len,
-                                match_octets.data, add_len);
-
-    /* Not scalar, update lengths if needed */
-    delta = add_len - pkt_in_len;
-    if (delta != 0) {
-        /* Update parent(s) */
-        of_object_parent_length_update((of_object_t *)obj, delta);
-    }
-
-    return OF_ERROR_NONE;
-}
-
-/* Set up a stats entry from the original add */
-
-int
-of_flow_stats_entry_setup_from_flow_add(of_flow_stats_entry_t *obj,
-                                        of_flow_add_t *flow_add,
-                                        of_object_t *effects)
-{
-    switch (obj->version) {
-    case OF_VERSION_1_0:
-        return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
-                                                           effects, 4, 8);
-        break;
-    case OF_VERSION_1_1:
-    case OF_VERSION_1_2:
-    case OF_VERSION_1_3:
-        return flow_stats_entry_setup_from_flow_add_common(obj, flow_add,
-                                                           effects, 48, 48);
-        break;
-    default:
-        return OF_ERROR_VERSION;
-    }
-
-    return OF_ERROR_NONE;
-}
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index b210570..88fd029 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -398,5 +398,14 @@
 #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_flags(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/locitest/main.c b/c_gen/templates/locitest/main.c
index 86f7ae6..36bf60c 100644
--- a/c_gen/templates/locitest/main.c
+++ b/c_gen/templates/locitest/main.c
@@ -33,7 +33,6 @@
     TEST_ASSERT(run_scalar_acc_tests() == TEST_PASS);
     TEST_ASSERT(run_list_tests() == TEST_PASS);
     TEST_ASSERT(run_message_tests() == TEST_PASS);
-    TEST_ASSERT(run_setup_from_add_tests() == TEST_PASS);
 
     TEST_ASSERT(run_validator_tests() == TEST_PASS);
 
diff --git a/c_gen/templates/locitest/test_setup_from_add.c b/c_gen/templates/locitest/test_setup_from_add.c
deleted file mode 100644
index 0b07076..0000000
--- a/c_gen/templates/locitest/test_setup_from_add.c
+++ /dev/null
@@ -1,133 +0,0 @@
-:: # 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')
-
-/**
- * Test code for setup from flow add routines
- */
-
-#include <locitest/test_common.h>
-
-/* mcheck is a glibc extension */
-#if defined(__linux__)
-#include <mcheck.h>
-#define MCHECK_INIT mcheck(NULL)
-#else
-#define MCHECK_INIT do { } while (0)
-#endif
-
-
-static int
-test_removed_setup_from_add(void)
-{
-    of_flow_removed_t *removed;
-    of_flow_add_t *add;
-    of_match_t m1, m2;
-
-    TEST_ASSERT((add = of_flow_add_new(OF_VERSION_1_0)) != NULL);
-    TEST_ASSERT((removed = of_flow_removed_new(OF_VERSION_1_0)) != NULL);
-
-    TEST_ASSERT(of_flow_add_OF_VERSION_1_0_populate(add, 1) != 0);
-    TEST_ASSERT(of_flow_add_match_get(add, &m1) == 0);
-
-    TEST_ASSERT(of_flow_removed_setup_from_flow_add(removed, add) == 0);
-    TEST_ASSERT(of_flow_removed_match_get(removed, &m2) == 0);
-    TEST_ASSERT(memcmp(&m1, &m2, sizeof(m1)) == 0);
-
-    of_flow_add_delete(add);
-    of_flow_removed_delete(removed);
-
-    return TEST_PASS;
-}
-
-
-static int
-test_stats_entry_setup_from_add(void)
-{
-    of_flow_add_t *add;
-    of_flow_stats_entry_t *entry;
-    of_match_t m1, m2;
-    of_list_action_t *list;
-    of_list_action_t list_out;
-
-    TEST_ASSERT((add = of_flow_add_new(OF_VERSION_1_0)) != NULL);
-    TEST_ASSERT((entry = of_flow_stats_entry_new(OF_VERSION_1_0)) != NULL);
-
-    TEST_ASSERT(of_flow_add_OF_VERSION_1_0_populate(add, 1) != 0);
-    TEST_ASSERT(of_flow_add_match_get(add, &m1) == 0);
-
-    TEST_ASSERT(of_flow_stats_entry_setup_from_flow_add(entry, add, NULL) == 0);
-    TEST_ASSERT(of_flow_stats_entry_match_get(entry, &m2) == 0);
-    TEST_ASSERT(memcmp(&m1, &m2, sizeof(m1)) == 0);
-
-    of_flow_add_delete(add);
-    of_flow_stats_entry_delete(entry);
-
-    /* @todo check action lists agree */
-
-    /* Same with an external action list */
-
-    TEST_ASSERT((add = of_flow_add_new(OF_VERSION_1_0)) != NULL);
-    TEST_ASSERT((entry = of_flow_stats_entry_new(OF_VERSION_1_0)) != NULL);
-
-    TEST_ASSERT(of_flow_add_OF_VERSION_1_0_populate(add, 1) != 0);
-    TEST_ASSERT(of_flow_add_match_get(add, &m1) == 0);
-
-    list = of_list_action_new(OF_VERSION_1_0);
-    TEST_ASSERT(list != NULL);
-    TEST_ASSERT(of_list_action_OF_VERSION_1_0_populate(list, 1) != 0);
-
-    /* Verify matches agree */
-    TEST_ASSERT(of_flow_stats_entry_setup_from_flow_add(entry, add, list) == 0);
-    TEST_ASSERT(of_flow_stats_entry_match_get(entry, &m2) == 0);
-    TEST_ASSERT(memcmp(&m1, &m2, sizeof(m1)) == 0);
-
-    of_list_action_init(&list_out, OF_VERSION_1_0, 0, 1);
-    of_flow_stats_entry_actions_bind(entry, &list_out);
-
-    /* Verify lists agree */
-    TEST_ASSERT(list->length == list_out.length);
-    TEST_ASSERT(memcmp(WBUF_BUF(list->wire_object.wbuf),
-                       WBUF_BUF(list_out.wire_object.wbuf),
-                       list->length));
-
-    of_flow_add_delete(add);
-    of_list_action_delete(list);
-    of_flow_stats_entry_delete(entry);
-
-    return TEST_PASS;
-}
-
-
-int run_setup_from_add_tests(void)
-{
-    RUN_TEST(removed_setup_from_add);
-    RUN_TEST(stats_entry_setup_from_add);
-
-    return TEST_PASS;
-}
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 69bd8d3..39a6790 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -61,11 +61,10 @@
     MEMSET(obj, 0, sizeof(*obj));
 
     if (bytes > 0) {
-        if ((obj->wire_object.wbuf = of_wire_buffer_new(bytes)) == NULL) {
+        if ((obj->wbuf = of_wire_buffer_new(bytes)) == NULL) {
             FREE(obj);
             return NULL;
         }
-        obj->wire_object.owned = 1;
     }
 
     return obj;
@@ -87,15 +86,8 @@
         return;
     }
 
-    /*
-     * Make callback if present
-     */
-    if (obj->track_info.delete_cb != NULL) {
-        obj->track_info.delete_cb(obj);
-    }
-
-    if (obj->wire_object.owned) {
-        of_wire_buffer_free(obj->wire_object.wbuf);
+    if (obj->parent == NULL) {
+        of_wire_buffer_free(obj->wbuf);
     }
 
     FREE(obj);
@@ -121,13 +113,11 @@
     MEMSET(dst, 0, sizeof(*dst));
 
     /* Allocate a minimal wire buffer assuming we will not write to it. */
-    if ((dst->wire_object.wbuf = of_wire_buffer_new(src->length)) == NULL) {
+    if ((dst->wbuf = of_wire_buffer_new(src->length)) == NULL) {
         FREE(dst);
         return NULL;
     }
 
-    dst->wire_object.owned = 1;
-
     init_fn = of_object_init_map[src->object_id];
     init_fn(dst, src->version, src->length, 0);
 
@@ -211,7 +201,7 @@
     }
 
     obj->version = version;
-    obj->wire_object.wbuf = wbuf;
+    obj->wbuf = wbuf;
     wbuf->buf = msg;
     wbuf->alloc_bytes = len;
     wbuf->current_bytes = len;
@@ -239,23 +229,18 @@
 of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes, 
                       of_buffer_free_f buf_free)
 {
-    of_wire_object_t *wobj;
     of_wire_buffer_t *wbuf;
 
     LOCI_ASSERT(buf != NULL);
     LOCI_ASSERT(bytes > 0);
-    // LOCI_ASSERT(wobj is not bound);
-
-    wobj = &obj->wire_object;
-    MEMSET(wobj, 0, sizeof(*wobj));
 
     wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
     if (wbuf == NULL) {
         return OF_ERROR_RESOURCE;
     }
 
-    wobj->wbuf = wbuf;
-    wobj->owned = 1;
+    obj->wbuf = wbuf;
+    obj->obj_offset = 0;
     obj->length = bytes;
 
     return OF_ERROR_NONE;
@@ -291,17 +276,14 @@
 object_child_attach(of_object_t *parent, of_object_t *child, 
                        int offset, int bytes)
 {
-    of_wire_object_t *c_wobj; /* Pointer to child's wire object */
     of_wire_buffer_t *wbuf; /* Pointer to common wire buffer manager */
 
     child->parent = parent;
-    wbuf = parent->wire_object.wbuf;
+    wbuf = parent->wbuf;
 
     /* Set up the child's wire buf to point to same as parent */
-    c_wobj = &child->wire_object;
-    c_wobj->wbuf = wbuf;
-    c_wobj->obj_offset = parent->wire_object.obj_offset + offset;
-    c_wobj->owned = 0;
+    child->wbuf = wbuf;
+    child->obj_offset = parent->obj_offset + offset;
 
     /*
      * bytes determines if this is a read or write setup.
@@ -312,7 +294,7 @@
         int tot_bytes; /* Total bytes to request for buffer if updated */
 
         /* Set up space for the child in the parent's buffer */
-        tot_bytes = parent->wire_object.obj_offset + offset + bytes;
+        tot_bytes = parent->obj_offset + offset + bytes;
 
         of_wire_buffer_grow(wbuf, tot_bytes);
         child->length = bytes;
@@ -331,7 +313,7 @@
 of_object_can_grow(of_object_t *obj, int new_len)
 {
     return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
-        WBUF_ALLOC_BYTES(obj->wire_object.wbuf);
+        WBUF_ALLOC_BYTES(obj->wbuf);
 }
 
 /**
@@ -405,7 +387,7 @@
 of_list_append_bind(of_object_t *parent, of_object_t *child)
 {
     if (parent == NULL || child == NULL ||
-           parent->wire_object.wbuf == NULL) {
+           parent->wbuf == NULL) {
         return OF_ERROR_PARAM;
     }
 
@@ -417,13 +399,8 @@
                         child->length);
 
     /* Update the wire length and type if needed */
-    if (child->wire_length_set) {
-        child->wire_length_set(child, child->length);
-    }
-
-    if (child->wire_type_set) {
-        child->wire_type_set(child);
-    }
+    of_object_wire_length_set(child, child->length);
+    of_object_wire_type_set(child);
 
     /* Update the parent's length */
     of_object_parent_length_update(parent, child->length);
@@ -452,7 +429,7 @@
         return OF_ERROR_RESOURCE;
     }
 
-    of_wire_buffer_grow(list->wire_object.wbuf,
+    of_wire_buffer_grow(list->wbuf,
                         OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
 
     MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
@@ -503,8 +480,8 @@
 static int
 of_list_is_last(of_object_t *parent, of_object_t *child)
 {
-    if (child->wire_object.obj_offset + child->length >= 
-        parent->wire_object.obj_offset + parent->length) {
+    if (child->obj_offset + child->length >=
+        parent->obj_offset + parent->length) {
         return 1;
     }
 
@@ -538,7 +515,7 @@
     }
 
     /* Offset is relative to parent start */
-    offset = (child->wire_object.obj_offset - parent->wire_object.obj_offset) +
+    offset = (child->obj_offset - parent->obj_offset) +
         child->length;
     object_child_attach(parent, child, offset, 0);
 
@@ -549,8 +526,8 @@
 of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
 {
     LOCI_ASSERT(obj != NULL);
-    of_wire_buffer_steal(obj->wire_object.wbuf, buffer);
-    obj->wire_object.wbuf = NULL;
+    of_wire_buffer_steal(obj->wbuf, buffer);
+    obj->wbuf = NULL;
 }
 
 #define _MAX_PARENT_ITERATIONS 4
@@ -575,18 +552,16 @@
     while (obj != NULL) {
         LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
         obj->length += delta;
-        if (obj->wire_length_set != NULL) {
-            obj->wire_length_set(obj, obj->length);
-        }
+        of_object_wire_length_set(obj, obj->length);
 #ifndef NDEBUG
-        wbuf = obj->wire_object.wbuf;
+        wbuf = obj->wbuf;
 #endif
 
         /* Asserts for wire length checking */
-        LOCI_ASSERT(obj->length + obj->wire_object.obj_offset <=
+        LOCI_ASSERT(obj->length + obj->obj_offset <=
                WBUF_CURRENT_BYTES(wbuf));
         if (obj->parent == NULL) {
-            LOCI_ASSERT(obj->length + obj->wire_object.obj_offset ==
+            LOCI_ASSERT(obj->length + obj->obj_offset ==
                    WBUF_CURRENT_BYTES(wbuf));
         }
 
@@ -612,9 +587,9 @@
 of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
                     int max_len)
 {
-    if (obj->wire_type_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t id;
-        obj->wire_type_get(obj, &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;
         }
@@ -622,9 +597,9 @@
         /* 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);
     }
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
-        obj->wire_length_get(obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
         if (length < 0 || (max_len > 0 && length > max_len)) {
             return OF_ERROR_PARSE;
         }
@@ -665,8 +640,8 @@
 
     d_wbuf = OF_OBJECT_TO_WBUF(dst);
     s_wbuf = OF_OBJECT_TO_WBUF(src);
-    dst_offset = dst->wire_object.obj_offset + dst_length;
-    src_offset = src->wire_object.obj_offset;
+    dst_offset = dst->obj_offset + dst_length;
+    src_offset = src->obj_offset;
     OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
     MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
            OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
@@ -685,7 +660,7 @@
 of_packet_out_actions_length_set(of_packet_t *obj, int len)
 {
     if (obj == NULL || obj->object_id != OF_PACKET_IN ||
-        obj->wire_object.wbuf == NULL) {
+        obj->wbuf == NULL) {
         return OF_ERROR_PARAM;
     }
 
@@ -696,7 +671,7 @@
 _packet_out_data_offset_get(of_packet_t *obj)
 {
     if (obj == NULL || obj->object_id != OF_PACKET_IN ||
-        obj->wire_object.wbuf == NULL) {
+        obj->wbuf == NULL) {
         return -1;
     }
 
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index 3172ad1..d299537 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -48,30 +48,6 @@
 #include <loci/of_message.h>
 #include <loci/of_wire_buf.h>
 
-/**
- * This is the number of bytes reserved for metadata in each
- * of_object_t instance.
- */
-#define OF_OBJECT_METADATA_BYTES 32
-
-/*
- * Generic accessors:
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * FIXME: TBD if wire_length_set and wire_type_set are required.
- */
-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);
-
 /****************************************************************
  * General list operations: first, next, append_setup, append_advance
  ****************************************************************/
@@ -91,16 +67,6 @@
 extern of_object_t *of_object_new(int bytes);
 extern of_object_t *of_object_dup(of_object_t *src);
 
-/**
- * Callback function prototype for deleting an object
- */
-typedef void (*of_object_delete_callback_f)(of_object_t *obj);
-
-typedef struct of_object_track_info_s {
-    of_object_delete_callback_f delete_cb;  /* To be implemented */
-    void *delete_cookie;
-} of_object_track_info_t;
-
 extern int of_object_xid_set(of_object_t *obj, uint32_t xid);
 extern int of_object_xid_get(of_object_t *obj, uint32_t *xid);
 
@@ -135,8 +101,13 @@
 void of_object_parent_length_update(of_object_t *obj, int delta);
 
 struct of_object_s {
-    /* The control block for the underlying data buffer */
-    of_wire_object_t wire_object;
+    /** A pointer to the underlying buffer's management structure. */
+    of_wire_buffer_t *wbuf;
+
+    /** The start offset for this object relative to the start of the
+     * underlying buffer */
+    int obj_offset;
+
     /* The LOCI type enum value of the object */
     of_object_id_t object_id;
 
@@ -154,24 +125,6 @@
      */
     int length;
     of_version_t version;
-
-    /*
-     * Many objects have a length and/or type represented in the wire buffer
-     * These accessors get and set those value when present.  Treat as private.
-     */
-    of_wire_length_get_f wire_length_get;
-    of_wire_length_set_f wire_length_set;
-    of_wire_type_get_f wire_type_get;
-    of_wire_type_set_f wire_type_set;
-
-    of_object_track_info_t track_info;
-
-    /*
-     * Metadata available for applications.  Ensure 8-byte alignment, but
-     * that buffer is at least as large as requested.  This data is not used
-     * or inspected by LOCI.
-     */
-    uint64_t metadata[(OF_OBJECT_METADATA_BYTES + 7) / 8];
 };
 
 struct of_object_storage_s {
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index 0723454..dfec5c3 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -62,21 +62,6 @@
     of_buffer_free_f free;
 } of_wire_buffer_t;
 
-/**
- * Decouples object from underlying wire buffer
- *
- * Called a 'slice' in some places.
- */
-typedef struct of_wire_object_s {
-    /** A pointer to the underlying buffer's management structure. */
-    of_wire_buffer_t *wbuf;  
-    /** The start offset for this object relative to the start of the
-     * underlying buffer */
-    int obj_offset;
-    /* Boolean, whether the object owns the wire buffer. */
-    char owned;
-} of_wire_object_t;
-
 #define WBUF_BUF(wbuf) (wbuf)->buf
 #define WBUF_ALLOC_BYTES(wbuf) (wbuf)->alloc_bytes
 #define WBUF_CURRENT_BYTES(wbuf) (wbuf)->current_bytes
@@ -104,15 +89,6 @@
  */
 #define OF_WIRE_BUFFER_INDEX(wbuf, offset) (&((WBUF_BUF(wbuf))[offset]))
 
-/**
- * Return a pointer to a particular offset in the underlying buffer
- * associated with a wire object
- * @param wobj Pointer to an of_wire_object_t structure
- * @param offset The location to reference relative to the start of the object
- */
-#define OF_WIRE_OBJECT_INDEX(wobj, offset) \
-    OF_WIRE_BUFFER_INDEX((wobj)->wbuf, (offset) + (wobj)->obj_offset)
-
 /****************************************************************
  * Object specific macros; of_object_t includes a wire_object
  ****************************************************************/
@@ -124,7 +100,7 @@
  * @param offset The location to reference relative to the start of the object
  */
 #define OF_OBJECT_BUFFER_INDEX(obj, offset) \
-    OF_WIRE_OBJECT_INDEX(&((obj)->wire_object), offset)
+    OF_WIRE_BUFFER_INDEX((obj)->wbuf, (obj)->obj_offset + offset)
 
 /**
  * Return the absolute offset as an integer from a object-relative offset
@@ -132,7 +108,7 @@
  * @param offset The location to reference relative to the start of the object
  */
 #define OF_OBJECT_ABSOLUTE_OFFSET(obj, offset) \
-    ((obj)->wire_object.obj_offset + offset)
+    ((obj)->obj_offset + offset)
 
 
 /**
@@ -140,7 +116,7 @@
  *
  * Treat as private
  */
-#define OF_OBJECT_TO_WBUF(obj) ((obj)->wire_object.wbuf)
+#define OF_OBJECT_TO_WBUF(obj) ((obj)->wbuf)
 
 
 
@@ -174,7 +150,6 @@
         FREE(wbuf);
         return NULL;
     }
-    MEMSET(wbuf->buf, 0, a_bytes);
     wbuf->current_bytes = 0;
     wbuf->alloc_bytes = a_bytes;
 
@@ -245,6 +220,7 @@
     LOCI_ASSERT(wbuf != NULL);
     LOCI_ASSERT(wbuf->alloc_bytes >= bytes);
     if (bytes > wbuf->current_bytes) {
+        MEMSET(wbuf->buf + wbuf->current_bytes, 0, bytes - wbuf->current_bytes);
         wbuf->current_bytes = bytes;
     }
 }
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index ee452fc..7b745a6 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -41,7 +41,6 @@
 import loxi_globals
 
 invalid_type = "invalid_type"
-invalid_value = "0xeeee"  # Note, as a string
 
 ################################################################
 #
@@ -90,22 +89,10 @@
     }
 
 bsn_vport_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.2
-    of_g.VERSION_1_2:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.3
-    of_g.VERSION_1_3:dict(
-        q_in_q      = 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(),
     }
 
 oxm_types = {
@@ -393,18 +380,6 @@
         )
     }
 
-##
-# These are the objects whose length is specified by an external
-# reference, specifically another data member in the class.
-#
-#external_length_spec = {
-#    ("of_packet_out", "actions", OF_VERSION_1_0) : "actions_len",
-#    ("of_packet_out", "actions", OF_VERSION_1_1) : "actions_len",
-#    ("of_packet_out", "actions", OF_VERSION_1_2) : "actions_len",
-#    ("of_packet_out", "actions", OF_VERSION_1_3) : "actions_len"
-#}
-
-
 ################################################################
 #
 # type_val is the primary data structure that maps an
@@ -582,236 +557,3 @@
             }
         ),
 }
-
-# Set to empty dict if no extension instructions defined
-extension_instruction_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(
-        bsn = {   # of_instruction_bsn_
-            },
-        nicira = {   # of_instruction_nicira_
-            }
-        ),
-}
-
-# Set to empty dict if no extension instructions defined
-extension_queue_prop_subtype = {}
-
-# Set to empty dict if no extension instructions defined
-extension_table_feature_prop_subtype = {}
-
-extension_objects = [
-    extension_message_subtype,
-    extension_action_subtype,
-    extension_action_id_subtype,
-    extension_instruction_subtype,
-    extension_instruction_id_subtype,
-    extension_queue_prop_subtype,
-    extension_table_feature_prop_subtype
-]
-
-################################################################
-# These are extension type generic (for messages, actions...)
-################################################################
-
-def extension_to_experimenter_name(cls):
-    """
-    Return the name of the experimenter if class is an
-    extension, else None
-
-    This is brute force; we search all extension data for a match
-    """
-
-    for ext_obj in extension_objects:
-        for version, exp_list in ext_obj.items():
-            for exp_name, classes in exp_list.items():
-                if cls in classes:
-                    return exp_name
-    return None
-
-def extension_to_experimenter_id(cls):
-    """
-    Return the ID of the experimenter if class is an
-    extension, else None
-    """
-    exp_name = extension_to_experimenter_name(cls)
-    if exp_name:
-        return of_g.experimenter_name_to_id[exp_name]
-    return None
-
-def extension_to_experimenter_macro_name(cls):
-    """
-    Return the "macro name" of the ID of the experimenter if class is an
-    extension, else None
-    """
-    exp_name = extension_to_experimenter_name(cls)
-    if exp_name:
-        return "OF_EXPERIMENTER_ID_" + exp_name.upper()
-    return None
-
-def extension_to_subtype(cls, version):
-    """
-    Generic across all extension objects, return subtype identifier
-    """
-    for ext_obj in extension_objects:
-        for version, exp_list in ext_obj.items():
-            for exp_name, classes in exp_list.items():
-                if cls in classes:
-                    return classes[cls]
-
-def class_is_extension(cls, version):
-    """
-    Return True if class, version is recognized as an extension
-    of any type (message, action....)
-
-    Accepts of_g.OF_VERSION_ANY
-    """
-
-    for ext_obj in extension_objects:
-        if cls_is_ext_obj(cls, version, ext_obj):
-            return True
-
-    return False
-
-# Internal
-def cls_is_ext_obj(cls, version, ext_obj):
-    """
-    @brief Return True if cls in an extension of type ext_obj
-    @param cls The class to check
-    @param version The version to check
-    @param ext_obj The extension object dictionary (messages, actions...)
-
-    Accepts of_g.VERSION_ANY
-    """
-
-    # Call with each version if "any" is passed
-    if version == of_g.VERSION_ANY:
-        for v in of_g.of_version_range:
-            if cls_is_ext_obj(cls, v, ext_obj):
-                return True
-    else:   # Version specified
-        if version in ext_obj:
-            for exp, subtype_vals in ext_obj[version].items():
-                if cls in subtype_vals:
-                    return True
-
-    return False
-
-################################################################
-# These are extension message specific
-################################################################
-
-def message_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an  extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version, extension_message_subtype)
-
-def extension_message_to_subtype(cls, version):
-    """
-    Return the subtype of the experimenter message if the class is an
-    extension, else None
-    """
-    if version in extension_message_subtype:
-        for exp, classes in extension_message_subtype[version].items():
-            for ext_class, subtype in classes.items():
-                if cls == ext_class:
-                    return subtype
-    return None
-
-################################################################
-# These are extension action specific
-################################################################
-
-def action_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an action extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version, extension_action_subtype)
-
-def extension_action_to_subtype(cls, version):
-    """
-    Return the ID of the action subtype (for its experimenteer)
-    if class is an action extension, else None
-    """
-    if version in extension_action_subtype:
-        for exp, classes in extension_action_subtype[version].items():
-            if cls in classes:
-                return classes[cls]
-
-    return None
-
-################################################################
-# These are extension action specific
-################################################################
-
-def action_id_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an action ID extension
-    This is brute force, searching records for a match
-    """
-    if version not in [of_g.VERSION_1_3]: # Action IDs only 1.3
-        return False
-    return cls_is_ext_obj(cls, version, extension_action_id_subtype)
-
-def extension_action_id_to_subtype(cls, version):
-    """
-    Return the ID of the action ID subtype (for its experimenteer)
-    if class is an action ID extension, else None
-    """
-    if version in extension_action_id_subtype:
-        for exp, classes in extension_action_id_subtype[version].items():
-            if cls in classes:
-                return classes[cls]
-
-    return None
-
-################################################################
-# These are extension instruction specific
-################################################################
-
-def instruction_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an instruction extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version, extension_instruction_subtype)
-
-################################################################
-# These are extension instruction specific
-################################################################
-
-def instruction_id_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an instruction ID extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version, extension_instruction_id_subtype)
-
-################################################################
-# These are extension queue_prop specific
-################################################################
-
-def queue_prop_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an instruction extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version, extension_queue_prop_subtype)
-
-################################################################
-# These are extension table_feature_prop specific
-################################################################
-
-def table_feature_prop_is_extension(cls, version):
-    """
-    Return True if cls, version is recognized as an instruction extension
-    This is brute force, searching records for a match
-    """
-    return cls_is_ext_obj(cls, version,
-                          extension_table_feature_prop_subtype)
diff --git a/c_gen/util.py b/c_gen/util.py
index 54e0f80..58a4355 100644
--- a/c_gen/util.py
+++ b/c_gen/util.py
@@ -37,6 +37,3 @@
 
 def render_template(out, name, **context):
     template_utils.render_template(out, name, template_path, context)
-
-def render_static(out, name):
-    template_utils.render_static(out, name, template_path)
diff --git a/cmdline.py b/cmdline.py
index aafa019..6395fff 100644
--- a/cmdline.py
+++ b/cmdline.py
@@ -29,14 +29,6 @@
 
 from loxi_globals import OFVersions
 
-##
-# Command line options
-options = {}
-
-##
-# Command line arguments
-args = []
-
 ##@var config_default
 # The default configuration dictionary for LOXI code generation
 options_default = {
@@ -77,10 +69,6 @@
     @param cfg_dflt The default configuration dictionary
     @return A pair (options, args) as per parser return
     """
-    global options
-    global args
-    global target_version_list
-
     parser = OptionParser(version="%prog 0.1")
 
     #@todo Add options via dictionary
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index f55e7d3..452ac58 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -420,8 +420,8 @@
 meter_features = JType("OFMeterFeatures")\
         .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
             write="$name.writeTo(bb)")
-bsn_vport_q_in_q = JType("OFBsnVportQInQ")\
-        .op(read="OFBsnVportQInQVer$version.READER.readFrom(bb)",
+bsn_vport = JType("OFBsnVport")\
+        .op(read="OFBsnVportVer$version.READER.readFrom(bb)",
             write="$name.writeTo(bb)")
 flow_wildcards = JType("int") \
         .op(read='bb.readInt()',
@@ -537,7 +537,7 @@
         'of_meter_features_t': meter_features,
         'of_bitmap_128_t': port_bitmap,
         'of_checksum_128_t': checksum,
-        'of_bsn_vport_q_in_q_t': bsn_vport_q_in_q,
+        'of_bsn_vport_t': bsn_vport,
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
@@ -649,6 +649,7 @@
         'of_bsn_set_l2_table_request': { 'l2_table_enable': boolean },
         'of_bsn_set_l2_table_reply': { 'l2_table_enable': boolean },
         'of_bsn_set_pktin_suppression_request': { 'enabled': boolean },
+        'of_bsn_controller_connection': { 'auxiliary_id' : of_aux_id},
         'of_flow_stats_request': { 'out_group': of_group_default_any },
         'of_aggregate_stats_request': { 'out_group': of_group_default_any },
 
diff --git a/java_gen/pre-written/pom.xml b/java_gen/pre-written/pom.xml
index 4f0dc74..b4e81cc 100644
--- a/java_gen/pre-written/pom.xml
+++ b/java_gen/pre-written/pom.xml
@@ -179,7 +179,7 @@
                     <failOnNoGitDirectory>false</failOnNoGitDirectory>
 
                     <gitDescribe>
-                        <skip>false</skip>
+                        <skip>true</skip>
                         <always>true</always>
                         <abbrev>7</abbrev>
                         <dirty>-dirty</dirty>
@@ -211,10 +211,20 @@
                                     <projectName>${project.name}</projectName>
                                     <version>${project.version}</version>
                                     <vcsRevision>${git.commit.id.abbrev}</vcsRevision>
-                                    <vcsBranch>${git.branch}</vcsBranch>
-                                    <vcsDirty>${git.commit.id.describe}</vcsDirty>
+                                    <!-- note: git.branch does not work in jenkins, because jenkins
+                                         builds the system in 'detached head' state. Because we mostly
+                                         about jenkins builds, we instead use the environment variable
+                                         GIT_BRANCH set by jenkins here -->
+                                    <vcsBranch>${env.GIT_BRANCH}</vcsBranch>
                                     <buildUser>${user.name}</buildUser>
                                     <buildDate>${git.build.time}</buildDate>
+                                    <!-- continuous integration information from jenkins env variables:
+                                         https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-below -->
+                                    <ciBuildNumber>${env.BUILD_NUMBER}</ciBuildNumber>
+                                    <ciBuildId>${env.BUILD_ID}</ciBuildId>
+                                    <ciBuildTag>${env.BUILD_TAG}</ciBuildTag>
+                                   <ciJobName>${env.JOB_NAME}</ciJobName>
+i                                  <ciNodeName>${env.NODE_NAME}</ciNodeName>
                                 </manifestEntries>
                             </manifestSection>
                         </manifestSections>
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
index 2e675d4..ee605de 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
@@ -33,6 +33,8 @@
     }
 
     public static VlanVid ofVlan(int vid) {
+        if (vid == NO_MASK.vid)
+            return NO_MASK;
         if ((vid & VALIDATION_MASK) != vid)
             throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
         return new VlanVid((short) vid);
diff --git a/lang_c.py b/lang_c.py
index 0a881e9..1969a83 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -84,7 +84,6 @@
     'loci/src/of_object.c': static,
     'loci/src/of_utils.c': static,
     'loci/src/of_wire_buf.c': static,
-    'loci/src/loci_setup_from_add_fns.c': static,
 
     # Static LOCI documentation
     'loci/README': static,
@@ -107,7 +106,6 @@
     'locitest/src/test_ext.c': static,
     'locitest/src/test_list_limits.c': static,
     'locitest/src/test_match_utils.c': static,
-    'locitest/src/test_setup_from_add.c': static,
     'locitest/src/test_utils.c': static,
     'locitest/src/test_validator.c': static,
     'locitest/src/main.c': static,
@@ -131,3 +129,4 @@
     c_gen.codegen.generate_strings(install_dir)
     c_gen.codegen.generate_init_map(install_dir)
     c_gen.codegen.generate_type_maps(install_dir)
+    c_gen.codegen.generate_class_metadata(install_dir)
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index bc79ed9..7b96fe3 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -112,7 +112,6 @@
                     ofinput.wire_versions.add(int(decl_ast[2]))
                 else:
                     raise InputError("Unrecognized wire protocol version %r" % decl_ast[2])
-                found_wire_version = True
 
     if not ofinput.wire_versions:
         raise InputError("Missing #version metadata")
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index c8ca04d..0e95473 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -220,7 +220,7 @@
         else:
             raise Exception("Not a fixed length member: {}.{} [{}]".format(
                 self.of_class.name,
-                self.name if hasattr("self", name) else "(unnnamed)",
+                self.name if hasattr("self", "name") else "(unnnamed)",
                 type(self).__name__))
 
 """
diff --git a/loxi_ir/ir_offset.py b/loxi_ir/ir_offset.py
index 2e6d004..9c6a5c1 100644
--- a/loxi_ir/ir_offset.py
+++ b/loxi_ir/ir_offset.py
@@ -172,7 +172,6 @@
     """
     count, base_type = type_dec_to_count_base(fe_member.oftype)
 
-    len_update = 0
     if base_type in of_mixed_types:
         base_type = of_mixed_types[base_type][version.wire_version]
 
diff --git a/loxigen.py b/loxigen.py
index 700168a..fcb2788 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -132,7 +132,6 @@
     filenames = [x for x in filenames if not x.endswith('~')]
 
     # Read input files
-    all_ofinputs = []
     for filename in filenames:
         log("Processing struct file: " + filename)
         ofinput = process_input_file(filename)
@@ -167,20 +166,9 @@
     lang_file = "lang_%s" % options.lang
     lang_module = __import__(lang_file)
 
-    if hasattr(lang_module, "config_sanity_check") and not lang_module.config_sanity_check():
-        debug("Config sanity check failed\n")
-        sys.exit(1)
-
-    # If list files, just list auto-gen files to stdout and exit
-    if options.list_files:
-        for name in lang_module.targets:
-            print options.install_dir + '/' + name
-        sys.exit(0)
-
     log("\nGenerating files for target language %s\n" % options.lang)
 
     loxi_globals.OFVersions.target_versions = target_versions
     inputs = read_input()
     build_ir(inputs)
-    #log_all_class_info()
     lang_module.generate(options.install_dir)
diff --git a/openflow_input/bsn_pktin_flag b/openflow_input/bsn_pktin_flag
new file mode 100644
index 0000000..54c942f
--- /dev/null
+++ b/openflow_input/bsn_pktin_flag
@@ -0,0 +1,45 @@
+// 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.
+
+#version 4
+
+// 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,
+// so we use the metadata OXM to carry this information.
+
+enum ofp_bsn_pktin_flag(wire_type=uint64_t, bitmask=True) {
+    OFP_BSN_PKTIN_FLAG_PDU = 0x1,
+    OFP_BSN_PKTIN_FLAG_NEW_HOST = 0x2,
+    OFP_BSN_PKTIN_FLAG_STATION_MOVE = 0x4,
+    OFP_BSN_PKTIN_FLAG_ARP = 0x8,
+    OFP_BSN_PKTIN_FLAG_DHCP = 0x10,
+    OFP_BSN_PKTIN_FLAG_L2_CPU = 0x20,
+    OFP_BSN_PKTIN_FLAG_DEBUG = 0x40,
+    OFP_BSN_PKTIN_FLAG_TTL_EXPIRED = 0x80,
+    OFP_BSN_PKTIN_FLAG_L3_MISS = 0x100,
+    OFP_BSN_PKTIN_FLAG_L3_CPU = 0x200,
+};
diff --git a/openflow_input/bsn_vport b/openflow_input/bsn_vport
index 4eeda8c..82d9d33 100644
--- a/openflow_input/bsn_vport
+++ b/openflow_input/bsn_vport
@@ -42,6 +42,14 @@
     OF_BSN_VPORT_Q_IN_Q_UNTAGGED = 0xffff,
 };
 
+enum ofp_bsn_vport_l2gre_flags(wire_type=uint32_t, bitmask=True) {
+    OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID = 0x1,
+
+    /* DSCP flags are mutually exclusive */
+    OF_BSN_VPORT_L2GRE_DSCP_ASSIGN = 0x2,
+    OF_BSN_VPORT_L2GRE_DSCP_COPY = 0x4,
+};
+
 // BSN Virtual port object header
 // FIXME For now, inheritance is not exercised.  See below.
 struct of_bsn_vport {
@@ -55,7 +63,7 @@
 
 struct of_bsn_vport_q_in_q : of_bsn_vport {
     uint16_t type == 0;
-    uint16_t length;  /* 32 */
+    uint16_t length;
     uint32_t port_no;     /* OF port number of parent; usually phys port */
     uint16_t ingress_tpid;
     uint16_t ingress_vlan_id;
@@ -64,6 +72,26 @@
     of_port_name_t if_name;  /* Name to use in create operation */
 };
 
+
+// L2GRE tunnel virtual port specification
+
+struct of_bsn_vport_l2gre : of_bsn_vport {
+    uint16_t type == 1;
+    uint16_t length;
+    enum ofp_bsn_vport_l2gre_flags flags;
+    of_port_no_t port_no;       /* OF port number of parent */
+    of_mac_addr_t local_mac;    /* Local MAC */
+    of_mac_addr_t nh_mac;       /* Next Hop MAC */
+    of_ipv4_t src_ip;           /* Source IP */
+    of_ipv4_t dst_ip;           /* Destination IP */
+    uint8_t dscp;
+    uint8_t ttl;
+    pad(2);
+    uint32_t vpn;               /* VPN ID (for GRE Key) */
+    of_port_name_t if_name;     /* Virtual Interface Name */
+};
+
+
 // Request from controller to switch to create vport
 struct of_bsn_virtual_port_create_request : of_bsn_header {
     uint8_t version;
@@ -72,8 +100,7 @@
     uint32_t xid;
     uint32_t experimenter == 0x5c16c7;
     uint32_t subtype == 15;
-    // FIXME This should be an instance of the inheritance superclass
-    of_bsn_vport_q_in_q_t vport;   // Description of vport to create
+    of_bsn_vport_t vport;   // Description of vport to create
     // Additional data follows depending on header type
 };
 
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index 44b4814..9c32e7f 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -118,9 +118,6 @@
                          ofclasses=modules_by_version[version]['meter_band'],
                          version=version)
 
-def generate_pp(out, name, version):
-    util.render_template(out, 'pp.py')
-
 def generate_util(out, name, version):
     util.render_template(out, 'util.py', version=version)
 
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index ddde14a..7bd242e 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -142,7 +142,7 @@
     'of_match_t': 'common.match',
     'of_port_desc_t': 'common.port_desc',
     'of_meter_features_t': 'common.meter_features',
-    'of_bsn_vport_q_in_q_t': 'common.bsn_vport_q_in_q',
+    'of_bsn_vport_t': 'common.bsn_vport',
 }
 
 for (cls, pyclass) in embedded_structs.items():
diff --git a/py_gen/tests/generic_util.py b/py_gen/tests/generic_util.py
index 8b2f59f..03885a2 100644
--- a/py_gen/tests/generic_util.py
+++ b/py_gen/tests/generic_util.py
@@ -44,12 +44,6 @@
         self.assertEquals(['\x04abc', '\x03de', '\x02f', '\x01'], a)
 
 class TestOFReader(unittest.TestCase):
-    def test_empty(self):
-        reader = OFReader("")
-        self.assertEquals(str(reader.read('')), "")
-        with self.assertRaisesRegexp(loxi.ProtocolError, "Buffer too short"):
-            reader.read_buf(1)
-
     def test_simple(self):
         reader = OFReader("abcdefg")
         self.assertEquals(reader.read('2s')[0], "ab")
diff --git a/py_gen/util.py b/py_gen/util.py
index 2a0dc54..0d8c43f 100644
--- a/py_gen/util.py
+++ b/py_gen/util.py
@@ -41,18 +41,3 @@
 
 def render_static(out, name):
     template_utils.render_static(out, name, [templates_dir])
-
-def constant_for_value(version, group, value):
-    enums = loxi_globals.ir[version].enums
-    enum = [x for x in enums if x.name == group][0]
-    for name, value2 in enum.values:
-        if value == value2:
-            return "const." + name
-    return repr(value)
-
-def ancestors(ofclass):
-    r = []
-    while ofclass:
-        r.append(ofclass)
-        ofclass = ofclass.superclass
-    return r
diff --git a/test_data/of13/bsn_virtual_port_create_request__l2gre.data b/test_data/of13/bsn_virtual_port_create_request__l2gre.data
new file mode 100644
index 0000000..b5fd5fa
--- /dev/null
+++ b/test_data/of13/bsn_virtual_port_create_request__l2gre.data
@@ -0,0 +1,77 @@
+-- binary
+04 04               # version, type
+00 48               # len
+01 02 03 04         # xid
+00 5c 16 c7         # experimenter
+00 00 00 0f         # subtype
+00 01               # vport type
+00 38               # vport len
+00 00 00 03         # vport flags
+00 00 00 01         # vport port no
+0a 0b 0c 0d 0e 0f   # local mac
+01 02 03 04 05 06   # next hop mac
+c0 00 00 02         # src ip
+c0 00 10 02         # dst ip
+01 40 00 00         # dscp, ttl, pad(2)
+00 00 be ef         # vpn
+66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 # vport if name
+-- python
+ofp.message.bsn_virtual_port_create_request(
+xid=0x01020304, vport=ofp.bsn_vport_l2gre(
+flags=ofp.OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID | ofp.OF_BSN_VPORT_L2GRE_DSCP_ASSIGN,
+port_no=1,
+local_mac=[0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f],
+nh_mac=[0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
+src_ip=0xc0000002,
+dst_ip=0xc0001002,
+dscp=1,
+ttl=64,
+vpn=0xbeef,
+if_name="foo"
+))
+-- c
+obj = of_bsn_virtual_port_create_request_new(OF_VERSION_1_3);
+of_bsn_virtual_port_create_request_xid_set(obj, 0x01020304);
+{
+    of_object_t *vport = of_bsn_vport_l2gre_new(OF_VERSION_1_3);
+    {
+        of_port_name_t if_name = "foo";
+        of_mac_addr_t local_mac = { { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } };
+        of_mac_addr_t nh_mac = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } };
+        of_bsn_vport_l2gre_flags_set(vport,
+            OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID |
+            OF_BSN_VPORT_L2GRE_DSCP_ASSIGN);
+        of_bsn_vport_l2gre_port_no_set(vport, 1);
+        of_bsn_vport_l2gre_local_mac_set(vport, local_mac);
+        of_bsn_vport_l2gre_nh_mac_set(vport, nh_mac);
+        of_bsn_vport_l2gre_src_ip_set(vport, 0xc0000002);
+        of_bsn_vport_l2gre_dst_ip_set(vport, 0xc0001002);
+        of_bsn_vport_l2gre_dscp_set(vport, 1);
+        of_bsn_vport_l2gre_ttl_set(vport, 64);
+        of_bsn_vport_l2gre_vpn_set(vport, 0xbeef);
+        of_bsn_vport_l2gre_if_name_set(vport, if_name);
+    }
+    of_bsn_virtual_port_create_request_vport_set(obj, vport);
+    of_object_delete(vport);
+}
+-- java
+builder.setXid(0x01020304)
+    .setVport(
+        factory.buildBsnVportL2Gre()
+            .setFlags(
+                ImmutableSet.<OFBsnVportL2GreFlags>of(
+                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID,
+                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_DSCP_ASSIGN
+                )
+            )
+            .setPortNo(OFPort.of(1))
+            .setLocalMac(MacAddress.of("0a:0b:0c:0d:0e:0f"))
+            .setNhMac(MacAddress.of("01:02:03:04:05:06"))
+            .setSrcIp(IPv4Address.of("192.0.0.2"))
+            .setDstIp(IPv4Address.of("192.0.16.2"))
+            .setDscp((short)1)
+            .setTtl((short)64)
+            .setVpn(0xbeef)
+            .setIfName("foo")
+            .build()
+    );
diff --git a/test_data/of13/bsn_virtual_port_create_request__q_in_q.data b/test_data/of13/bsn_virtual_port_create_request__q_in_q.data
new file mode 100644
index 0000000..ca53fbe
--- /dev/null
+++ b/test_data/of13/bsn_virtual_port_create_request__q_in_q.data
@@ -0,0 +1,53 @@
+-- binary
+04 04           # version, type
+00 30           # len
+01 02 03 04     # xid
+00 5c 16 c7     # experimenter
+00 00 00 0f     # subtype
+00 00           # vport type
+00 20           # vport len
+00 00 00 01     # vport port no
+00 02           # vport ingress tpid
+00 03           # vport ingress vlan id
+00 04           # vport egress tpid
+00 05           # vport egress vlan id
+66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 # vport if name
+-- python
+ofp.message.bsn_virtual_port_create_request(
+xid=0x01020304, vport=ofp.bsn_vport_q_in_q(
+port_no=1,
+ingress_tpid=2,
+ingress_vlan_id=3,
+egress_tpid=4,
+egress_vlan_id=5,
+if_name="foo"
+))
+-- c
+obj = of_bsn_virtual_port_create_request_new(OF_VERSION_1_3);
+of_bsn_virtual_port_create_request_xid_set(obj, 0x01020304);
+{
+    of_object_t *vport = of_bsn_vport_q_in_q_new(OF_VERSION_1_3);
+    {
+        of_port_name_t if_name = "foo";
+        of_bsn_vport_q_in_q_port_no_set(vport, 1);
+        of_bsn_vport_q_in_q_ingress_tpid_set(vport, 2);
+        of_bsn_vport_q_in_q_ingress_vlan_id_set(vport, 3);
+        of_bsn_vport_q_in_q_egress_tpid_set(vport, 4);
+        of_bsn_vport_q_in_q_egress_vlan_id_set(vport, 5);
+        of_bsn_vport_q_in_q_if_name_set(vport, if_name);
+    }
+    of_bsn_virtual_port_create_request_vport_set(obj, vport);
+    of_object_delete(vport);
+}
+-- java
+builder.setXid(0x01020304)
+    .setVport(
+        factory.buildBsnVportQInQ()
+            .setPortNo(1)
+            .setIngressTpid(2)
+            .setIngressVlanId(3)
+            .setEgressTpid(4)
+            .setEgressVlanId(5)
+            .setIfName("foo")
+            .build()
+    );