Merge into master from pull request #242:
loci: lazily zero wire buffer (https://github.com/floodlight/loxigen/pull/242)
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index ed923cb..b43675a 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -375,7 +375,7 @@
  * Treat as private
  */
 #define OF_OBJECT_TO_MESSAGE(obj) \\
-    ((of_message_t)(WBUF_BUF((obj)->wire_object.wbuf)))
+    ((of_message_t)(WBUF_BUF((obj)->wbuf)))
 
 /**
  * Macro for the fixed length part of an object
@@ -469,8 +469,8 @@
  */
 #define OF_LENGTH_CHECK_ASSERT(obj) \\
     LOCI_ASSERT(((obj)->parent != NULL) || \\
-     ((obj)->wire_object.wbuf == NULL) || \\
-     (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
+     ((obj)->wbuf == NULL) || \\
+     (WBUF_CURRENT_BYTES((obj)->wbuf) == (obj)->length))
 
 #define OF_DEBUG_DUMP
 #if defined(OF_DEBUG_DUMP)
@@ -803,6 +803,7 @@
 #include <loci/of_match.h>
 #include <loci/of_object.h>
 #include <loci/loci_classes.h>
+#include <loci/loci_class_metadata.h>
 
 /****************************************************************
  *
@@ -1676,9 +1677,8 @@
     %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
     /* Attach to parent */
     %(m_name)s->parent = (of_object_t *)obj;
-    %(m_name)s->wire_object.wbuf = obj->wire_object.wbuf;
-    %(m_name)s->wire_object.obj_offset = abs_offset;
-    %(m_name)s->wire_object.owned = 0;
+    %(m_name)s->wbuf = obj->wbuf;
+    %(m_name)s->obj_offset = abs_offset;
     %(m_name)s->length = cur_len;
 """ % dict(m_type=m_type[:-2], m_name=m_name))
 
@@ -1720,7 +1720,7 @@
         out.write("""
     new_len = %(m_name)s->length;
     /* If underlying buffer already shared; nothing to do */
-    if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
+    if (obj->wbuf == %(m_name)s->wbuf) {
         of_wire_buffer_grow(wbuf, abs_offset + new_len);
         /* Verify that the offsets are correct */
         LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
@@ -1752,9 +1752,7 @@
         elif m_type not in ["of_match_t", "of_octets_t"]:
             out.write("""
     /* @fixme Shouldn't this precede copying value's data to buffer? */
-    if (%(m_name)s->wire_length_set != NULL) {
-        %(m_name)s->wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
-    }
+    of_object_wire_length_set((of_object_t *)%(m_name)s, %(m_name)s->length);
 """ % dict(m_name=m_name))
         out.write("""
     /* Not scalar, update lengths if needed */
@@ -2058,15 +2056,14 @@
     obj->length = bytes;
     obj->object_id = %(enum)s;
 """ % dict(cls=cls, enum=enum_name(cls)))
-    gen_coerce_ops(out, cls)
 
     out.write("""
     /* Grow the wire buffer */
-    if (obj->wire_object.wbuf != NULL) {
+    if (obj->wbuf != NULL) {
         int tot_bytes;
 
-        tot_bytes = bytes + obj->wire_object.obj_offset;
-        of_wire_buffer_grow(obj->wire_object.wbuf, tot_bytes);
+        tot_bytes = bytes + obj->obj_offset;
+        of_wire_buffer_grow(obj->wbuf, tot_bytes);
     }
 }
 
@@ -2117,7 +2114,7 @@
 
         if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
             out.write("""
-    obj->wire_length_set((of_object_t *)obj, obj->length);
+    of_object_wire_length_set((of_object_t *)obj, obj->length);
 """)
 
         if cls == "of_meter_stats":
@@ -2332,99 +2329,6 @@
  ****************************************************************/
 """)
 
-#
-# @fixme Not clear that these should all be set for virtual fns
-#
-# @fixme Clean up.  should have a (language specific) map from class
-# to length and type get/set functions
-#
-
-def gen_coerce_ops(out, cls):
-    out.write("""
-    /* Set up the object's function pointers */
-""")
-
-    uclass = loxi_globals.unified.class_by_name(cls)
-    if uclass and not uclass.virtual and uclass.has_type_members:
-        out.write("""
-    obj->wire_type_set = %(cls)s_push_wire_types;
-""" % dict(cls=cls))
-
-    if loxi_utils.class_is_message(cls):
-        out.write("""
-    obj->wire_length_get = of_object_message_wire_length_get;
-    obj->wire_length_set = of_object_message_wire_length_set;
-""")
-    else:
-        if loxi_utils.class_is_tlv16(cls):
-            if not (cls in type_maps.inheritance_map): # Don't set for super
-                out.write("""
-    obj->wire_length_set = of_tlv16_wire_length_set;
-""")
-            out.write("""
-    obj->wire_length_get = of_tlv16_wire_length_get;
-""")
-            if loxi_utils.class_is_action(cls):
-                out.write("""
-    obj->wire_type_get = of_action_wire_object_id_get;
-""")
-            if loxi_utils.class_is_action_id(cls):
-                out.write("""
-    obj->wire_type_get = of_action_id_wire_object_id_get;
-""")
-            if loxi_utils.class_is_instruction(cls):
-                out.write("""
-    obj->wire_type_get = of_instruction_wire_object_id_get;
-""")
-            if loxi_utils.class_is_instruction_id(cls):
-                out.write("""
-    obj->wire_type_get = of_instruction_id_wire_object_id_get;
-""")
-            if loxi_utils.class_is_queue_prop(cls):
-                    out.write("""
-    obj->wire_type_get = of_queue_prop_wire_object_id_get;
-""")
-            if loxi_utils.class_is_table_feature_prop(cls):
-                    out.write("""
-    obj->wire_type_get = of_table_feature_prop_wire_object_id_get;
-""")
-            if loxi_utils.class_is_meter_band(cls):
-                    out.write("""
-    obj->wire_type_get = of_meter_band_wire_object_id_get;
-""")
-            if loxi_utils.class_is_hello_elem(cls):
-                    out.write("""
-    obj->wire_type_get = of_hello_elem_wire_object_id_get;
-""")
-            if loxi_utils.class_is_bsn_tlv(cls):
-                    out.write("""
-    obj->wire_type_get = of_bsn_tlv_wire_object_id_get;
-""")
-        if loxi_utils.class_is_oxm(cls):
-            out.write("""
-    obj->wire_length_get = of_oxm_wire_length_get;
-    obj->wire_type_get = of_oxm_wire_object_id_get;
-""")
-        if loxi_utils.class_is_u16_len(cls):
-            out.write("""
-    obj->wire_length_get = of_u16_len_wire_length_get;
-    obj->wire_length_set = of_u16_len_wire_length_set;
-""")
-        if cls == "of_packet_queue":
-            out.write("""
-    obj->wire_length_get = of_packet_queue_wire_length_get;
-    obj->wire_length_set = of_packet_queue_wire_length_set;
-""")
-#        if cls == "of_list_meter_band_stats":
-#            out.write("""
-#    obj->wire_length_get = of_list_meter_band_stats_wire_length_get;
-#""")
-        if cls == "of_meter_stats":
-            out.write("""
-    obj->wire_length_get = of_meter_stats_wire_length_get;
-    obj->wire_length_set = of_meter_stats_wire_length_set;
-""")
-
 def gen_new_function_definitions(out, cls):
     """
     Generate the new operator for all classes
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index d7fa178..3aad03e 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -929,7 +929,7 @@
 
             /* Free the wire buffer control block without freeing
              * octets->bytes. */
-            of_wire_buffer_steal(wire_match.wire_object.wbuf, &tmp);
+            of_wire_buffer_steal(wire_match.wbuf, &tmp);
         }
         break;
 """ % dict(version=version, ver_name=of_g.of_version_wire2name[version]))
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 01f1c5d..2ca743a 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -565,10 +565,10 @@
 
     if not type_maps.class_is_virtual(cls):
         out.write("""
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
 
-        obj->wire_length_get((of_object_t *)obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
         TEST_ASSERT(length == %(length)d);
     }
 
@@ -717,10 +717,10 @@
     if inst_len >= 0:
         check_template = """
     TEST_ASSERT(%(inst)s->length == %(inst_len)d);
-    if (%(inst)s->wire_length_get != NULL) {
+    if (loci_class_metadata[%(inst)s->object_id].wire_length_get != NULL) {
         int length;
 
-        %(inst)s->wire_length_get(
+        loci_class_metadata[%(inst)s->object_id].wire_length_get(
             (of_object_t *)&elt, &length);
         TEST_ASSERT(length == %(inst_len)d);
     }
@@ -1552,16 +1552,16 @@
            v_name=v_name, length=length, version=version))
     if (not type_maps.class_is_virtual(cls)) or loxi_utils.class_is_list(cls):
         out.write("""
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
 
-        obj->wire_length_get((of_object_t *)obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get((of_object_t *)obj, &length);
         TEST_ASSERT(length == %(length)d);
     }
-    if (obj->wire_type_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t obj_id;
 
-        obj->wire_type_get((of_object_t *)obj, &obj_id);
+        loci_class_metadata[obj->object_id].wire_type_get((of_object_t *)obj, &obj_id);
         TEST_ASSERT(obj_id == %(u_cls)s);
     }
 
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index af4dfa4..82de380 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -180,3 +180,155 @@
 
     with template_utils.open_output(install_dir, "loci/src/of_type_maps.c") as out:
         util.render_template(out, "of_type_maps.c", legacy_code=tmp.getvalue())
+
+ClassMetadata = namedtuple('ClassMetadata',
+    ['name', 'wire_length_get', 'wire_length_set', 'wire_type_get', 'wire_type_set'])
+
+def generate_class_metadata(install_dir):
+    with template_utils.open_output(install_dir, "loci/inc/loci/loci_class_metadata.h") as out:
+        util.render_template(out, "loci_class_metadata.h")
+
+    with template_utils.open_output(install_dir, "loci/src/loci_class_metadata.c") as out:
+        class_metadata = []
+        for uclass in loxi_globals.unified.classes:
+            wire_length_get = 'NULL'
+            wire_length_set = 'NULL'
+            wire_type_get = 'NULL'
+            wire_type_set = 'NULL'
+
+            if uclass and not uclass.virtual and uclass.has_type_members:
+                wire_type_set = '%s_push_wire_types' % uclass.name
+
+            if uclass.is_message and uclass.name != "of_header":
+                wire_length_get = 'of_object_message_wire_length_get'
+                wire_length_set = 'of_object_message_wire_length_set'
+            elif uclass.is_action:
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_action_wire_object_id_get'
+            elif uclass.is_action_id:
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_action_id_wire_object_id_get'
+            elif uclass.is_instruction:
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_instruction_wire_object_id_get'
+            elif uclass.is_instanceof('of_instruction_id'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_instruction_id_wire_object_id_get'
+            elif uclass.is_instanceof('of_queue_prop'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_queue_prop_wire_object_id_get'
+            elif uclass.is_instanceof('of_table_feature_prop'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_table_feature_prop_wire_object_id_get'
+            elif uclass.is_instanceof('of_meter_band'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_meter_band_wire_object_id_get'
+            elif uclass.is_instanceof('of_hello_elem'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_hello_elem_wire_object_id_get'
+            elif uclass.is_instanceof('of_bsn_tlv'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_bsn_tlv_wire_object_id_get'
+            elif uclass.is_oxm:
+                wire_length_get = 'of_oxm_wire_length_get'
+                wire_type_get = 'of_oxm_wire_object_id_get'
+            elif uclass.name == "of_packet_queue":
+                wire_length_get = 'of_packet_queue_wire_length_get'
+                wire_length_set = 'of_packet_queue_wire_length_set'
+            elif uclass.name == "of_list_meter_band_stats":
+                wire_length_get = 'of_list_meter_band_stats_wire_length_get'
+            elif uclass.name == "of_meter_stats":
+                wire_length_get = 'of_meter_stats_wire_length_get'
+                wire_length_set = 'of_meter_stats_wire_length_set'
+            elif uclass.name in ["of_group_desc_stats_entry", "of_group_stats_entry",
+                   "of_flow_stats_entry", "of_bucket", "of_table_features",
+                   "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
+                   "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
+                   "of_bsn_gentable_desc_stats_entry"]:
+                wire_length_get = "of_u16_len_wire_length_get"
+                wire_length_set = "of_u16_len_wire_length_set"
+            elif uclass.name == 'of_match_v3':
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_set = 'of_match_v3_push_wire_types'
+
+            class_metadata.append(ClassMetadata(
+                name=uclass.name,
+                wire_length_get=wire_length_get,
+                wire_length_set=wire_length_set,
+                wire_type_get=wire_type_get,
+                wire_type_set=wire_type_set))
+
+        class_metadata.extend([
+            ClassMetadata(
+                name="of_action_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_action_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_action_id_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_action_id_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_instruction_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_instruction_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_instruction_id_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_instruction_id_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_queue_prop_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_queue_prop_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_table_feature_prop_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_table_feature_prop_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_meter_band_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_meter_band_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_hello_elem_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_hello_elem_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_bsn_tlv_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_bsn_tlv_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
+                name="of_oxm_header",
+                wire_length_set='NULL',
+                wire_length_get='of_oxm_wire_length_get',
+                wire_type_get='of_oxm_wire_object_id_get',
+                wire_type_set='NULL'),
+        ])
+
+        util.render_template(out, "loci_class_metadata.c", class_metadata=class_metadata)
diff --git a/c_gen/templates/_push_wire_types.c b/c_gen/templates/_push_wire_types.c
index fd2536c..96a9111 100644
--- a/c_gen/templates/_push_wire_types.c
+++ b/c_gen/templates/_push_wire_types.c
@@ -25,7 +25,7 @@
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
 ::
-static void
+void
 ${data.class_name}_push_wire_types(of_object_t *obj)
 {
     unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
diff --git a/c_gen/templates/loci_class_metadata.c b/c_gen/templates/loci_class_metadata.c
new file mode 100644
index 0000000..1aca773
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.c
@@ -0,0 +1,51 @@
+:: # Copyright 2014, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.c')
+:: import loxi_globals
+
+/****************************************************************
+ *
+ * loci_class_metadata.c
+ *
+ * Tables with information for each class
+ *
+ ****************************************************************/
+
+#include "loci_log.h"
+#include <loci/loci.h>
+
+struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT] = {
+:: for data in class_metadata:
+    [${data.name.upper()}] = {
+        .wire_length_get=${data.wire_length_get},
+        .wire_length_set=${data.wire_length_set},
+        .wire_type_get=${data.wire_type_get},
+        .wire_type_set=${data.wire_type_set},
+    },
+:: #endfor
+};
diff --git a/c_gen/templates/loci_class_metadata.h b/c_gen/templates/loci_class_metadata.h
new file mode 100644
index 0000000..37962e3
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.h
@@ -0,0 +1,63 @@
+:: # Copyright 2014, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.c')
+::
+#ifndef __LOCI_CLASS_METADATA_H__
+#define __LOCI_CLASS_METADATA_H__
+
+typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
+typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
+typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
+typedef void (*of_wire_type_set_f)(of_object_t *obj);
+
+struct loci_class_metadata {
+    of_wire_length_get_f wire_length_get;
+    of_wire_length_set_f wire_length_set;
+    of_wire_type_get_f wire_type_get;
+    of_wire_type_set_f wire_type_set;
+};
+
+extern struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT];
+
+static inline void
+of_object_wire_length_set(of_object_t *obj, int bytes)
+{
+    if (loci_class_metadata[obj->object_id].wire_length_set) {
+        loci_class_metadata[obj->object_id].wire_length_set(obj, bytes);
+    }
+}
+
+static inline void
+of_object_wire_type_set(of_object_t *obj)
+{
+    if (loci_class_metadata[obj->object_id].wire_type_set) {
+        loci_class_metadata[obj->object_id].wire_type_set(obj);
+    }
+}
+
+#endif
diff --git a/c_gen/templates/loci_classes.h b/c_gen/templates/loci_classes.h
index 12c07d1..c5147cb 100644
--- a/c_gen/templates/loci_classes.h
+++ b/c_gen/templates/loci_classes.h
@@ -33,6 +33,7 @@
 
 :: for uclass in loxi_globals.unified.classes:
 void ${uclass.name}_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
+void ${uclass.name}_push_wire_types(of_object_t *obj);
 :: #endfor
 
 ${legacy_code}
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index c57371a..1ea9eeb 100644
--- a/c_gen/templates/loci_int.h
+++ b/c_gen/templates/loci_int.h
@@ -67,8 +67,8 @@
 of_object_u16_get(of_object_t *obj, int offset) {
     uint16_t val16;
 
-    of_wire_buffer_u16_get(obj->wire_object.wbuf,
-        obj->wire_object.obj_offset + offset, &val16);
+    of_wire_buffer_u16_get(obj->wbuf,
+        obj->obj_offset + offset, &val16);
 
     return (int)val16;
 }
@@ -86,8 +86,8 @@
     uint16_t val16;
 
     val16 = (uint16_t)value;
-    of_wire_buffer_u16_set(obj->wire_object.wbuf,
-        obj->wire_object.obj_offset + offset, val16);
+    of_wire_buffer_u16_set(obj->wbuf,
+        obj->obj_offset + offset, val16);
 }
 
 /**
diff --git a/c_gen/templates/locitest/test_setup_from_add.c b/c_gen/templates/locitest/test_setup_from_add.c
index 0b07076..ebb4968 100644
--- a/c_gen/templates/locitest/test_setup_from_add.c
+++ b/c_gen/templates/locitest/test_setup_from_add.c
@@ -112,8 +112,8 @@
 
     /* Verify lists agree */
     TEST_ASSERT(list->length == list_out.length);
-    TEST_ASSERT(memcmp(WBUF_BUF(list->wire_object.wbuf),
-                       WBUF_BUF(list_out.wire_object.wbuf),
+    TEST_ASSERT(memcmp(WBUF_BUF(list->wbuf),
+                       WBUF_BUF(list_out.wbuf),
                        list->length));
 
     of_flow_add_delete(add);
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 69bd8d3..39a6790 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -61,11 +61,10 @@
     MEMSET(obj, 0, sizeof(*obj));
 
     if (bytes > 0) {
-        if ((obj->wire_object.wbuf = of_wire_buffer_new(bytes)) == NULL) {
+        if ((obj->wbuf = of_wire_buffer_new(bytes)) == NULL) {
             FREE(obj);
             return NULL;
         }
-        obj->wire_object.owned = 1;
     }
 
     return obj;
@@ -87,15 +86,8 @@
         return;
     }
 
-    /*
-     * Make callback if present
-     */
-    if (obj->track_info.delete_cb != NULL) {
-        obj->track_info.delete_cb(obj);
-    }
-
-    if (obj->wire_object.owned) {
-        of_wire_buffer_free(obj->wire_object.wbuf);
+    if (obj->parent == NULL) {
+        of_wire_buffer_free(obj->wbuf);
     }
 
     FREE(obj);
@@ -121,13 +113,11 @@
     MEMSET(dst, 0, sizeof(*dst));
 
     /* Allocate a minimal wire buffer assuming we will not write to it. */
-    if ((dst->wire_object.wbuf = of_wire_buffer_new(src->length)) == NULL) {
+    if ((dst->wbuf = of_wire_buffer_new(src->length)) == NULL) {
         FREE(dst);
         return NULL;
     }
 
-    dst->wire_object.owned = 1;
-
     init_fn = of_object_init_map[src->object_id];
     init_fn(dst, src->version, src->length, 0);
 
@@ -211,7 +201,7 @@
     }
 
     obj->version = version;
-    obj->wire_object.wbuf = wbuf;
+    obj->wbuf = wbuf;
     wbuf->buf = msg;
     wbuf->alloc_bytes = len;
     wbuf->current_bytes = len;
@@ -239,23 +229,18 @@
 of_object_buffer_bind(of_object_t *obj, uint8_t *buf, int bytes, 
                       of_buffer_free_f buf_free)
 {
-    of_wire_object_t *wobj;
     of_wire_buffer_t *wbuf;
 
     LOCI_ASSERT(buf != NULL);
     LOCI_ASSERT(bytes > 0);
-    // LOCI_ASSERT(wobj is not bound);
-
-    wobj = &obj->wire_object;
-    MEMSET(wobj, 0, sizeof(*wobj));
 
     wbuf = of_wire_buffer_new_bind(buf, bytes, buf_free);
     if (wbuf == NULL) {
         return OF_ERROR_RESOURCE;
     }
 
-    wobj->wbuf = wbuf;
-    wobj->owned = 1;
+    obj->wbuf = wbuf;
+    obj->obj_offset = 0;
     obj->length = bytes;
 
     return OF_ERROR_NONE;
@@ -291,17 +276,14 @@
 object_child_attach(of_object_t *parent, of_object_t *child, 
                        int offset, int bytes)
 {
-    of_wire_object_t *c_wobj; /* Pointer to child's wire object */
     of_wire_buffer_t *wbuf; /* Pointer to common wire buffer manager */
 
     child->parent = parent;
-    wbuf = parent->wire_object.wbuf;
+    wbuf = parent->wbuf;
 
     /* Set up the child's wire buf to point to same as parent */
-    c_wobj = &child->wire_object;
-    c_wobj->wbuf = wbuf;
-    c_wobj->obj_offset = parent->wire_object.obj_offset + offset;
-    c_wobj->owned = 0;
+    child->wbuf = wbuf;
+    child->obj_offset = parent->obj_offset + offset;
 
     /*
      * bytes determines if this is a read or write setup.
@@ -312,7 +294,7 @@
         int tot_bytes; /* Total bytes to request for buffer if updated */
 
         /* Set up space for the child in the parent's buffer */
-        tot_bytes = parent->wire_object.obj_offset + offset + bytes;
+        tot_bytes = parent->obj_offset + offset + bytes;
 
         of_wire_buffer_grow(wbuf, tot_bytes);
         child->length = bytes;
@@ -331,7 +313,7 @@
 of_object_can_grow(of_object_t *obj, int new_len)
 {
     return OF_OBJECT_ABSOLUTE_OFFSET(obj, new_len) <=
-        WBUF_ALLOC_BYTES(obj->wire_object.wbuf);
+        WBUF_ALLOC_BYTES(obj->wbuf);
 }
 
 /**
@@ -405,7 +387,7 @@
 of_list_append_bind(of_object_t *parent, of_object_t *child)
 {
     if (parent == NULL || child == NULL ||
-           parent->wire_object.wbuf == NULL) {
+           parent->wbuf == NULL) {
         return OF_ERROR_PARAM;
     }
 
@@ -417,13 +399,8 @@
                         child->length);
 
     /* Update the wire length and type if needed */
-    if (child->wire_length_set) {
-        child->wire_length_set(child, child->length);
-    }
-
-    if (child->wire_type_set) {
-        child->wire_type_set(child);
-    }
+    of_object_wire_length_set(child, child->length);
+    of_object_wire_type_set(child);
 
     /* Update the parent's length */
     of_object_parent_length_update(parent, child->length);
@@ -452,7 +429,7 @@
         return OF_ERROR_RESOURCE;
     }
 
-    of_wire_buffer_grow(list->wire_object.wbuf,
+    of_wire_buffer_grow(list->wbuf,
                         OF_OBJECT_ABSOLUTE_OFFSET(list, new_len));
 
     MEMCPY(OF_OBJECT_BUFFER_INDEX(list, list->length),
@@ -503,8 +480,8 @@
 static int
 of_list_is_last(of_object_t *parent, of_object_t *child)
 {
-    if (child->wire_object.obj_offset + child->length >= 
-        parent->wire_object.obj_offset + parent->length) {
+    if (child->obj_offset + child->length >=
+        parent->obj_offset + parent->length) {
         return 1;
     }
 
@@ -538,7 +515,7 @@
     }
 
     /* Offset is relative to parent start */
-    offset = (child->wire_object.obj_offset - parent->wire_object.obj_offset) +
+    offset = (child->obj_offset - parent->obj_offset) +
         child->length;
     object_child_attach(parent, child, offset, 0);
 
@@ -549,8 +526,8 @@
 of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
 {
     LOCI_ASSERT(obj != NULL);
-    of_wire_buffer_steal(obj->wire_object.wbuf, buffer);
-    obj->wire_object.wbuf = NULL;
+    of_wire_buffer_steal(obj->wbuf, buffer);
+    obj->wbuf = NULL;
 }
 
 #define _MAX_PARENT_ITERATIONS 4
@@ -575,18 +552,16 @@
     while (obj != NULL) {
         LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
         obj->length += delta;
-        if (obj->wire_length_set != NULL) {
-            obj->wire_length_set(obj, obj->length);
-        }
+        of_object_wire_length_set(obj, obj->length);
 #ifndef NDEBUG
-        wbuf = obj->wire_object.wbuf;
+        wbuf = obj->wbuf;
 #endif
 
         /* Asserts for wire length checking */
-        LOCI_ASSERT(obj->length + obj->wire_object.obj_offset <=
+        LOCI_ASSERT(obj->length + obj->obj_offset <=
                WBUF_CURRENT_BYTES(wbuf));
         if (obj->parent == NULL) {
-            LOCI_ASSERT(obj->length + obj->wire_object.obj_offset ==
+            LOCI_ASSERT(obj->length + obj->obj_offset ==
                    WBUF_CURRENT_BYTES(wbuf));
         }
 
@@ -612,9 +587,9 @@
 of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
                     int max_len)
 {
-    if (obj->wire_type_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t id;
-        obj->wire_type_get(obj, &id);
+        loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
         if (!of_wire_id_valid(id, base_object_id)) {
             return OF_ERROR_PARSE;
         }
@@ -622,9 +597,9 @@
         /* Call the init function for this object type; do not push to wire */
         of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
     }
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
-        obj->wire_length_get(obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
         if (length < 0 || (max_len > 0 && length > max_len)) {
             return OF_ERROR_PARSE;
         }
@@ -665,8 +640,8 @@
 
     d_wbuf = OF_OBJECT_TO_WBUF(dst);
     s_wbuf = OF_OBJECT_TO_WBUF(src);
-    dst_offset = dst->wire_object.obj_offset + dst_length;
-    src_offset = src->wire_object.obj_offset;
+    dst_offset = dst->obj_offset + dst_length;
+    src_offset = src->obj_offset;
     OF_WIRE_BUFFER_INIT_CHECK(d_wbuf, dst_offset + src->length);
     MEMCPY(OF_WBUF_BUFFER_POINTER(d_wbuf, dst_offset),
            OF_WBUF_BUFFER_POINTER(s_wbuf, 0), src->length);
@@ -685,7 +660,7 @@
 of_packet_out_actions_length_set(of_packet_t *obj, int len)
 {
     if (obj == NULL || obj->object_id != OF_PACKET_IN ||
-        obj->wire_object.wbuf == NULL) {
+        obj->wbuf == NULL) {
         return OF_ERROR_PARAM;
     }
 
@@ -696,7 +671,7 @@
 _packet_out_data_offset_get(of_packet_t *obj)
 {
     if (obj == NULL || obj->object_id != OF_PACKET_IN ||
-        obj->wire_object.wbuf == NULL) {
+        obj->wbuf == NULL) {
         return -1;
     }
 
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index 3172ad1..d299537 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -48,30 +48,6 @@
 #include <loci/of_message.h>
 #include <loci/of_wire_buf.h>
 
-/**
- * This is the number of bytes reserved for metadata in each
- * of_object_t instance.
- */
-#define OF_OBJECT_METADATA_BYTES 32
-
-/*
- * Generic accessors:
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * FIXME: TBD if wire_length_set and wire_type_set are required.
- */
-typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
-typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
-typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
-typedef void (*of_wire_type_set_f)(of_object_t *obj);
-
 /****************************************************************
  * General list operations: first, next, append_setup, append_advance
  ****************************************************************/
@@ -91,16 +67,6 @@
 extern of_object_t *of_object_new(int bytes);
 extern of_object_t *of_object_dup(of_object_t *src);
 
-/**
- * Callback function prototype for deleting an object
- */
-typedef void (*of_object_delete_callback_f)(of_object_t *obj);
-
-typedef struct of_object_track_info_s {
-    of_object_delete_callback_f delete_cb;  /* To be implemented */
-    void *delete_cookie;
-} of_object_track_info_t;
-
 extern int of_object_xid_set(of_object_t *obj, uint32_t xid);
 extern int of_object_xid_get(of_object_t *obj, uint32_t *xid);
 
@@ -135,8 +101,13 @@
 void of_object_parent_length_update(of_object_t *obj, int delta);
 
 struct of_object_s {
-    /* The control block for the underlying data buffer */
-    of_wire_object_t wire_object;
+    /** A pointer to the underlying buffer's management structure. */
+    of_wire_buffer_t *wbuf;
+
+    /** The start offset for this object relative to the start of the
+     * underlying buffer */
+    int obj_offset;
+
     /* The LOCI type enum value of the object */
     of_object_id_t object_id;
 
@@ -154,24 +125,6 @@
      */
     int length;
     of_version_t version;
-
-    /*
-     * Many objects have a length and/or type represented in the wire buffer
-     * These accessors get and set those value when present.  Treat as private.
-     */
-    of_wire_length_get_f wire_length_get;
-    of_wire_length_set_f wire_length_set;
-    of_wire_type_get_f wire_type_get;
-    of_wire_type_set_f wire_type_set;
-
-    of_object_track_info_t track_info;
-
-    /*
-     * Metadata available for applications.  Ensure 8-byte alignment, but
-     * that buffer is at least as large as requested.  This data is not used
-     * or inspected by LOCI.
-     */
-    uint64_t metadata[(OF_OBJECT_METADATA_BYTES + 7) / 8];
 };
 
 struct of_object_storage_s {
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index ec65098..dfec5c3 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -62,21 +62,6 @@
     of_buffer_free_f free;
 } of_wire_buffer_t;
 
-/**
- * Decouples object from underlying wire buffer
- *
- * Called a 'slice' in some places.
- */
-typedef struct of_wire_object_s {
-    /** A pointer to the underlying buffer's management structure. */
-    of_wire_buffer_t *wbuf;  
-    /** The start offset for this object relative to the start of the
-     * underlying buffer */
-    int obj_offset;
-    /* Boolean, whether the object owns the wire buffer. */
-    char owned;
-} of_wire_object_t;
-
 #define WBUF_BUF(wbuf) (wbuf)->buf
 #define WBUF_ALLOC_BYTES(wbuf) (wbuf)->alloc_bytes
 #define WBUF_CURRENT_BYTES(wbuf) (wbuf)->current_bytes
@@ -104,15 +89,6 @@
  */
 #define OF_WIRE_BUFFER_INDEX(wbuf, offset) (&((WBUF_BUF(wbuf))[offset]))
 
-/**
- * Return a pointer to a particular offset in the underlying buffer
- * associated with a wire object
- * @param wobj Pointer to an of_wire_object_t structure
- * @param offset The location to reference relative to the start of the object
- */
-#define OF_WIRE_OBJECT_INDEX(wobj, offset) \
-    OF_WIRE_BUFFER_INDEX((wobj)->wbuf, (offset) + (wobj)->obj_offset)
-
 /****************************************************************
  * Object specific macros; of_object_t includes a wire_object
  ****************************************************************/
@@ -124,7 +100,7 @@
  * @param offset The location to reference relative to the start of the object
  */
 #define OF_OBJECT_BUFFER_INDEX(obj, offset) \
-    OF_WIRE_OBJECT_INDEX(&((obj)->wire_object), offset)
+    OF_WIRE_BUFFER_INDEX((obj)->wbuf, (obj)->obj_offset + offset)
 
 /**
  * Return the absolute offset as an integer from a object-relative offset
@@ -132,7 +108,7 @@
  * @param offset The location to reference relative to the start of the object
  */
 #define OF_OBJECT_ABSOLUTE_OFFSET(obj, offset) \
-    ((obj)->wire_object.obj_offset + offset)
+    ((obj)->obj_offset + offset)
 
 
 /**
@@ -140,7 +116,7 @@
  *
  * Treat as private
  */
-#define OF_OBJECT_TO_WBUF(obj) ((obj)->wire_object.wbuf)
+#define OF_OBJECT_TO_WBUF(obj) ((obj)->wbuf)
 
 
 
diff --git a/lang_c.py b/lang_c.py
index 0a881e9..037c1d7 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -131,3 +131,4 @@
     c_gen.codegen.generate_strings(install_dir)
     c_gen.codegen.generate_init_map(install_dir)
     c_gen.codegen.generate_type_maps(install_dir)
+    c_gen.codegen.generate_class_metadata(install_dir)