Merge remote-tracking branch 'origin/master' into loci-split

Conflicts:
	c_gen/codegen.py
diff --git a/Makefile b/Makefile
index fc9c6e4..80b81eb 100644
--- a/Makefile
+++ b/Makefile
@@ -132,7 +132,7 @@
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of13.py
 
 check-c: c
-	make -C ${LOXI_OUTPUT_DIR}/locitest
+	make -j4 -C ${LOXI_OUTPUT_DIR}/locitest
 	${LOXI_OUTPUT_DIR}/locitest/locitest
 
 pylint:
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 640687f..3621507 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -36,7 +36,6 @@
 from generic_utils import *
 from c_gen import flags, type_maps, c_type_maps
 import c_gen.loxi_utils_legacy as loxi_utils
-from c_gen.loxi_utils_legacy import config_check
 import loxi_globals
 
 import c_gen.identifiers as identifiers
@@ -64,18 +63,6 @@
     """
     return loxi_utils.enum_name(cls)
 
-def member_returns_val(cls, m_name):
-    """
-    Should get accessor return a value rather than void
-    @param cls The class name
-    @param m_name The member name
-    @return True if of_g config and the specific member allow a
-    return value.  Otherwise False
-    """
-    m_type = of_g.unified[cls]["union"][m_name]["m_type"]
-    return (config_check("get_returns") =="value" and
-            m_type in of_g.of_scalar_types)
-
 # TODO serialize match outside accessor?
 def accessor_return_type(a_type, m_type):
     if loxi_utils.accessor_returns_error(a_type, m_type):
@@ -430,27 +417,44 @@
 
     # gen_base_types(out)
 
-    gen_struct_typedefs(out)
-    gen_acc_pointer_typedefs(out)
-    gen_new_function_declarations(out)
-    if config_check("gen_unified_fns"):
-        gen_accessor_declarations(out)
-
-    gen_common_struct_definitions(out)
     gen_flow_add_setup_function_declarations(out)
-    if config_check("gen_fn_ptrs"): # Otherwise, all classes are from generic cls
-        gen_struct_definitions(out)
-    gen_generic_union(out)
-    gen_generics(out)
-    gen_top_static_functions(out)
     out.write("""
 /****************************************************************
  *
  * Declarations of maps between on-the-wire type values and LOCI identifiers
  *
  ****************************************************************/
+
+/**
+ * Generic experimenter type value.  Applies to all except
+ * top level message: Action, instruction, error, stats, queue_props, oxm
+ */
+#define OF_EXPERIMENTER_TYPE 0xffff
+
+int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
+int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
+
+of_object_id_t of_action_to_object_id(int action, of_version_t version);
+of_object_id_t of_action_id_to_object_id(int action_id, of_version_t version);
+of_object_id_t of_instruction_to_object_id(int instruction, of_version_t version);
+of_object_id_t of_queue_prop_to_object_id(int queue_prop, of_version_t version);
+of_object_id_t of_table_feature_prop_to_object_id(int table_feature_prop, of_version_t version);
+of_object_id_t of_meter_band_to_object_id(int meter_band, of_version_t version);
+of_object_id_t of_hello_elem_to_object_id(int hello_elem, of_version_t version);
+of_object_id_t of_stats_reply_to_object_id(int stats_reply, of_version_t version);
+of_object_id_t of_stats_request_to_object_id(int stats_request, of_version_t version);
+of_object_id_t of_error_msg_to_object_id(uint16_t error_msg, of_version_t version);
+of_object_id_t of_flow_mod_to_object_id(int flow_mod, of_version_t version);
+of_object_id_t of_group_mod_to_object_id(int group_mod, of_version_t version);
+of_object_id_t of_oxm_to_object_id(uint32_t type_len, of_version_t version);
+of_object_id_t of_message_experimenter_to_object_id(of_message_t msg, of_version_t version);
+of_object_id_t of_message_to_object_id(of_message_t msg, int length);
+
+int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
+
+extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];
+extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];
 """)
-    c_type_maps.gen_type_maps_header(out)
     c_type_maps.gen_type_data_header(out)
     c_match.gen_declarations(out)
     # @fixme Move debug stuff to own fn
@@ -485,325 +489,6 @@
     c_match.gen_serialize(out)
     c_match.gen_deserialize(out)
 
-def gen_len_offset_macros(out):
-    """
-    Special case length and offset calculations put directly into
-    loci.c as they are private.
-    """
-
-    out.write("""
-/****************************************************************
- * Special case macros for calculating variable lengths and offsets
- ****************************************************************/
-
-/**
- * Get a u16 directly from an offset in an object's wire buffer
- * @param obj An of_object_t object
- * @param offset Base offset of the uint16 relative to the object
- *
- */
-
-static inline int
-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);
-
-    return (int)val16;
-}
-
-/**
- * Set a u16 directly at an offset in an object's wire buffer
- * @param obj An of_object_t object
- * @param offset Base offset of the uint16 relative to the object
- * @param val The value to store
- *
- */
-
-static inline void
-of_object_u16_set(of_object_t *obj, int offset, int value) {
-    uint16_t val16;
-
-    val16 = (uint16_t)value;
-    of_wire_buffer_u16_set(obj->wire_object.wbuf,
-        obj->wire_object.obj_offset + offset, val16);
-}
-
-/**
- * Get length of an object with a TLV header with uint16_t
- * @param obj An object with a match member
- * @param offset The wire offset of the start of the object
- *
- * The length field follows the type field.
- */
-
-#define _TLV16_LEN(obj, offset) \\
-    (of_object_u16_get((of_object_t *)(obj), (offset) + 2))
-
-/**
- * Get length of an object that is the "rest" of the object
- * @param obj An object with a match member
- * @param offset The wire offset of the start of the object
- *
- */
-
-#define _END_LEN(obj, offset) ((obj)->length - (offset))
-
-/**
- * Offset of the action_len member in a packet-out object
- */
-
-#define _PACKET_OUT_ACTION_LEN_OFFSET(obj) \\
-    (((obj)->version == OF_VERSION_1_0) ? 14 : 16)
-
-/**
- * Get length of the action list object in a packet_out object
- * @param obj An object of type of_packet_out
- */
-
-#define _PACKET_OUT_ACTION_LEN(obj) \\
-    (of_object_u16_get((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj)))
-
-/**
- * Set length of the action list object in a packet_out object
- * @param obj An object of type of_packet_out
- */
-
-#define _PACKET_OUT_ACTION_LEN_SET(obj, len) \\
-    (of_object_u16_set((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj), len))
-
-/*
- * Match structs in 1.2 come at the end of the fixed length part
- * of structures.  They add 8 bytes to the minimal length of the
- * message, but are also variable length.  This means that the
- * type/length offsets are 8 bytes back from the end of the fixed
- * length part of the object.  The right way to handle this is to
- * expose the offset of the match member more explicitly.  For now,
- * we make the calculation as described here.
- */
-
-/* 1.2 min length of match is 8 bytes */
-#define _MATCH_MIN_LENGTH_V3 8
-
-/**
- * The offset of a 1.2 match object relative to fixed length of obj
- */
-#define _MATCH_OFFSET_V3(fixed_obj_len) \\
-    ((fixed_obj_len) - _MATCH_MIN_LENGTH_V3)
-
-/**
- * The "extra" length beyond the minimal 8 bytes of a match struct
- * in an object
- */
-#define _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len) \\
-    (OF_MATCH_BYTES(_TLV16_LEN(obj, _MATCH_OFFSET_V3(fixed_obj_len))) - \\
-     _MATCH_MIN_LENGTH_V3)
-
-/**
- * The offset of an object following a match object for 1.2
- */
-#define _OFFSET_FOLLOWING_MATCH_V3(obj, fixed_obj_len) \\
-    ((fixed_obj_len) + _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len))
-
-/**
- * Get length of a match object from its wire representation
- * @param obj An object with a match member
- * @param match_offset The wire offset of the match object.
- *
- * See above; for 1.2,
- * The match length is raw bytes but the actual space it takes
- * up is padded for alignment to 64-bits
- */
-#define _WIRE_MATCH_LEN(obj, match_offset) \\
-    (((obj)->version == OF_VERSION_1_0) ? %(match1)d : \\
-     (((obj)->version == OF_VERSION_1_1) ? %(match2)d : \\
-      _TLV16_LEN(obj, match_offset)))
-
-#define _WIRE_LEN_MIN 4
-
-/*
- * Wrapper function for match len.  There are cases where the wire buffer
- * has not been set with the proper minimum length.  In this case, the
- * wire match len is interpretted as its minimum length, 4 bytes.
- */
-
-static inline int
-wire_match_len(of_object_t *obj, int match_offset) {
-    int len;
-
-    len = _WIRE_MATCH_LEN(obj, match_offset);
-
-    return (len == 0) ? _WIRE_LEN_MIN : len;
-}
-
-#define _WIRE_MATCH_PADDED_LEN(obj, match_offset) \\
-    OF_MATCH_BYTES(wire_match_len((of_object_t *)(obj), (match_offset)))
-
-/**
- * Macro to calculate variable offset of instructions member in flow mod
- * @param obj An object of some type of flow modify/add/delete
- *
- * Get length of preceding match object and add to fixed length
- * Applies only to version 1.2
- */
-
-#define _FLOW_MOD_INSTRUCTIONS_OFFSET(obj) \\
-    _OFFSET_FOLLOWING_MATCH_V3(obj, %(flow_mod)d)
-
-/* The different flavors of flow mod all use the above */
-#define _FLOW_ADD_INSTRUCTIONS_OFFSET(obj) \\
-    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
-#define _FLOW_MODIFY_INSTRUCTIONS_OFFSET(obj) \\
-    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
-#define _FLOW_MODIFY_STRICT_INSTRUCTIONS_OFFSET(obj) \\
-    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
-#define _FLOW_DELETE_INSTRUCTIONS_OFFSET(obj) \\
-    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
-#define _FLOW_DELETE_STRICT_INSTRUCTIONS_OFFSET(obj) \\
-    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
-
-/**
- * Macro to calculate variable offset of instructions member in flow stats
- * @param obj An object of type of_flow_mod_t
- *
- * Get length of preceding match object and add to fixed length
- * Applies only to version 1.2 and 1.3
- */
-
-#define _FLOW_STATS_ENTRY_INSTRUCTIONS_OFFSET(obj) \\
-    _OFFSET_FOLLOWING_MATCH_V3(obj, %(flow_stats)d)
-
-/**
- * Macro to calculate variable offset of data (packet) member in packet_in
- * @param obj An object of type of_packet_in_t
- *
- * Get length of preceding match object and add to fixed length
- * Applies only to version 1.2 and 1.3
- * The +2 comes from the 2 bytes of padding between the match and packet data.
- */
-
-#define _PACKET_IN_DATA_OFFSET(obj) \\
-    (_OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
-%(packet_in)d : %(packet_in_1_3)d) + 2)
-
-/**
- * Macro to calculate variable offset of data (packet) member in packet_out
- * @param obj An object of type of_packet_out_t
- *
- * Find the length in the actions_len variable and add to the fixed len
- * Applies only to version 1.2 and 1.3
- */
-
-#define _PACKET_OUT_DATA_OFFSET(obj) (_PACKET_OUT_ACTION_LEN(obj) + \\
-     of_object_fixed_len[(obj)->version][OF_PACKET_OUT])
-
-/**
- * Macro to map port numbers that changed across versions
- * @param port The port_no_t variable holding the value
- * @param ver The OpenFlow version from which the value was extracted
- */
-#define OF_PORT_NO_VALUE_CHECK(port, ver) \\
-    if (((ver) == OF_VERSION_1_0) && ((port) > 0xff00)) (port) += 0xffff0000
-
-""" % dict(flow_mod=of_g.base_length[("of_flow_modify",of_g.VERSION_1_2)],
-           packet_in=of_g.base_length[("of_packet_in",of_g.VERSION_1_2)],
-           packet_in_1_3=of_g.base_length[("of_packet_in",of_g.VERSION_1_3)],
-           flow_stats=of_g.base_length[("of_flow_stats_entry",
-                                        of_g.VERSION_1_2)],
-           match1=of_g.base_length[("of_match_v1",of_g.VERSION_1_0)],
-           match2=of_g.base_length[("of_match_v2",of_g.VERSION_1_1)]))
-
-def gen_obj_id_macros(out):
-    """
-    Flow modify (add, delete) messages (and maybe others) use ID checks allowing
-    inheritance to use common accessor functions.
-    """
-    out.write("""
-/**
- * Macro to detect if an object ID falls in the "flow mod" family of objects
- * This includes add, modify, modify_strict, delete and delete_strict
- */
-#define IS_FLOW_MOD_SUBTYPE(object_id)                 \\
-    (((object_id) == OF_FLOW_MODIFY) ||                \\
-     ((object_id) == OF_FLOW_MODIFY_STRICT) ||         \\
-     ((object_id) == OF_FLOW_DELETE) ||                \\
-     ((object_id) == OF_FLOW_DELETE_STRICT) ||         \\
-     ((object_id) == OF_FLOW_ADD))
-""")
-
-
-def top_c_gen(out, name):
-    """
-    Generate code for
-    @param out The file handle to write to
-    @param name The name of the file
-    """
-    common_top_matter(out, name)
-    # Generic C code that needs to go into loci.c can go here.
-    out.write("""
-/****************************************************************
- *
- * This file is divided into the following sections.
- *
- * Instantiate strings such as object names
- * Special case macros for low level object access
- * Per-class, per-member accessor definitions
- * Per-class new/init function definitions
- * Per-class new/init pointer instantiations
- * Instantiate "set map" for pointer set fns
- *
- ****************************************************************/
-
-#ifdef __GNUC__
-#ifdef __linux__
-/* glibc */
-#include <features.h>
-#else
-/* NetBSD etc */
-#include <sys/cdefs.h>
-#ifdef __GNUC_PREREQ__
-#define __GNUC_PREREQ __GNUC_PREREQ__
-#endif
-#endif
-
-#ifndef __GNUC_PREREQ
-/* fallback */
-#define __GNUC_PREREQ(maj, min) 0
-#endif
-
-#if __GNUC_PREREQ(4,4)
-#pragma GCC optimize ("s")
-#endif
-
-#if __GNUC_PREREQ(4,6)
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#endif
-
-#endif
-
-#include <loci/loci.h>
-#include <loci/of_object.h>
-#include "loci_log.h"
-#include "loci_push_wire_types.h"
-
-""")
-    gen_object_enum_str(out)
-    gen_len_offset_macros(out)
-    gen_obj_id_macros(out)
-    if config_check("gen_unified_fns"):
-        gen_accessor_definitions(out)
-    gen_new_function_definitions(out)
-    gen_init_map(out)
-    out.write("\n/* This code should be broken out to a different file */\n")
-    gen_setup_from_add_fns(out)
-
-def type_data_c_gen(out, name):
-    common_top_matter(out, name)
-    c_type_maps.gen_type_maps(out)
-    c_type_maps.gen_length_array(out)
-    c_type_maps.gen_extra_length_array(out)
-
 ################################################################
 # Top Matter
 ################################################################
@@ -1102,7 +787,7 @@
 #include <loci/of_message.h>
 #include <loci/of_match.h>
 #include <loci/of_object.h>
-#include <loci/of_wire_buf.h>
+#include <loci/loci_classes.h>
 
 /****************************************************************
  *
@@ -1122,51 +807,6 @@
  ****************************************************************/
 """)
 
-def gen_top_static_functions(out):
-    out.write("""
-
-#define _MAX_PARENT_ITERATIONS 4
-/**
- * Iteratively update parent lengths thru hierarchy
- * @param obj The object whose length is being updated
- * @param delta The difference between the current and new lengths
- *
- * Note that this includes updating the object itself.  It will
- * iterate thru parents.
- *
- * Assumes delta > 0.
- */
-static inline void
-of_object_parent_length_update(of_object_t *obj, int delta)
-{
-#ifndef NDEBUG
-    int count = 0;
-    of_wire_buffer_t *wbuf;  /* For debug asserts only */
-#endif
-
-    while (obj != NULL) {
-        ASSERT(count++ < _MAX_PARENT_ITERATIONS);
-        obj->length += delta;
-        if (obj->wire_length_set != NULL) {
-            obj->wire_length_set(obj, obj->length);
-        }
-#ifndef NDEBUG
-        wbuf = obj->wire_object.wbuf;
-#endif
-
-        /* Asserts for wire length checking */
-        ASSERT(obj->length + obj->wire_object.obj_offset <=
-               WBUF_CURRENT_BYTES(wbuf));
-        if (obj->parent == NULL) {
-            ASSERT(obj->length + obj->wire_object.obj_offset ==
-                   WBUF_CURRENT_BYTES(wbuf));
-        }
-
-        obj = obj->parent;
-    }
-}
-""")
-
 ################################################################
 #
 ################################################################
@@ -1323,63 +963,6 @@
 }
 """)
 
-def gen_object_enum_str(out):
-    out.write("\nconst char *const of_object_id_str[] = {\n")
-    out.write("    \"of_object\",\n")
-    for cls in of_g.ordered_messages:
-        out.write("    \"%s\",\n" % cls)
-    out.write("\n    /* Non-message objects */\n")
-    for cls in of_g.ordered_non_messages:
-        out.write("    \"%s\",\n" % cls)
-    out.write("\n    /* List objects */\n")
-    for cls in of_g.ordered_list_objects:
-        out.write("    \"%s\",\n" % cls)
-    out.write("\n    /* Generic stats request/reply types; pseudo objects */\n")
-    for cls in of_g.ordered_pseudo_objects:
-        out.write("    \"%s\",\n" % cls)
-    out.write("\n    \"of_unknown_object\"\n};\n")
-
-    # We'll do version strings while we're at it
-    out.write("""
- const char *const of_version_str[] = {
-    "Unknown OpenFlow Version",
-    "OpenFlow-1.0",
-    "OpenFlow-1.1",
-    "OpenFlow-1.2"
-};
-
-const of_mac_addr_t of_mac_addr_all_ones = {
-    {
-        0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-    }
-};
-/* Just to be explicit; static duration vars are init'd to 0 */
-const of_mac_addr_t of_mac_addr_all_zeros = {
-    {
-        0, 0, 0, 0, 0, 0
-    }
-};
-
-const of_ipv6_t of_ipv6_all_ones = {
-    {
-        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-    }
-};
-/* Just to be explicit; static duration vars are init'd to 0 */
-const of_ipv6_t of_ipv6_all_zeros = {
-    {
-        0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0
-    }
-};
-
-/** @var of_error_strings
- * The error string map; use abs value to index
- */
-const char *const of_error_strings[] = { OF_ERROR_STRINGS };
-""")
-
 ################################################################
 #
 # Internal Utility Functions
@@ -1411,8 +994,6 @@
     member = of_g.unified[cls]["union"][m_name]
     m_type = member["m_type"]
     rv = "int"
-    if member_returns_val(cls, m_name):
-        rv = m_type
     if m_type[-2:] == "_t":
         m_type = m_type[:-2]
 
@@ -1548,11 +1129,8 @@
     for cls in of_g.standard_class_order:
         if cls in type_maps.inheritance_map:
             continue
-        if config_check("gen_fn_ptrs"):
-            out.write("typedef struct %(cls)s_s %(cls)s_t;\n" % dict(cls=cls))
-        else:
-            template = "typedef of_object_t %(cls)s_t;\n"
-            out.write(template % dict(cls=cls))
+        template = "typedef of_object_t %(cls)s_t;\n"
+        out.write(template % dict(cls=cls))
 
     out.write("""
 /****************************************************************
@@ -1567,47 +1145,6 @@
 
 """)
 
-def gen_generic_union(out):
-    """
-    Generate the generic union object composing all LOCI objects
-
-    @param out The file to which to write the decs
-    """
-    out.write("""
-/**
- * The common LOCI object is a union of all possible objects.
- */
-union of_generic_u {
-    of_object_t object;  /* Common base class with fundamental accessors */
-
-    /* Message objects */
-""")
-    for cls in of_g.ordered_messages:
-        out.write("    %s_t %s;\n" % (cls, cls))
-    out.write("\n    /* Non-message composite objects */\n")
-    for cls in of_g.ordered_non_messages:
-        if cls in type_maps.inheritance_map:
-            continue
-        out.write("    %s_t %s;\n" % (cls, cls))
-    out.write("\n    /* List objects */\n")
-    for cls in of_g.ordered_list_objects:
-        out.write("    %s_t %s;\n" % (cls, cls))
-    out.write("};\n")
-
-def gen_common_struct_definitions(out):
-    out.write("""
-/****************************************************************
- *
- * Unified structure definitions
- *
- ****************************************************************/
-
-struct of_object_s {
-    /* Common members */
-%(common)s
-};
-""" % dict(common=of_g.base_object_members))
-
 def gen_flow_add_setup_function_declarations(out):
     """
     Add the declarations for functions that can be initialized
@@ -1688,51 +1225,6 @@
                                         of_object_t *effects);
 """)
 
-def gen_struct_definitions(out):
-    """
-    Generate the declaration of all of_ C structures
-
-    @param out The file to which to write the decs
-    """
-
-    # This should only get called if gen_fn_ptr is true in code_gen_config
-    if not config_check("gen_fn_ptrs"):
-        debug("Error: gen_struct_defs called, but no fn ptrs set")
-        return
-
-    for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            continue # These are generated elsewhere
-        note = ""
-        if loxi_utils.class_is_message(cls):
-            note = " /* Class is message */"
-        out.write("struct %s_s {%s\n" % (cls, note))
-        out.write("""    /* Common members */
-%s
-    /* Class specific members */
-""" % of_g.base_object_members)
-        if loxi_utils.class_is_list(cls):
-            out.write("""
-    %(cls)s_first_f first;
-    %(cls)s_next_f next;
-    %(cls)s_append_bind_f append_bind;
-    %(cls)s_append_f append;
-};
-
-""" % {"cls": cls})
-            continue   # All done with list object
-
-        # Else, not a list instance; add accessors for all data members
-        for m_name in of_g.ordered_members[cls]:
-            if m_name in of_g.skip_members:
-                # These members (length, etc) are handled internally
-                continue
-            f_name = acc_name(cls, m_name)
-            out.write("    %s_get_f %s;\n" % (f_name, m_name + "_get"))
-            out.write("    %s_set_f %s;\n" % (f_name, m_name + "_set"))
-        out.write("};\n\n")
-
-
 ################################################################
 #
 # List accessor code generation
@@ -2409,28 +1901,7 @@
     out.write("%s\n%s_%s_get(\n    %s)\n" % (ret_type, cls, m_name, params))
     gen_unified_acc_body(out, cls, m_name, ver_type_map, "get", m_type)
 
-def gen_accessor_definitions(out):
-    """
-    Generate the body of each version independent accessor
-
-    @param out The file to which to write the decs
-    """
-
-    out.write("""
-/****************************************************************
- *
- * Unified accessor function definitions
- *
- ****************************************************************/
-""")
-    for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            continue
-        out.write("\n/* Unified accessor functions for %s */\n" % cls)
-        if loxi_utils.class_is_list(cls):
-            gen_list_accessors(out, cls)
-            continue
-        out.write("/** \\ingroup %s \n * @{ */\n" % cls)
+def gen_accessor_definitions(out, cls):
         for m_name in of_g.ordered_members[cls]:
             if m_name in of_g.skip_members:
                 continue
@@ -2471,96 +1942,6 @@
             out.write("%s\n%s_%s_set(\n    %s)\n" % (ret_type, cls, m_name, params))
             gen_unified_acc_body(out, cls, m_name, ver_type_map, "set", m_type)
 
-        out.write("\n/** @} */\n")
-
-def gen_acc_pointer_typedefs(out):
-    """
-    Generate the function pointer typedefs for in-struct accessors
-    @param out The file to which to write the typedefs
-    """
-
-    out.write("""
-/****************************************************************
- *
- * Accessor function pointer typedefs
- *
- ****************************************************************/
-
-/*
- * 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);
-""")
-    # If not using function pointers in classes, don't gen typedefs below
-    if not config_check("gen_fn_ptrs"):
-        return
-
-    # For each class, for each type it uses, generate a typedef
-    for cls in of_g.standard_class_order:
-        if cls in type_maps.inheritance_map:
-            continue
-        out.write("\n/* Accessor function pointer typedefs for %s */\n" % cls)
-        types_done = list()
-        for m_name in of_g.ordered_members[cls]:
-            (m_type, get_rv) = get_acc_rv(cls, m_name)
-            if (m_type, get_rv) in types_done:
-                continue
-            types_done.append((m_type, get_rv))
-            fn = "%s_%s" % (cls, m_type)
-            params = ", ".join(param_list(cls, m_name, "get"))
-            out.write("typedef int (*%s_get_f)(\n    %s);\n" %
-                      (fn, params))
-
-            params = ", ".join(param_list(cls, m_name, "set"))
-            out.write("typedef int (*%s_set_f)(\n    %s);\n" %
-                      (fn, params))
-        if loxi_utils.class_is_list(cls):
-            obj_type = loxi_utils.list_to_entry_type(cls)
-            out.write("""typedef int (*%(cls)s_first_f)(
-    %(cls)s_t *list,
-    %(obj_type)s_t *obj);
-typedef int (*%(cls)s_next_f)(
-    %(cls)s_t *list,
-    %(obj_type)s_t *obj);
-typedef int (*%(cls)s_append_bind_f)(
-    %(cls)s_t *list,
-    %(obj_type)s_t *obj);
-typedef int (*%(cls)s_append_f)(
-    %(cls)s_t *list,
-    %(obj_type)s_t *obj);
-""" % {"cls":cls, "obj_type":obj_type})
-
-#             out.write("""
-# typedef int (*%(cls)s_get_f)(
-#     %(cls)s_t *list,
-#     %(obj_type)s_t *obj, int index);
-# typedef int (*%(cls)s_set_f)(
-#     %(cls)s_t *list,
-#     %(obj_type)s_t *obj, int index);
-# typedef int (*%(cls)s_append_f)(
-#     %(cls)s_t *list,
-#     %(obj_type)s_t *obj, int index);
-# typedef int (*%(cls)s_insert_f)(
-#     %(cls)s_t *list,
-#     %(obj_type)s_t *obj, int index);
-# typedef int (*%(cls)s_remove_f)(
-#     %(cls)s_t *list,
-#     int index);
-# """ % {"cls":cls, "obj_type":obj_type})
-
 ################################################################
 #
 # New/Delete Function Definitions
@@ -2581,21 +1962,6 @@
     return fn
 
 
-def instantiate_fn_ptrs(cls, ilvl, out):
-    """
-    Generate the C code to instantiate function pointers for a class
-    @param cls The class name
-    @param ilvl The base indentation level
-    @param out The file to which to write the functions
-    """
-    for m_name in of_g.ordered_members[cls]:
-        if m_name in of_g.skip_members:
-            continue
-        out.write(" " * ilvl + "obj->%s_get = %s_%s_get;\n" %
-                  (m_name, cls, m_name))
-        out.write(" " * ilvl + "obj->%s_set = %s_%s_set;\n" %
-                  (m_name, cls, m_name))
-
 ################################################################
 # Routines to generate the body of new/delete functions
 ################################################################
@@ -2760,7 +2126,7 @@
  */
 
 %(cls)s_t *
-%(cls)s_new_(of_version_t version)
+%(cls)s_new(of_version_t version)
 {
     %(cls)s_t *obj;
     int bytes;
@@ -2795,25 +2161,6 @@
     out.write("""
     return obj;
 }
-
-#if defined(OF_OBJECT_TRACKING)
-
-/*
- * Tracking objects.  Call the new function and then record location
- */
-
-%(cls)s_t *
-%(cls)s_new_tracking(of_version_t version,
-     const char *file, int line)
-{
-    %(cls)s_t *obj;
-
-    obj = %(cls)s_new_(version);
-    of_object_track((of_object_t *)obj, file, line);
-
-    return obj;
-}
-#endif
 """ % dict(cls=cls))
 
 
@@ -2834,7 +2181,7 @@
  */
 
 %(cls)s_t *
-%(cls)s_new_from_message_(of_message_t msg)
+%(cls)s_new_from_message(of_message_t msg)
 {
     %(cls)s_t *obj = NULL;
     of_version_t version;
@@ -2863,25 +2210,6 @@
 
     return obj;
 }
-
-#if defined(OF_OBJECT_TRACKING)
-
-/*
- * Tracking objects.  Call the new function and then record location
- */
-
-%(cls)s_t *
-%(cls)s_new_from_message_tracking(of_message_t msg,
-    const char *file, int line)
-{
-    %(cls)s_t *obj;
-
-    obj = %(cls)s_new_from_message_(msg);
-    of_object_track((of_object_t *)obj, file, line);
-
-    return obj;
-}
-#endif
 """ % dict(cls=cls))
 
 
@@ -2911,58 +2239,15 @@
  *
  ****************************************************************/
 """)
-    out.write("""
-/*
- * If object tracking is enabled, map "new" and "new from msg"
- * calls to tracking versions; otherwise, directly to internal
- * versions of fns which have the same name but end in _.
- */
-
-#if defined(OF_OBJECT_TRACKING)
-""")
-    for cls in of_g.standard_class_order:
-        out.write("""
-extern %(cls)s_t *
-    %(cls)s_new_tracking(of_version_t version,
-        const char *file, int line);
-#define %(cls)s_new(version) \\
-    %(cls)s_new_tracking(version, \\
-        __FILE__, __LINE__)
-""" % dict(cls=cls))
-        if loxi_utils.class_is_message(cls):
-            out.write("""extern %(cls)s_t *
-    %(cls)s_new_from_message_tracking(of_message_t msg,
-        const char *file, int line);
-#define %(cls)s_new_from_message(msg) \\
-    %(cls)s_new_from_message_tracking(msg, \\
-        __FILE__, __LINE__)
-""" % dict(cls=cls))
-
-    out.write("""
-#else /* No object tracking */
-""")
-    for cls in of_g.standard_class_order:
-        out.write("""
-#define %(cls)s_new(version) \\
-    %(cls)s_new_(version)
-""" % dict(cls=cls))
-        if loxi_utils.class_is_message(cls):
-            out.write("""#define %(cls)s_new_from_message(msg) \\
-    %(cls)s_new_from_message_(msg)
-""" % dict(cls=cls))
-
-    out.write("""
-#endif /* Object tracking */
-""")
 
     for cls in of_g.standard_class_order:
         out.write("""
 extern %(cls)s_t *
-    %(cls)s_new_(of_version_t version);
+    %(cls)s_new(of_version_t version);
 """ % dict(cls=cls))
         if loxi_utils.class_is_message(cls):
             out.write("""extern %(cls)s_t *
-    %(cls)s_new_from_message_(of_message_t msg);
+    %(cls)s_new_from_message(of_message_t msg);
 """ % dict(cls=cls))
         out.write("""extern void %(cls)s_init(
     %(cls)s_t *obj, of_version_t version, int bytes, int clean_wire);
@@ -3092,57 +2377,17 @@
     obj->wire_length_set = of_meter_stats_wire_length_set;
 """)
 
-    if config_check("gen_fn_ptrs"):
-        if loxi_utils.class_is_list(cls):
-            out.write("""
-    obj->first = %(cls)s_first;
-    obj->next = %(cls)s_next;
-    obj->append = %(cls)s_append;
-    obj->append_bind = %(cls)s_append_bind;
-""" % dict(cls=cls))
-        else:
-            instantiate_fn_ptrs(cls, 4, out)
-
-def gen_new_function_definitions(out):
+def gen_new_function_definitions(out, cls):
     """
     Generate the new operator for all classes
 
     @param out The file to which to write the functions
     """
 
-    out.write("\n/* New operators for each message class */\n")
-    for cls in of_g.standard_class_order:
-        out.write("\n/* New operators for %s */\n" % cls)
-        gen_new_fn_body(cls, out)
-        gen_init_fn_body(cls, out)
-        if loxi_utils.class_is_message(cls):
-            gen_from_message_fn_body(cls, out)
-
-def gen_init_map(out):
-    """
-    Generate map from object ID to type coerce function
-    """
-    out.write("""
-/**
- * Map from object ID to type coerce function
- */
-const of_object_init_f of_object_init_map[] = {
-    (of_object_init_f)NULL,
-""")
-    count = 1
-    for i, cls in enumerate(of_g.standard_class_order):
-        if count != of_g.unified[cls]["object_id"]:
-            print "Error in class mapping: object IDs not sequential"
-            print cls, count, of_g.unified[cls]["object_id"]
-            sys.exit(1)
-        s = "(of_object_init_f)%s_init" % cls
-        if cls in type_maps.inheritance_map:
-            s = "(of_object_init_f)%s_header_init" % cls
-        if i < len(of_g.standard_class_order) - 1:
-            s += ","
-        out.write("    %-65s /* %d */\n" % (s, count))
-        count += 1
-    out.write("};\n")
+    gen_new_fn_body(cls, out)
+    gen_init_fn_body(cls, out)
+    if loxi_utils.class_is_message(cls):
+        gen_from_message_fn_body(cls, out)
 
 """
 Document generation functions
@@ -3410,232 +2655,3 @@
 }
 """ % dict(s_cls=cls[3:], cls=cls, cxn_type=cxn_type))
     gen_message_switch_stmt_tmeplate(out, False, cxn_type)
-
-def gen_setup_from_add_fns(out):
-    """
-    Generate functions that setup up objects based on an add
-
-    Okay, this is getting out of hand.  We need to refactor the code
-    so that this can be done without so much pain.
-    """
-    out.write("""
-
-/* 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/c_type_maps.py b/c_gen/c_type_maps.py
index b0775d1..06161ec 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -39,137 +39,6 @@
 # reserved values like 0xffff
 max_type_value = 1000
 
-def gen_object_id_to_type(out):
-    out.write("""
-/**
- * Map from object ID to primary wire type
- *
- * For messages, this is the header type; in particular for stats, this is
- * the common stats request/response type.  For per-stats types, use the
- * stats type map.  For things like actions, instructions or queue-props,
- * this gives the "sub type".
- */
-""")
-    for version in of_g.of_version_range:
-        out.write("static const int\nof_object_to_type_map_v%d[OF_OBJECT_COUNT] = {\n"
-                  %version)
-        out.write("    -1, /* of_object, not a valid specific type */\n")
-        for j, cls in enumerate(of_g.all_class_order):
-            comma = ""
-            if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
-                comma = ","
-
-            if cls in type_maps.stats_reply_list:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_stats_reply", version)],
-                           comma, cls))
-            elif cls in type_maps.stats_request_list:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_stats_request", version)],
-                           comma, cls))
-            elif cls in type_maps.error_msg_list:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_error_msg", version)],
-                           comma, cls))
-            elif cls in type_maps.flow_mod_list:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_flow_mod", version)],
-                           comma, cls))
-            elif cls in type_maps.group_mod_list and version > 1:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_group_mod", version)],
-                           comma, cls))
-            elif (cls, version) in type_maps.type_val and \
-                    type_maps.type_val[(cls, version)] != type_maps.invalid_type:
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[(cls, version)], comma, cls))
-            elif type_maps.message_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_experimenter", version)],
-                           comma, cls))
-            elif type_maps.action_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_action_experimenter",
-                                               version)],
-                           comma, cls))
-            elif type_maps.action_id_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_action_id_experimenter",
-                                               version)],
-                           comma, cls))
-            elif type_maps.instruction_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_instruction_experimenter",
-                                               version)],
-                           comma, cls))
-            elif type_maps.queue_prop_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                          (type_maps.type_val[("of_queue_prop_experimenter",
-                                               version)],
-                           comma, cls))
-            elif type_maps.table_feature_prop_is_extension(cls, version):
-                out.write("    %d%s /* %s */\n" %
-                    (type_maps.type_val[("of_table_feature_prop_experimenter",
-                                         version)],
-                     comma, cls))
-            else:
-                out.write("    -1%s /* %s (invalid) */\n" % (comma, cls))
-        out.write("};\n\n")
-
-    out.write("""
-/**
- * Unified map, indexed by wire version which is 1-based.
- */
-const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX] = {
-    NULL,
-""")
-    for version in of_g.of_version_range:
-        out.write("    of_object_to_type_map_v%d,\n" % version)
-    out.write("""
-};
-""")
-
-def gen_object_id_to_extension_data(out):
-    out.write("""
-/**
- * Extension data.
- * @fixme There must be a better way to represent this data
- */
-""")
-    for version in of_g.of_version_range:
-        out.write("""
-static const of_experimenter_data_t
-of_object_to_extension_data_v%d[OF_OBJECT_COUNT] = {
-""" % version)
-        out.write("    {0, 0, 0}, /* of_object, not a valid specific type */\n")
-        for j, cls in enumerate(of_g.all_class_order):
-            comma = ""
-            if j < len(of_g.all_class_order) - 1: # Avoid ultimate comma
-                comma = ","
-
-            if type_maps.class_is_extension(cls, version):
-                exp_name = type_maps.extension_to_experimenter_macro_name(cls)
-                subtype = type_maps.extension_to_subtype(cls, version)
-                out.write("    {1, %s, %d}%s /* %s */\n" %
-                          (exp_name, subtype, comma, cls))
-            else:
-                out.write("    {0, 0, 0}%s /* %s (non-extension) */\n" %
-                          (comma, cls))
-        out.write("};\n\n")
-
-    out.write("""
-/**
- * Unified map, indexed by wire version which is 1-based.
- */
-const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX] = {
-    NULL,
-""")
-    for version in of_g.of_version_range:
-        out.write("    of_object_to_extension_data_v%d,\n" % version)
-    out.write("""
-};
-""")
-
 def gen_type_to_object_id(out, type_str, prefix, template,
                           value_array, max_val):
     """
@@ -236,8 +105,6 @@
     @param out The file handle to write to
     """
 
-    out.write("#include <loci/loci.h>\n\n")
-
     # Generate maps from wire type values to object IDs
     gen_type_to_object_id(out, "error_msg_type_to_id", "OF_ERROR_MSG",
                           "OF_%s_ERROR_MSG", type_maps.error_types,
@@ -284,15 +151,9 @@
     gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
                           "OF_%s", type_maps.message_types, max_type_value)
 
-    gen_object_id_to_type(out)
-    gen_object_id_to_extension_data(out)
-    # Don't need array mapping ID to stats types right now; handled directly
-    # gen_object_id_to_stats_type(out)
-
-
 def gen_type_to_obj_map_functions(out):
     """
-    Generate the templated static inline type map functions
+    Generate the templated type map functions
     @param out The file handle to write to
     """
 
@@ -317,7 +178,7 @@
  * @return OF_OBJECT_INVALID if type does not map to an object
  *
  */
-static inline of_object_id_t
+of_object_id_t
 of_%(name)s_to_object_id(int %(name)s, of_version_t version)
 {
     if (!OF_VERSION_OKAY(version)) {
@@ -348,7 +209,7 @@
  * @return OF_OBJECT_INVALID if type does not map to an object
  *
  */
-static inline of_object_id_t
+of_object_id_t
 of_%(name)s_to_object_id(int %(name)s, of_version_t version)
 {
     if (!OF_VERSION_OKAY(version)) {
@@ -383,7 +244,7 @@
  * @return OF_OBJECT_INVALID if type does not map to an object
  *
  */
-static inline of_object_id_t
+of_object_id_t
 of_%(name)s_to_object_id(int %(name)s, of_version_t version)
 {
     if (!OF_VERSION_OKAY(version)) {
@@ -418,7 +279,7 @@
  * @return OF_OBJECT_INVALID if type does not map to an object
  *
  */
-static inline of_object_id_t
+of_object_id_t
 of_error_msg_to_object_id(uint16_t %(name)s, of_version_t version)
 {
     if (!OF_VERSION_OKAY(version)) {
@@ -452,7 +313,7 @@
  * @todo put OF_EXPERIMENTER_<name> in loci_base.h
  */
 
-static inline of_object_id_t
+of_object_id_t
 of_message_experimenter_to_object_id(of_message_t msg, of_version_t version) {
     uint32_t experimenter_id;
     uint32_t subtype;
@@ -502,7 +363,7 @@
  * @returns object ID or OF_OBJECT_INVALID if parse error
  */
 
-static inline of_object_id_t
+of_object_id_t
 of_message_to_object_id(of_message_t msg, int length) {
     uint8_t type;
     of_version_t ver;
@@ -608,7 +469,7 @@
  * @return OF_OBJECT_INVALID if type does not map to an object
  *
  */
-static inline of_object_id_t
+of_object_id_t
 of_oxm_to_object_id(uint32_t type_len, of_version_t version)
 {
     if (!OF_VERSION_OKAY(version)) {
@@ -727,373 +588,6 @@
     out.write(msg_template %
               dict(name="message", u_name="MESSAGE", ar_len=ar_len))
 
-def gen_obj_to_type_map_functions(out):
-    """
-    Generate the static line maps from object IDs to types
-    @param out The file handle to write to
-    """
-
-    ################################################################
-    # Generate object ID to primary type map
-    ################################################################
-
-    out.write("""
-extern const int *const of_object_to_type_map[OF_VERSION_ARRAY_MAX];
-
-/**
- * Map an object ID to its primary wire type value
- * @param id An object ID
- * @return For message objects, the type value in the OpenFlow header
- * @return For non-message objects such as actions, instructions, OXMs
- * returns the type value that appears in the respective sub-header
- * @return -1 For improper version or out of bounds input
- *
- * NOTE that for stats request/reply, returns the header type, not the
- * sub-type
- *
- * Also, note that the value is returned as a signed integer.  So -1 is
- * an error code, while 0xffff is the usual "experimenter" code.
- */
-static inline int
-of_object_to_wire_type(of_object_id_t id, of_version_t version)
-{
-    if (!OF_VERSION_OKAY(version)) {
-        return -1;
-    }
-    if (id < 0 || id >= OF_OBJECT_COUNT) {
-        return -1;
-    }
-    return of_object_to_type_map[version][id];
-}
-
-""")
-
-    # Now for experimenter ids
-    out.write("""
-/**
- * Map from object ID to a triple, (is_extension, experimenter id, subtype)
- */
-""")
-    out.write("""
-typedef struct of_experimenter_data_s {
-    int is_extension;  /* Boolean indication that this is an extension */
-    uint32_t experimenter_id;
-    uint32_t subtype;
-} of_experimenter_data_t;
-
-""")
-
-    out.write("""
-extern const of_experimenter_data_t *const of_object_to_extension_data[OF_VERSION_ARRAY_MAX];
-
-/**
- * Map from the object ID of an extension to the experimenter ID
- */
-static inline uint32_t
-of_extension_to_experimenter_id(of_object_id_t obj_id, of_version_t ver)
-{
-    if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
-        return (uint32_t) -1;
-    }
-    /* @fixme: Verify ver? */
-    return of_object_to_extension_data[ver][obj_id].experimenter_id;
-}
-
-/**
- * Map from the object ID of an extension to the experimenter subtype
- */
-static inline uint32_t
-of_extension_to_experimenter_subtype(of_object_id_t obj_id, of_version_t ver)
-{
-    if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
-        return (uint32_t) -1;
-    }
-    /* @fixme: Verify ver? */
-    return of_object_to_extension_data[ver][obj_id].subtype;
-}
-
-/**
- * Boolean function indicating the the given object ID/version
- * is recognized as a supported (decode-able) extension.
- */
-static inline int
-of_object_id_is_extension(of_object_id_t obj_id, of_version_t ver)
-{
-    if (obj_id < 0 || obj_id > OF_OBJECT_COUNT) {
-        return (uint32_t) -1;
-    }
-    /* @fixme: Verify ver? */
-    return of_object_to_extension_data[ver][obj_id].is_extension;
-}
-""")
-
-    ################################################################
-    # Generate object ID to the stats sub-type map
-    ################################################################
-
-    out.write("""
-/**
- * Map an object ID to a stats type
- * @param id An object ID
- * @return The wire value for the stats type
- * @return -1 if not supported for this version
- * @return -1 if id is not a specific stats type ID
- *
- * Note that the value is returned as a signed integer.  So -1 is
- * an error code, while 0xffff is the usual "experimenter" code.
- */
-
-static inline int
-of_object_to_stats_type(of_object_id_t id, of_version_t version)
-{
-    if (!OF_VERSION_OKAY(version)) {
-        return -1;
-    }
-    switch (id) {
-""")
-    # Assumes 1.2 contains all stats types and type values are
-    # the same across all versions
-    stats_names = dict()
-    for ver in of_g.of_version_range:
-        for name, value in type_maps.stats_types[ver].items():
-            if name in stats_names and (not value == stats_names[name]):
-                print "ERROR stats type differ violating assumption"
-                sys.exit(1)
-            stats_names[name] = value
-
-    for name, value in stats_names.items():
-        out.write("    case OF_%s_STATS_REPLY:\n" % name.upper())
-        out.write("    case OF_%s_STATS_REQUEST:\n" % name.upper())
-        for version in of_g.of_version_range:
-            if not name in type_maps.stats_types[version]:
-                out.write("        if (version == %s) break;\n" %
-                          of_g.of_version_wire2name[version])
-        out.write("        return %d;\n" % value)
-    out.write("""
-    default:
-        break;
-    }
-    return -1; /* Not recognized as stats type object for this version */
-}
-""")
-
-    ################################################################
-    # Generate object ID to the error sub-type map
-    ################################################################
-    out.write("""
-/**
- * Map an object ID to an error type
- * @param id An object ID
- * @return The wire value for the error type
- * @return -1 if not supported for this version
- * @return -1 if id is not a specific error type ID
- *
- * Note that the value is returned as a signed integer.  So -1 is
- * an error code, while 0xffff is the usual "experimenter" code.
- */
-
-static inline int
-of_object_to_error_type(of_object_id_t id, of_version_t version)
-{
-    if (!OF_VERSION_OKAY(version)) {
-        return -1;
-    }
-    switch (id) {""")
-    error_names = set()
-    for ver in of_g.of_version_range:
-        for name in type_maps.error_types[ver]:
-            error_names.add(name)
-    for name in error_names:
-        out.write("""
-    case OF_%(name)s_ERROR_MSG:
-        if (OF_ERROR_TYPE_%(name)s_SUPPORTED(version))
-            return OF_ERROR_TYPE_%(name)s_BY_VERSION(version);
-        break;""" % {"name": name.upper()})
-    out.write("""
-    default:
-        break;
-    }
-    return -1; /* Not recognized as error type object for this version */
-}
-""")
-
-    ################################################################
-    # Generate object ID to the flow mod sub-type map
-    ################################################################
-
-    out.write("""
-/**
- * Map an object ID to a flow-mod command value
- * @param id An object ID
- * @return The wire value for the flow-mod command
- * @return -1 if not supported for this version
- * @return -1 if id is not a specific stats type ID
- *
- * Note that the value is returned as a signed integer.  So -1 is
- * an error code, while 0xffff is the usual "experimenter" code.
- */
-
-static inline int
-of_object_to_flow_mod_command(of_object_id_t id, of_version_t version)
-{
-    if (!OF_VERSION_OKAY(version)) {
-        return -1;
-    }
-    switch (id) {
-""")
-    # Assumes 1.2 contains all stats types and type values are
-    # the same across all versions
-    flow_mod_names = dict()
-    for ver in of_g.of_version_range:
-        for name, value in type_maps.flow_mod_types[ver].items():
-            if name in flow_mod_names and \
-                    (not value == flow_mod_names[name]):
-                print "ERROR flow mod command differ violating assumption"
-                sys.exit(1)
-            flow_mod_names[name] = value
-
-    for name, value in flow_mod_names.items():
-        out.write("    case OF_FLOW_%s:\n" % name.upper())
-        for version in of_g.of_version_range:
-            if not name in type_maps.flow_mod_types[version]:
-                out.write("        if (version == %s) break;\n" %
-                          of_g.of_version_wire2name[version])
-        out.write("        return %d;\n" % value)
-    out.write("""
-    default:
-        break;
-    }
-    return -1; /* Not recognized as flow mod type object for this version */
-}
-
-""")
-
-    ################################################################
-    # Generate object ID to the group mod sub-type map
-    ################################################################
-
-    out.write("""
-/**
- * Map an object ID to a group-mod command value
- * @param id An object ID
- * @return The wire value for the group-mod command
- * @return -1 if not supported for this version
- * @return -1 if id is not a specific stats type ID
- *
- * Note that the value is returned as a signed integer.  So -1 is
- * an error code, while 0xffff is the usual "experimenter" code.
- */
-
-static inline int
-of_object_to_group_mod_command(of_object_id_t id, of_version_t version)
-{
-    if (!OF_VERSION_OKAY(version)) {
-        return -1;
-    }
-    switch (id) {""")
-    group_mod_names = set()
-    for ver in of_g.of_version_range:
-        for name in type_maps.group_mod_types[ver]:
-            group_mod_names.add(name)
-    for name in group_mod_names:
-        out.write("""
-    case OF_GROUP_%(name)s:
-        if (OF_GROUP_MOD_COMMAND_%(name)s_SUPPORTED(version))
-            return OF_GROUP_MOD_COMMAND_%(name)s_BY_VERSION(version);
-        break;""" % {"name": name.upper()})
-    out.write("""
-    default:
-        break;
-    }
-    return -1; /* Not recognized as group mod type object for this version */
-}
-
-""")
-
-def gen_type_maps_header(out):
-    """
-    Generate various header file declarations for type maps
-    @param out The file handle to write to
-    """
-
-    out.write("""
-/**
- * Generic experimenter type value.  Applies to all except
- * top level message: Action, instruction, error, stats, queue_props, oxm
- */
-#define OF_EXPERIMENTER_TYPE 0xffff
-
-int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
-int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
-""")
-    gen_type_to_obj_map_functions(out)
-    gen_obj_to_type_map_functions(out)
-
-    out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
-    out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
-
-    out.write("""
-/**
- * Map a message in a wire buffer object to its OF object id.
- * @param wbuf Pointer to a wire buffer object, populated with an OF message
- * @returns The object ID of the message
- * @returns OF_OBJECT_INVALID if unable to parse the message type
- */
-
-static inline of_object_id_t
-of_wire_object_id_get(of_wire_buffer_t *wbuf)
-{
-    of_message_t msg;
-
-    msg = (of_message_t)WBUF_BUF(wbuf);
-    return of_message_to_object_id(msg, WBUF_CURRENT_BYTES(wbuf));
-}
-
-/**
- * Use the type/length from the wire buffer and init the object
- * @param obj The object being initialized
- * @param base_object_id If > 0, this indicates the base object
- * @param max_len If > 0, the max length to expect for the obj
- * type for inheritance checking
- * @return OF_ERROR_
- *
- * Used for inheritance type objects such as actions and OXMs
- * The type is checked and if valid, the object is initialized.
- * Then the length is taken from the buffer.
- *
- * Note that the object version must already be properly set.
- */
-static inline int
-of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
-                    int max_len)
-{
-    if (obj->wire_type_get != NULL) {
-        of_object_id_t id;
-        obj->wire_type_get(obj, &id);
-        if (!of_wire_id_valid(id, base_object_id)) {
-            return OF_ERROR_PARSE;
-        }
-        obj->object_id = id;
-        /* Call the init function for this object type; do not push to wire */
-        of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
-    }
-    if (obj->wire_length_get != NULL) {
-        int length;
-        obj->wire_length_get(obj, &length);
-        if (length < 0 || (max_len > 0 && length > max_len)) {
-            return OF_ERROR_PARSE;
-        }
-        obj->length = length;
-    } else {
-        /* @fixme Does this cover everything else? */
-        obj->length = of_object_fixed_len[obj->version][base_object_id];
-    }
-
-    return OF_ERROR_NONE;
-}
-
-""")
-
 def gen_type_data_header(out):
 
     out.write("""
@@ -1281,45 +775,3 @@
     out.write("""
 };
 """)
-
-
-################################################################
-################################################################
-
-# THIS IS PROBABLY NOT NEEDED AND MAY NOT BE CALLED CURRENTLY
-def gen_object_id_to_stats_type(out):
-    out.write("""
-/**
- * Map from message object ID to stats type
- *
- * All message object IDs are mapped for simplicity
- */
-""")
-    for version in of_g.of_version_range:
-        out.write("const int *of_object_to_stats_type_map_v%d = {\n" % (i+1))
-        out.write("    -1, /* of_object (invalid) */\n");
-        for cls in of_g.ordered_messages:
-            name = cls[3:]
-            name = name[:name.find("_stats")]
-            if (((cls in type_maps.stats_reply_list) or
-                 (cls in type_maps.stats_request_list)) and
-                name in type_maps.stats_types[i]):
-                out.write("    %d, /* %s */\n" %
-                          (type_maps.stats_types[i][name], cls))
-            else:
-                out.write("    -1, /* %s (invalid) */\n" % cls)
-        out.write("};\n\n")
-
-    out.write("""
-/**
- * Unified map, indexed by wire version which is 1-based.
- */
-const int *of_object_to_stats_type_map[OF_VERSION_ARRAY_MAX] = {
-    NULL,
-""")
-    for version in of_g.of_version_range:
-        out.write("    of_object_to_stats_type_map_v%d,\n" % version)
-    out.write("""
-};
-""")
-
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index cc4a58c..3249747 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -33,47 +33,113 @@
 
 from collections import namedtuple
 from itertools import groupby
+from StringIO import StringIO
 import template_utils
 import loxi_globals
 import loxi_ir.ir as ir
 import util
+import c_code_gen
+import c_gen.of_g_legacy as of_g
+import c_gen.type_maps as type_maps
+import c_gen.c_type_maps as c_type_maps
 
-PushWireTypesFn = namedtuple('PushWireTypesFn',
+PushWireTypesData = namedtuple('PushWireTypesData',
     ['class_name', 'versioned_type_members'])
 PushWireTypesMember = namedtuple('PushWireTypesMember',
     ['name', 'offset', 'length', 'value'])
 
-def gen_push_wire_types(install_dir):
-    fns = []
+def push_wire_types_data(uclass):
+    if uclass.virtual or not uclass.has_type_members:
+        return None
+
+    # Generate a dict of version -> list of PushWireTypesMember
+    type_members_by_version = {}
+    for version, ofclass in sorted(uclass.version_classes.items()):
+        pwtms = []
+        for m in ofclass.members:
+            if isinstance(m, ir.OFTypeMember):
+                if m.name == "version" and m.value == version.wire_version:
+                    # Special case for version
+                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
+                else:
+                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
+        type_members_by_version[version] = pwtms
+
+    # Merge versions with identical type members
+    all_versions = sorted(type_members_by_version.keys())
+    versioned_type_members = []
+    for pwtms, versions in groupby(all_versions, type_members_by_version.get):
+        versioned_type_members.append((pwtms, list(versions)))
+
+    return PushWireTypesData(
+        class_name=uclass.name,
+        versioned_type_members=versioned_type_members)
+
+def generate_classes(install_dir):
     for uclass in loxi_globals.unified.classes:
-        if uclass.virtual or not uclass.has_type_members:
+        with template_utils.open_output(install_dir, "loci/src/%s.c" % uclass.name) as out:
+            util.render_template(out, "class.c",
+                push_wire_types_data=push_wire_types_data(uclass))
+            # Append legacy generated code
+            c_code_gen.gen_new_function_definitions(out, uclass.name)
+            c_code_gen.gen_accessor_definitions(out, uclass.name)
+
+# TODO remove header classes and use the corresponding class instead
+def generate_header_classes(install_dir):
+    for cls in of_g.standard_class_order:
+        if cls.find("_header") < 0:
             continue
+        with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
+            util.render_template(out, "class.c",
+                push_wire_types_data=None)
+            # Append legacy generated code
+            c_code_gen.gen_new_function_definitions(out, cls)
+            c_code_gen.gen_accessor_definitions(out, cls)
 
-        # Generate a dict of version -> list of PushWireTypesMember
-        type_members_by_version = {}
-        for version, ofclass in sorted(uclass.version_classes.items()):
-            pwtms = []
-            for m in ofclass.members:
-                if isinstance(m, ir.OFTypeMember):
-                    if m.name == "version" and m.value == version.wire_version:
-                        # Special case for version
-                        pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
-                    else:
-                        pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
-            type_members_by_version[version] = pwtms
+def generate_classes_header(install_dir):
+    # Collect legacy code
+    tmp = StringIO()
+    c_code_gen.gen_struct_typedefs(tmp)
+    c_code_gen.gen_new_function_declarations(tmp)
+    c_code_gen.gen_accessor_declarations(tmp)
+    c_code_gen.gen_generics(tmp)
 
-        # Merge versions with identical type members
-        all_versions = sorted(type_members_by_version.keys())
-        versioned_type_members = []
-        for pwtms, versions in groupby(all_versions, type_members_by_version.get):
-            versioned_type_members.append((pwtms, list(versions)))
+    with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
+        util.render_template(out, "loci_classes.h",
+            legacy_code=tmp.getvalue())
 
-        fns.append(PushWireTypesFn(
-            class_name=uclass.name,
-            versioned_type_members=versioned_type_members))
+def generate_lists(install_dir):
+    for cls in of_g.ordered_list_objects:
+        with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
+            util.render_template(out, "class.c",
+                push_wire_types_data=None)
+            # Append legacy generated code
+            c_code_gen.gen_new_function_definitions(out, cls)
+            c_code_gen.gen_list_accessors(out, cls)
 
-    with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.c") as out:
-        util.render_template(out, "loci_push_wire_types.c", fns=fns)
+def generate_strings(install_dir):
+    object_id_strs = []
+    object_id_strs.append("of_object")
+    object_id_strs.extend(of_g.ordered_messages)
+    object_id_strs.extend(of_g.ordered_non_messages)
+    object_id_strs.extend(of_g.ordered_list_objects)
+    object_id_strs.extend(of_g.ordered_pseudo_objects)
+    object_id_strs.append("of_unknown_object")
 
-    with template_utils.open_output(install_dir, "loci/src/loci_push_wire_types.h") as out:
-        util.render_template(out, "loci_push_wire_types.h", fns=fns)
+    with template_utils.open_output(install_dir, "loci/src/loci_strings.c") as out:
+        util.render_template(out, "loci_strings.c", object_id_strs=object_id_strs)
+
+def generate_init_map(install_dir):
+    with template_utils.open_output(install_dir, "loci/src/loci_init_map.c") as out:
+        util.render_template(out, "loci_init_map.c", classes=of_g.standard_class_order)
+
+def generate_type_maps(install_dir):
+    # Collect legacy code
+    tmp = StringIO()
+    c_type_maps.gen_type_to_obj_map_functions(tmp)
+    c_type_maps.gen_type_maps(tmp)
+    c_type_maps.gen_length_array(tmp)
+    c_type_maps.gen_extra_length_array(tmp)
+
+    with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
+        util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
diff --git a/c_gen/loci_utils.py b/c_gen/loci_utils.py
index bc3092f..686fb0f 100644
--- a/c_gen/loci_utils.py
+++ b/c_gen/loci_utils.py
@@ -96,30 +96,6 @@
 def member_type_is_octets(cls, m_name):
     return member_base_type(cls, m_name) == "of_octets_t"
 
-def member_returns_val(cls, m_name):
-    """
-    Should get accessor return a value rather than void
-    @param cls The class name
-    @param m_name The member name
-    @return True if of_g config and the specific member allow a
-    return value.  Otherwise False
-    """
-    m_type = of_g.unified[cls]["union"][m_name]["m_type"]
-    return (config_check("get_returns") =="value" and
-            m_type in of_g.of_scalar_types)
-
-def config_check(str, dictionary = of_g.code_gen_config):
-    """
-    Return config value if in dictionary; else return False.
-    @param str The lookup index
-    @param dictionary The dict to check; use code_gen_config if None
-    """
-
-    if str in dictionary:
-        return dictionary[str]
-
-    return False
-
 def h_file_to_define(name):
     """
     Convert a .h file name to the define used for the header
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 9abca52..6a0fb2e 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -322,30 +322,6 @@
 def member_type_is_octets(cls, m_name):
     return member_base_type(cls, m_name) == "of_octets_t"
 
-def member_returns_val(cls, m_name):
-    """
-    Should get accessor return a value rather than void
-    @param cls The class name
-    @param m_name The member name
-    @return True if of_g config and the specific member allow a
-    return value.  Otherwise False
-    """
-    m_type = of_g.unified[cls]["union"][m_name]["m_type"]
-    return (config_check("get_returns") =="value" and
-            m_type in of_g.of_scalar_types)
-
-def config_check(str, dictionary = of_g.code_gen_config):
-    """
-    Return config value if in dictionary; else return False.
-    @param str The lookup index
-    @param dictionary The dict to check; use code_gen_config if None
-    """
-
-    if str in dictionary:
-        return dictionary[str]
-
-    return False
-
 def h_file_to_define(name):
     """
     Convert a .h file name to the define used for the header
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index 80d922c..6f0947c 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -53,15 +53,6 @@
 ##
 # The dictionary of config variables related to code
 #
-# @param gen_unified_fns  Boolean; Generate top level function definitions for
-# accessors which are independent of the version; the alternative is to only
-# use the function pointers in the class definitions.  These functions support
-# better inlining optimizations.
-#
-# @param gen_fn_ptrs Boolean; Generate the functions pointed to by pointer
-# in the class (struct) definitions; the alternative is to only use the
-# unified (use_) functions
-#
 # @param use_obj_id  Use object IDs in struct defns   CURRENTLY NOT SUPPORTED
 #
 # @param return_base_types For 'get' accessors, return values when possible.
@@ -83,19 +74,6 @@
 # and use a call-by-variable parameter
 #
 
-# @fixme These are still very C specific and should probably either
-# go into lang_c.py or be swallowed by command line option parsing
-code_gen_config = dict(
-    gen_unified_fns=True,
-#    gen_fn_ptrs=True,  # WARNING: Haven't tested with this in a while
-    gen_fn_ptrs=False,
-    use_obj_id=False,
-    use_static_inlines=False,
-    copy_semantics="read",  # Only read implemented: read, write, grow
-    encoded_typedefs=False,
-    get_returns="error",   # Only error implemented; error, value, void
-)
-
 ## These members do not get normal accessors
 
 skip_members = ["version", "type", "length", "err_type", "stats_type", "len",
@@ -236,46 +214,6 @@
                    "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
                    "of_ipv6_t", "of_ipv4_t", "of_bitmap_128_t"]
 
-base_object_members = """\
-    /* The control block for the underlying data buffer */
-    of_wire_object_t wire_object;
-    /* The LOCI type enum value of the object */
-    of_object_id_t object_id;
-
-    /*
-     * Objects need to track their "parent" so that updates to the
-     * object that affect its length can be pushed to the parent.
-     * Treat as private.
-     */
-    of_object_t *parent;
-
-    /*
-     * Not all objects have length and version on the wire so we keep
-     * them here.  NOTE: Infrastructure manages length and version.
-     * Treat length as private and version as read only.
-     */
-    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];
-"""
-
 ##
 # LOXI identifiers
 #
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/_pragmas.c
similarity index 78%
copy from c_gen/templates/loci_push_wire_types.h
copy to c_gen/templates/_pragmas.c
index 5b2c1e8..cbdc350 100644
--- a/c_gen/templates/loci_push_wire_types.h
+++ b/c_gen/templates/_pragmas.c
@@ -25,16 +25,26 @@
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
 ::
-:: include('_copyright.c')
-#ifndef LOCI_PUSH_WIRE_TYPES_H
-#define LOCI_PUSH_WIRE_TYPES_H
+#ifdef __GNUC__
 
-#include <loci/loci.h>
+#ifdef __linux__
+/* glibc */
+#include <features.h>
+#else
+/* NetBSD etc */
+#include <sys/cdefs.h>
+#ifdef __GNUC_PREREQ__
+#define __GNUC_PREREQ __GNUC_PREREQ__
+#endif
+#endif
 
-/* Declarations of public functions from loci_push_wire_types.c */
+#ifndef __GNUC_PREREQ
+/* fallback */
+#define __GNUC_PREREQ(maj, min) 0
+#endif
 
-:: for fn in fns:
-void ${fn.class_name}_push_wire_types(of_object_t *obj);
-:: #endfor
+#if __GNUC_PREREQ(4,6)
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
 
 #endif
diff --git a/c_gen/templates/loci_push_wire_types.c b/c_gen/templates/_push_wire_types.c
similarity index 71%
rename from c_gen/templates/loci_push_wire_types.c
rename to c_gen/templates/_push_wire_types.c
index 2103aad..b7b6288 100644
--- a/c_gen/templates/loci_push_wire_types.c
+++ b/c_gen/templates/_push_wire_types.c
@@ -25,41 +25,12 @@
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
 ::
-:: include('_copyright.c')
-
-/****************************************************************
- *
- * Functions for each concrete class that set the type fields
- *
- ****************************************************************/
-
-#include <loci/loci.h>
-#include <loci/of_message.h>
-#include <endian.h>
-
-#ifdef __GNUC__
-#define UNREACHABLE() __builtin_unreachable()
-#else
-#define UNREACHABLE()
-#endif
-
-/*
- * In a separate function to give the compiler the choice of whether to inline.
- */
-static unsigned char *
-loci_object_to_buffer(of_object_t *obj)
+static void
+${data.class_name}_push_wire_types(of_object_t *obj)
 {
-    return OF_OBJECT_BUFFER_INDEX(obj, 0);
-}
-
-:: for fn in fns:
-
-void
-${fn.class_name}_push_wire_types(of_object_t *obj)
-{
-    unsigned char *buf = loci_object_to_buffer(obj);
+    unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
     switch (obj->version) {
-:: for ms, versions in fn.versioned_type_members:
+:: for ms, versions in data.versioned_type_members:
 :: for version in versions:
     case ${version.constant_version(prefix='OF_VERSION_')}:
 :: #endfor
@@ -80,4 +51,3 @@
         UNREACHABLE();
     }
 }
-:: #endfor
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/class.c
similarity index 84%
copy from c_gen/templates/loci_push_wire_types.h
copy to c_gen/templates/class.c
index 5b2c1e8..044e03e 100644
--- a/c_gen/templates/loci_push_wire_types.h
+++ b/c_gen/templates/class.c
@@ -26,15 +26,12 @@
 :: # under the EPL.
 ::
 :: include('_copyright.c')
-#ifndef LOCI_PUSH_WIRE_TYPES_H
-#define LOCI_PUSH_WIRE_TYPES_H
+:: include('_pragmas.c')
 
-#include <loci/loci.h>
+#include "loci_log.h"
+#include "loci_int.h"
 
-/* Declarations of public functions from loci_push_wire_types.c */
+:: if push_wire_types_data:
+:: include("_push_wire_types.c", data=push_wire_types_data)
 
-:: for fn in fns:
-void ${fn.class_name}_push_wire_types(of_object_t *obj);
-:: #endfor
-
-#endif
+:: #endif
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/loci_classes.h
similarity index 84%
rename from c_gen/templates/loci_push_wire_types.h
rename to c_gen/templates/loci_classes.h
index 5b2c1e8..3486055 100644
--- a/c_gen/templates/loci_push_wire_types.h
+++ b/c_gen/templates/loci_classes.h
@@ -26,15 +26,10 @@
 :: # under the EPL.
 ::
 :: include('_copyright.c')
-#ifndef LOCI_PUSH_WIRE_TYPES_H
-#define LOCI_PUSH_WIRE_TYPES_H
+::
+#ifndef __LOCI_CLASSES_H__
+#define __LOCI_CLASSES_H__
 
-#include <loci/loci.h>
-
-/* Declarations of public functions from loci_push_wire_types.c */
-
-:: for fn in fns:
-void ${fn.class_name}_push_wire_types(of_object_t *obj);
-:: #endfor
+${legacy_code}
 
 #endif
diff --git a/c_gen/templates/loci_push_wire_types.h b/c_gen/templates/loci_init_map.c
similarity index 83%
copy from c_gen/templates/loci_push_wire_types.h
copy to c_gen/templates/loci_init_map.c
index 5b2c1e8..dc4616d 100644
--- a/c_gen/templates/loci_push_wire_types.h
+++ b/c_gen/templates/loci_init_map.c
@@ -24,17 +24,18 @@
 :: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
-::
 :: include('_copyright.c')
-#ifndef LOCI_PUSH_WIRE_TYPES_H
-#define LOCI_PUSH_WIRE_TYPES_H
-
 #include <loci/loci.h>
+#include <loci/of_object.h>
+#include "loci_log.h"
+#include "loci_int.h"
 
-/* Declarations of public functions from loci_push_wire_types.c */
-
-:: for fn in fns:
-void ${fn.class_name}_push_wire_types(of_object_t *obj);
+/**
+ * Map from object ID to type coerce function
+ */
+const of_object_init_f of_object_init_map[] = {
+    (of_object_init_f)NULL,
+:: for cls in classes:
+    (of_object_init_f)${cls}_init,
 :: #endfor
-
-#endif
+};
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index 87cfd1e..241cf7b 100644
--- a/c_gen/templates/loci_int.h
+++ b/c_gen/templates/loci_int.h
@@ -26,6 +26,13 @@
 :: # under the EPL.
 ::
 :: include('_copyright.c')
+:: import c_gen.of_g_legacy as of_g
+:: flow_mod = of_g.base_length[("of_flow_modify",of_g.VERSION_1_2)]
+:: packet_in = of_g.base_length[("of_packet_in",of_g.VERSION_1_2)]
+:: packet_in_1_3 = of_g.base_length[("of_packet_in",of_g.VERSION_1_3)]
+:: flow_stats = of_g.base_length[("of_flow_stats_entry", of_g.VERSION_1_2)]
+:: match1 = of_g.base_length[("of_match_v1",of_g.VERSION_1_0)]
+:: match2 = of_g.base_length[("of_match_v2",of_g.VERSION_1_1)]
 
 /******************************************************************************
  *
@@ -37,9 +44,237 @@
 #ifndef __LOCI_INT_H__
 #define __LOCI_INT_H__
 
+#include <loci/loci.h>
 
+#ifdef __GNUC__
+#define UNREACHABLE() __builtin_unreachable()
+#else
+#define UNREACHABLE()
+#endif
 
+/****************************************************************
+ * Special case macros for calculating variable lengths and offsets
+ ****************************************************************/
 
+/**
+ * Get a u16 directly from an offset in an object's wire buffer
+ * @param obj An of_object_t object
+ * @param offset Base offset of the uint16 relative to the object
+ *
+ */
 
-#include <loci/loci.h> 
+static inline int
+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);
+
+    return (int)val16;
+}
+
+/**
+ * Set a u16 directly at an offset in an object's wire buffer
+ * @param obj An of_object_t object
+ * @param offset Base offset of the uint16 relative to the object
+ * @param val The value to store
+ *
+ */
+
+static inline void
+of_object_u16_set(of_object_t *obj, int offset, int value) {
+    uint16_t val16;
+
+    val16 = (uint16_t)value;
+    of_wire_buffer_u16_set(obj->wire_object.wbuf,
+        obj->wire_object.obj_offset + offset, val16);
+}
+
+/**
+ * Get length of an object with a TLV header with uint16_t
+ * @param obj An object with a match member
+ * @param offset The wire offset of the start of the object
+ *
+ * The length field follows the type field.
+ */
+
+#define _TLV16_LEN(obj, offset) \
+    (of_object_u16_get((of_object_t *)(obj), (offset) + 2))
+
+/**
+ * Get length of an object that is the "rest" of the object
+ * @param obj An object with a match member
+ * @param offset The wire offset of the start of the object
+ *
+ */
+
+#define _END_LEN(obj, offset) ((obj)->length - (offset))
+
+/**
+ * Offset of the action_len member in a packet-out object
+ */
+
+#define _PACKET_OUT_ACTION_LEN_OFFSET(obj) \
+    (((obj)->version == OF_VERSION_1_0) ? 14 : 16)
+
+/**
+ * Get length of the action list object in a packet_out object
+ * @param obj An object of type of_packet_out
+ */
+
+#define _PACKET_OUT_ACTION_LEN(obj) \
+    (of_object_u16_get((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj)))
+
+/**
+ * Set length of the action list object in a packet_out object
+ * @param obj An object of type of_packet_out
+ */
+
+#define _PACKET_OUT_ACTION_LEN_SET(obj, len) \
+    (of_object_u16_set((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj), len))
+
+/*
+ * Match structs in 1.2 come at the end of the fixed length part
+ * of structures.  They add 8 bytes to the minimal length of the
+ * message, but are also variable length.  This means that the
+ * type/length offsets are 8 bytes back from the end of the fixed
+ * length part of the object.  The right way to handle this is to
+ * expose the offset of the match member more explicitly.  For now,
+ * we make the calculation as described here.
+ */
+
+/* 1.2 min length of match is 8 bytes */
+#define _MATCH_MIN_LENGTH_V3 8
+
+/**
+ * The offset of a 1.2 match object relative to fixed length of obj
+ */
+#define _MATCH_OFFSET_V3(fixed_obj_len) \
+    ((fixed_obj_len) - _MATCH_MIN_LENGTH_V3)
+
+/**
+ * The "extra" length beyond the minimal 8 bytes of a match struct
+ * in an object
+ */
+#define _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len) \
+    (OF_MATCH_BYTES(_TLV16_LEN(obj, _MATCH_OFFSET_V3(fixed_obj_len))) - \
+     _MATCH_MIN_LENGTH_V3)
+
+/**
+ * The offset of an object following a match object for 1.2
+ */
+#define _OFFSET_FOLLOWING_MATCH_V3(obj, fixed_obj_len) \
+    ((fixed_obj_len) + _MATCH_EXTRA_LENGTH_V3(obj, fixed_obj_len))
+
+/**
+ * Get length of a match object from its wire representation
+ * @param obj An object with a match member
+ * @param match_offset The wire offset of the match object.
+ *
+ * See above; for 1.2,
+ * The match length is raw bytes but the actual space it takes
+ * up is padded for alignment to 64-bits
+ */
+#define _WIRE_MATCH_LEN(obj, match_offset) \
+    (((obj)->version == OF_VERSION_1_0) ? ${match1} : \
+     (((obj)->version == OF_VERSION_1_1) ? ${match2} : \
+      _TLV16_LEN(obj, match_offset)))
+
+#define _WIRE_LEN_MIN 4
+
+/*
+ * Wrapper function for match len.  There are cases where the wire buffer
+ * has not been set with the proper minimum length.  In this case, the
+ * wire match len is interpretted as its minimum length, 4 bytes.
+ */
+
+static inline int
+wire_match_len(of_object_t *obj, int match_offset) {
+    int len;
+
+    len = _WIRE_MATCH_LEN(obj, match_offset);
+
+    return (len == 0) ? _WIRE_LEN_MIN : len;
+}
+
+#define _WIRE_MATCH_PADDED_LEN(obj, match_offset) \
+    OF_MATCH_BYTES(wire_match_len((of_object_t *)(obj), (match_offset)))
+
+/**
+ * Macro to calculate variable offset of instructions member in flow mod
+ * @param obj An object of some type of flow modify/add/delete
+ *
+ * Get length of preceding match object and add to fixed length
+ * Applies only to version 1.2
+ */
+
+#define _FLOW_MOD_INSTRUCTIONS_OFFSET(obj) \
+    _OFFSET_FOLLOWING_MATCH_V3(obj, ${flow_mod})
+
+/* The different flavors of flow mod all use the above */
+#define _FLOW_ADD_INSTRUCTIONS_OFFSET(obj) \
+    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
+#define _FLOW_MODIFY_INSTRUCTIONS_OFFSET(obj) \
+    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
+#define _FLOW_MODIFY_STRICT_INSTRUCTIONS_OFFSET(obj) \
+    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
+#define _FLOW_DELETE_INSTRUCTIONS_OFFSET(obj) \
+    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
+#define _FLOW_DELETE_STRICT_INSTRUCTIONS_OFFSET(obj) \
+    _FLOW_MOD_INSTRUCTIONS_OFFSET(obj)
+
+/**
+ * Macro to calculate variable offset of instructions member in flow stats
+ * @param obj An object of type of_flow_mod_t
+ *
+ * Get length of preceding match object and add to fixed length
+ * Applies only to version 1.2 and 1.3
+ */
+
+#define _FLOW_STATS_ENTRY_INSTRUCTIONS_OFFSET(obj) \
+    _OFFSET_FOLLOWING_MATCH_V3(obj, ${flow_stats})
+
+/**
+ * Macro to calculate variable offset of data (packet) member in packet_in
+ * @param obj An object of type of_packet_in_t
+ *
+ * Get length of preceding match object and add to fixed length
+ * Applies only to version 1.2 and 1.3
+ * The +2 comes from the 2 bytes of padding between the match and packet data.
+ */
+
+#define _PACKET_IN_DATA_OFFSET(obj) \
+    (_OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
+${packet_in} : ${packet_in_1_3}) + 2)
+
+/**
+ * Macro to calculate variable offset of data (packet) member in packet_out
+ * @param obj An object of type of_packet_out_t
+ *
+ * Find the length in the actions_len variable and add to the fixed len
+ * Applies only to version 1.2 and 1.3
+ */
+
+#define _PACKET_OUT_DATA_OFFSET(obj) (_PACKET_OUT_ACTION_LEN(obj) + \
+     of_object_fixed_len[(obj)->version][OF_PACKET_OUT])
+
+/**
+ * Macro to map port numbers that changed across versions
+ * @param port The port_no_t variable holding the value
+ * @param ver The OpenFlow version from which the value was extracted
+ */
+#define OF_PORT_NO_VALUE_CHECK(port, ver) \
+    if (((ver) == OF_VERSION_1_0) && ((port) > 0xff00)) (port) += 0xffff0000
+
+/**
+ * Macro to detect if an object ID falls in the "flow mod" family of objects
+ * This includes add, modify, modify_strict, delete and delete_strict
+ */
+#define IS_FLOW_MOD_SUBTYPE(object_id)                 \
+    (((object_id) == OF_FLOW_MODIFY) ||                \
+     ((object_id) == OF_FLOW_MODIFY_STRICT) ||         \
+     ((object_id) == OF_FLOW_DELETE) ||                \
+     ((object_id) == OF_FLOW_DELETE_STRICT) ||         \
+     ((object_id) == OF_FLOW_ADD))
+
 #endif /* __LOCI_INT_H__ */
diff --git a/c_gen/templates/loci_log.h b/c_gen/templates/loci_log.h
index 25b9a67..14a68cf 100644
--- a/c_gen/templates/loci_log.h
+++ b/c_gen/templates/loci_log.h
@@ -30,10 +30,6 @@
 #if !defined(_LOCI_LOG_H_)
 #define _LOCI_LOG_H_
 
-#include <loci/loci_base.h>
-#include <loci/of_match.h>
-#include <stdio.h>
-
 /* g++ requires this to pick up PRI, etc.
  * See  http://gcc.gnu.org/ml/gcc-help/2006-10/msg00223.html
  */
diff --git a/c_gen/templates/loci_setup_from_add_fns.c b/c_gen/templates/loci_setup_from_add_fns.c
new file mode 100644
index 0000000..5f63d29
--- /dev/null
+++ b/c_gen/templates/loci_setup_from_add_fns.c
@@ -0,0 +1,250 @@
+:: # 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_strings.c b/c_gen/templates/loci_strings.c
new file mode 100644
index 0000000..f546e12
--- /dev/null
+++ b/c_gen/templates/loci_strings.c
@@ -0,0 +1,75 @@
+:: # 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"
+
+const char *const of_object_id_str[] = {
+:: for cls in object_id_strs:
+    "${cls}",
+:: #endfor
+};
+
+const char *const of_version_str[] = {
+    "Unknown OpenFlow Version",
+    "OpenFlow-1.0",
+    "OpenFlow-1.1",
+    "OpenFlow-1.2"
+};
+
+const of_mac_addr_t of_mac_addr_all_ones = {
+    {
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+    }
+};
+/* Just to be explicit; static duration vars are init'd to 0 */
+const of_mac_addr_t of_mac_addr_all_zeros = {
+    {
+        0, 0, 0, 0, 0, 0
+    }
+};
+
+const of_ipv6_t of_ipv6_all_ones = {
+    {
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+    }
+};
+/* Just to be explicit; static duration vars are init'd to 0 */
+const of_ipv6_t of_ipv6_all_zeros = {
+    {
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    }
+};
+
+/** @var of_error_strings
+ * The error string map; use abs value to index
+ */
+const char *const of_error_strings[] = { OF_ERROR_STRINGS };
diff --git a/c_gen/templates/locitest/Makefile b/c_gen/templates/locitest/Makefile
index a7a6f37..70e57ca 100644
--- a/c_gen/templates/locitest/Makefile
+++ b/c_gen/templates/locitest/Makefile
@@ -1,15 +1,22 @@
-SRCS := $(wildcard src/*.c)
-SRCS += $(wildcard ../loci/src/*.c)
+LOCITEST_SRCS := $(wildcard src/*.c)
+LOCI_SRCS := $(wildcard ../loci/src/*.c)
 
-OBJS := $(SRCS:.c=.o)
+LOCITEST_OBJS := $(LOCITEST_SRCS:.c=.o)
+LOCI_OBJS := $(LOCI_SRCS:.c=.o)
 
-CFLAGS := -Wall -Werror -g
+CFLAGS := -Wall -Werror -g -Os
 CFLAGS += -Iinc -I../loci/inc -I ../loci/src
 
 all: locitest
 
-locitest: $(OBJS)
+locitest: $(LOCITEST_OBJS) loci.a
 	$(CC) $^ -o $@
 
+loci.a: $(LOCI_OBJS)
+	ar rc $@ $^
+
+clean:
+	rm -f locitest loci.a $(LOCITEST_OBJS) $(LOCI_OBJS)
+
 # BSN build system magic
 MODULE := locitest
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index ae22f64..9b1bafd 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -39,17 +39,6 @@
 #include <loci/loci.h>
 #include <loci/loci_validator.h>
 
-#if defined(OF_OBJECT_TRACKING)
-#include <BigList/biglist.h>
-
-loci_object_track_t loci_global_tracking;
-
-#define TRACK (&loci_global_tracking)
-#define TRACK_OBJS (TRACK->objects)
-#define CHECK_MAX(val, max) if ((val) > (max)) (max) = (val)
-
-#endif
-
 /**
  * Create a generic new object and possibly underlying wire buffer
  * @param bytes The number of bytes to allocate in the underlying buffer
@@ -66,10 +55,10 @@
 {
     of_object_t *obj;
 
-    if ((obj = (of_object_t *)MALLOC(sizeof(of_generic_t))) == NULL) {
+    if ((obj = (of_object_t *)MALLOC(sizeof(*obj))) == NULL) {
         return NULL;
     }
-    MEMSET(obj, 0, sizeof(of_generic_t));
+    MEMSET(obj, 0, sizeof(*obj));
 
     if (bytes > 0) {
         if ((obj->wire_object.wbuf = of_wire_buffer_new(bytes)) == NULL) {
@@ -98,20 +87,6 @@
         return;
     }
 
-#if defined(OF_OBJECT_TRACKING)
-    ASSERT(obj->track_info.magic == OF_OBJECT_TRACKING_MAGIC &&
-           "of_object double free?");
-    LOCI_LOG_TRACE("OF obj delete %p.  Wire buf %p.\n", obj,
-                   obj->wire_object.wbuf);
-    ASSERT(TRACK->count_current > 0);
-    TRACK->count_current -= 1;
-    TRACK->deletes += 1;
-
-    TRACK_OBJS = biglist_remove_link_free(TRACK_OBJS,
-                                          obj->track_info.bl_entry);
-    obj->track_info.magic = 0;
-#endif
-
     /*
      * Make callback if present
      */
@@ -134,12 +109,12 @@
  */
 
 of_object_t *
-of_object_dup_(of_object_t *src)
+of_object_dup(of_object_t *src)
 {
     of_object_t *dst;
     of_object_init_f init_fn;
 
-    if ((dst = (of_object_t *)MALLOC(sizeof(of_generic_t))) == NULL) {
+    if ((dst = (of_object_t *)MALLOC(sizeof(*dst))) == NULL) {
         return NULL;
     }
 
@@ -163,107 +138,6 @@
     return dst;
 }
 
-#if defined(OF_OBJECT_TRACKING)
-
-/**
- * Record an object for tracking
- *
- * @param obj The object being tracked
- * @param file The file name where the allocation is happening
- * @param line The line number in the file where the alloc is happening
- */
-
-void
-of_object_track(of_object_t *obj, const char *file, int line)
-{
-    if (obj != NULL) {
-        LOCI_LOG_TRACE("OF obj track %p, wire buf %p\n%s:%d\\n",
-                      obj, obj->wire_object.wbuf, file, line);
-        obj->track_info.file = file;
-        obj->track_info.line = line;
-        TRACK_OBJS = biglist_prepend(TRACK_OBJS, (void *)obj);
-        obj->track_info.bl_entry = TRACK_OBJS;
-        obj->track_info.magic = OF_OBJECT_TRACKING_MAGIC;
-
-        TRACK->allocs += 1;
-        TRACK->count_current += 1;
-        CHECK_MAX(TRACK->count_current, TRACK->count_max);
-    }
-}
-
-/**
- * The dup function when tracking is enabled
- */
-
-of_object_t *
-of_object_dup_tracking(of_object_t *src, const char *file, int line)
-{
-    of_object_t *obj;
-
-    obj = of_object_dup_(src);
-    of_object_track(obj, file, line);
-
-    return obj;
-}
-
-/**
- * Display track info for one object
- */
-
-void
-of_object_track_output(of_object_t *obj, loci_writer_f writer, void* cookie)
-{
-    const char *offset;
-    static const char *unknown = "Unknown file";
-
-    if (obj->track_info.file) {
-        offset = strstr(obj->track_info.file, "Modules/");
-        if (offset == NULL) {
-            offset = obj->track_info.file;
-        } else {
-            offset += 8; /* Jump over Modules/ too */
-        }
-    } else {
-        offset = unknown;
-    }
-    writer(cookie, "obj %p. type %s.\n%s:%d\n",
-               obj, of_object_id_str[obj->object_id],
-               offset, obj->track_info.line);
-}
-
-/**
- * Dump out the current object list from LOCI
- *
- * @param log_fn The output printf vector
- *
- */
-
-void
-of_object_track_report(loci_writer_f writer, void* cookie)
-{
-    biglist_t *elt;
-    of_object_t *obj;
-    int count = 0;
-
-    writer(cookie, "\nLOCI Outstanding object list.\n");
-    writer(cookie, "Objs: Current %d. Max %d. Created %d. Deleted %d\n",
-               TRACK->count_current, TRACK->count_max, TRACK->allocs,
-               TRACK->deletes);
-    if (TRACK_OBJS) {
-        BIGLIST_FOREACH_DATA(elt, TRACK_OBJS, of_object_t *, obj) {
-            of_object_track_output(obj, writer, cookie);
-            ++count;
-        }
-    }
-    if (count != TRACK->count_current) {
-        writer(cookie, "\nERROR:  List has %d, but track count is %d\n",
-                   count, TRACK->count_current);
-    }
-    writer(cookie, "\nEnd of outstanding object list\n");
-}
-
-#endif
-
 /**
  * Generic new from message call
  */
@@ -302,11 +176,6 @@
     obj->length = len;
     obj->version = version;
 
-#if defined(OF_OBJECT_TRACKING)
-    /* @FIXME Would be nice to get caller; for now only in cxn_instance */
-    of_object_track(obj, __FILE__, __LINE__);
-#endif
-
     return obj;
 }
 
@@ -641,6 +510,90 @@
     obj->wire_object.wbuf = NULL;
 }
 
+#define _MAX_PARENT_ITERATIONS 4
+/**
+ * Iteratively update parent lengths thru hierarchy
+ * @param obj The object whose length is being updated
+ * @param delta The difference between the current and new lengths
+ *
+ * Note that this includes updating the object itself.  It will
+ * iterate thru parents.
+ *
+ * Assumes delta > 0.
+ */
+void
+of_object_parent_length_update(of_object_t *obj, int delta)
+{
+#ifndef NDEBUG
+    int count = 0;
+    of_wire_buffer_t *wbuf;  /* For debug asserts only */
+#endif
+
+    while (obj != NULL) {
+        ASSERT(count++ < _MAX_PARENT_ITERATIONS);
+        obj->length += delta;
+        if (obj->wire_length_set != NULL) {
+            obj->wire_length_set(obj, obj->length);
+        }
+#ifndef NDEBUG
+        wbuf = obj->wire_object.wbuf;
+#endif
+
+        /* Asserts for wire length checking */
+        ASSERT(obj->length + obj->wire_object.obj_offset <=
+               WBUF_CURRENT_BYTES(wbuf));
+        if (obj->parent == NULL) {
+            ASSERT(obj->length + obj->wire_object.obj_offset ==
+                   WBUF_CURRENT_BYTES(wbuf));
+        }
+
+        obj = obj->parent;
+    }
+}
+
+/**
+ * Use the type/length from the wire buffer and init the object
+ * @param obj The object being initialized
+ * @param base_object_id If > 0, this indicates the base object
+ * @param max_len If > 0, the max length to expect for the obj
+ * type for inheritance checking
+ * @return OF_ERROR_
+ *
+ * Used for inheritance type objects such as actions and OXMs
+ * The type is checked and if valid, the object is initialized.
+ * Then the length is taken from the buffer.
+ *
+ * Note that the object version must already be properly set.
+ */
+int
+of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
+                    int max_len)
+{
+    if (obj->wire_type_get != NULL) {
+        of_object_id_t id;
+        obj->wire_type_get(obj, &id);
+        if (!of_wire_id_valid(id, base_object_id)) {
+            return OF_ERROR_PARSE;
+        }
+        obj->object_id = id;
+        /* Call the init function for this object type; do not push to wire */
+        of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
+    }
+    if (obj->wire_length_get != NULL) {
+        int length;
+        obj->wire_length_get(obj, &length);
+        if (length < 0 || (max_len > 0 && length > max_len)) {
+            return OF_ERROR_PARSE;
+        }
+        obj->length = length;
+    } else {
+        /* @fixme Does this cover everything else? */
+        obj->length = of_object_fixed_len[obj->version][base_object_id];
+    }
+
+    return OF_ERROR_NONE;
+}
+
 /*
  * Set member:
  *    get_wbuf_extent
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index ff4c9c5..0e761fd 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -46,10 +46,7 @@
 #include <loci/of_match.h>
 #include <loci/loci_base.h>
 #include <loci/of_message.h>
-
-#if defined(OF_OBJECT_TRACKING)
-#include <BigList/biglist.h>
-#endif
+#include <loci/of_wire_buf.h>
 
 /**
  * This is the number of bytes reserved for metadata in each
@@ -57,6 +54,24 @@
  */
 #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
  ****************************************************************/
@@ -74,79 +89,18 @@
 extern int of_list_append(of_object_t *list, of_object_t *item);
 
 extern of_object_t *of_object_new(int bytes);
-extern of_object_t * of_object_dup_(of_object_t *src);
+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);
 
-#if defined(OF_OBJECT_TRACKING)
-/**
- * When tracking is enabled, the location of each new or dup
- * call of an OF object is recorded and a list is kept of all
- * outstanding objects.
- *
- * This dovetails with using objects to track outstanding operations
- * for barrier processing.
- */
-
-/**
- * Global tracking stats
- */
-typedef struct loci_object_track_s {
-    biglist_t *objects;
-    int count_current;
-    uint32_t count_max;
-    uint32_t allocs;
-    uint32_t deletes;
-} loci_object_track_t;
-
-extern loci_object_track_t loci_global_tracking;
-
-/* Remap dup call to tracking */
-extern of_object_t * of_object_dup_tracking(of_object_t *src,
-                                            const char *file, int line);
-#define of_object_dup(src) of_object_dup_tracking(src, __FILE__, __LINE__)
-extern void of_object_track(of_object_t *obj, const char *file, int line);
-
-extern void of_object_track_output(of_object_t *obj, loci_writer_f writer, void* cookie); 
-extern void of_object_track_report(loci_writer_f writer, void* cookie); 
-
-/**
- * The data stored in each object related to tracking and
- * The LOCI client may install a delete callback function to allow
- * the notification of an object's destruction.
- */
-
-typedef struct of_object_track_info_s {
-    of_object_delete_callback_f delete_cb;  /* To be implemented */
-    void *delete_cookie;
-
-    /* Track file and line where allocated */
-    const char *file;
-    int line;
-    biglist_t *bl_entry; /* Pointer to self */
-    uint32_t magic; /* validation value */
-} of_object_track_info_t;
-
-#define OF_OBJECT_TRACKING_MAGIC 0x11235813
-#else
-
-/* Use native dup call */
-#define of_object_dup of_object_dup_
-
-/**
- * When tracking is not enabled, we still support a delete callback
- */
-
 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;
 
-#endif
-
 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);
 
@@ -173,4 +127,46 @@
 
 int of_object_can_grow(of_object_t *obj, int new_len);
 
+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;
+    /* The LOCI type enum value of the object */
+    of_object_id_t object_id;
+
+    /*
+     * Objects need to track their "parent" so that updates to the
+     * object that affect its length can be pushed to the parent.
+     * Treat as private.
+     */
+    of_object_t *parent;
+
+    /*
+     * Not all objects have length and version on the wire so we keep
+     * them here.  NOTE: Infrastructure manages length and version.
+     * Treat length as private and version as read only.
+     */
+    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];
+};
+
 #endif /* _OF_OBJECT_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 4b35dcc..7310988 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -40,6 +40,8 @@
 #define OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET 4
 #define OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET 8
 
+${legacy_code}
+
 /****************************************************************
  * Top level OpenFlow message length functions
  ****************************************************************/
diff --git a/lang_c.py b/lang_c.py
index 7718d48..0a881e9 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -72,8 +72,6 @@
     'loci/inc/loci/of_wire_buf.h': static,
 
     # LOCI code
-    'loci/src/loci.c': c_code_gen.top_c_gen,
-    'loci/src/of_type_data.c': c_code_gen.type_data_c_gen,
     'loci/src/of_match.c': c_code_gen.match_c_gen,
     'loci/src/loci_obj_dump.c': c_dump_gen.gen_obj_dump_c,
     'loci/src/loci_obj_show.c': c_show_gen.gen_obj_show_c,
@@ -84,9 +82,9 @@
     'loci/src/loci_log.c': static,
     'loci/src/loci_log.h': static,
     'loci/src/of_object.c': static,
-    'loci/src/of_type_maps.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,
@@ -116,54 +114,6 @@
     'locitest/Makefile': static,
 }
 
-################################################################
-#
-# Configuration related
-#
-################################################################
-
-def config_check(str, dictionary = of_g.code_gen_config):
-    """
-    Return config value if in dictionary; else return False.
-    @param str The lookup index
-    @param dictionary The dict to check; use code_gen_config if None
-    """
-
-    if str in dictionary:
-        return dictionary[str]
-
-    return False
-
-def config_sanity_check():
-    """
-    Check the configuration for basic consistency
-
-    @fixme Needs update for generic language support
-    """
-
-    rv = True
-    # For now, only "error" supported for get returns
-    if config_check("copy_semantics") != "read":
-        debug("Only 'read' is supported for copy_semantics");
-        rv = False
-    if config_check("get_returns") != "error":
-        debug("Only 'error' is supported for get-accessor return types\m");
-        rv = False
-    if not config_check("use_fn_ptrs") and not config_check("gen_unified_fns"):
-        debug("Must have gen_fn_ptrs and/or gen_unified_fns set in config")
-        rv = False
-    if config_check("use_obj_id"):
-        debug("use_obj_id is set but not yet supported (change \
-config_sanity_check if it is)")
-        rv = False
-    if config_check("gen_unified_macros") and config_check("gen_unified_fns") \
-            and config_check("gen_unified_macro_lower"):
-        debug("Conflict: Cannot generate unified functions and lower case \
-unified macros")
-        rv = False
-
-    return rv
-
 def generate(install_dir):
     build_of_g.initialize_versions()
     build_of_g.build_ordered_classes()
@@ -174,4 +124,10 @@
     for (name, fn) in targets.items():
         with template_utils.open_output(install_dir, name) as outfile:
             fn(outfile, os.path.basename(name))
-    c_gen.codegen.gen_push_wire_types(install_dir)
+    c_gen.codegen.generate_classes(install_dir)
+    c_gen.codegen.generate_header_classes(install_dir)
+    c_gen.codegen.generate_classes_header(install_dir)
+    c_gen.codegen.generate_lists(install_dir)
+    c_gen.codegen.generate_strings(install_dir)
+    c_gen.codegen.generate_init_map(install_dir)
+    c_gen.codegen.generate_type_maps(install_dir)