Merge branch 'master' of github.com:floodlight/loxigen
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/build_of_g.py b/c_gen/build_of_g.py
index 46aedda..f117bfd 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -317,8 +317,6 @@
         version_name = of_g.of_version_wire2name[wire_version]
 
         for ofclass in protocol.classes:
-            if ofclass.name in ("of_group_add", "of_group_modify", "of_group_delete"):
-                continue
             of_g.ordered_classes[wire_version].append(ofclass.name)
             legacy_members = []
             pad_count = 0
@@ -417,9 +415,6 @@
                 continue
             if type_maps.class_is_virtual(cls):
                 continue
-            # HACK hide of_group subclasses from legacy c backend
-            if ofclass.name in ("of_group_add", "of_group_modify", "of_group_delete"):
-                continue
             subcls = cls[3:]
             val = find_type_value(ofclass, 'type')
             if not val in type_maps.message_types[wire_version].values():
@@ -448,28 +443,6 @@
                 of_g.ordered_classes[wire_version].append(new_cls)
                 classes[new_cls] = classes[cls]
 
-    # Generate action_id classes for OF 1.3
-    for wire_version, ordered_classes in of_g.ordered_classes.items():
-        if not wire_version in [of_g.VERSION_1_3]:
-            continue
-        classes = versions[of_g.of_version_wire2name[wire_version]]['classes']
-        for cls in ordered_classes:
-            if not loxi_utils.class_is_action(cls):
-                continue
-            action = cls[10:]
-            if action == '' or action == 'header':
-                continue
-            name = "of_action_id_" + action
-            members = classes["of_action"][:]
-            of_g.ordered_classes[wire_version].append(name)
-            if type_maps.action_id_is_extension(name, wire_version):
-                # Copy the base action classes thru subtype
-                members = classes["of_action_" + action][:4]
-            classes[name] = members
-
-    # @fixme If we support extended actions in OF 1.3, need to add IDs
-    # for them here
-
     for wire_version in of_g.wire_ver_map.keys():
         version_name = of_g.of_version_wire2name[wire_version]
         calculate_offsets_and_lengths(
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index e2bb467..78a809e 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -36,7 +36,7 @@
 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
 
@@ -63,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):
@@ -425,32 +413,49 @@
                                     of_match_t *match);
 extern int of_wire_buffer_of_match_set(of_object_t *obj, int offset,
                                     of_match_t *match, int cur_len);
-extern void of_extension_object_id_set(of_object_t *obj, of_object_id_t id);
 """)
 
     # gen_base_types(out)
 
-    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);
+of_object_id_t of_bsn_tlv_to_object_id(int tlv_type, of_version_t version);
+
+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,324 +490,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"
-
-""")
-    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
 ################################################################
@@ -1011,6 +698,11 @@
     uint64_t lo;
 } of_bitmap_128_t;
 
+typedef struct of_checksum_128_s {
+    uint64_t hi;
+    uint64_t lo;
+} of_checksum_128_t;
+
 /* These are types which change across versions.  */
 typedef uint32_t of_port_no_t;
 typedef uint16_t of_fm_cmd_t;
@@ -1101,7 +793,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>
 
 /****************************************************************
  *
@@ -1121,51 +813,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;
-    }
-}
-""")
-
 ################################################################
 #
 ################################################################
@@ -1322,63 +969,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
@@ -1410,8 +1000,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]
 
@@ -1547,11 +1135,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("""
 /****************************************************************
@@ -1566,47 +1151,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
@@ -1687,51 +1231,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
@@ -2051,7 +1550,7 @@
         m_type = "octets_data"
     return "of_wire_buffer_%s_%s" % (m_type, a_type)
 
-def get_len_macro(cls, m_type, version):
+def get_len_macro(cls, m_name, m_type, version):
     """
     Get the length macro for m_type in cls
     """
@@ -2063,6 +1562,12 @@
         return "_TLV16_LEN(obj, offset)"
     if cls == "of_packet_out" and m_type == "of_list_action_t":
         return "_PACKET_OUT_ACTION_LEN(obj)"
+    if cls == "of_bsn_gentable_entry_add" and m_name == "key":
+        return "of_object_u16_get(obj, 18)"
+    if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
+        return "of_object_u16_get(obj, 2)"
+    if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
+        return "of_object_u16_get(obj, 2)"
     # Default is everything to the end of the object
     return "_END_LEN(obj, offset)"
 
@@ -2089,6 +1594,12 @@
             pass
         elif (cls == "of_packet_out" and m_name == "data"):
             pass
+        elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
+            pass
+        elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
+            pass
+        elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
+            pass
         else:
             debug("Error: Unknown member with offset == -1")
             debug("  cls %s, m_name %s, version %d" % (cls, m_name, version))
@@ -2103,7 +1614,7 @@
     if not loxi_utils.type_is_scalar(m_type):
         if loxi_utils.class_is_var_len(m_type[:-2], version) or \
                 m_type == "of_match_t":
-            len_macro = get_len_macro(cls, m_type, version)
+            len_macro = get_len_macro(cls, m_name, m_type, version)
         else:
             len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
         out.write("        cur_len = %s;\n" % len_macro)
@@ -2219,6 +1730,16 @@
     /* Special case for setting action lengths */
     _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
 """ % dict(m_name=m_name))
+        elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
+            out.write("""
+    /* Special case for setting key length */
+    of_object_u16_set(obj, 18, %(m_name)s->length);
+""" % dict(m_name=m_name))
+        elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
+            out.write("""
+    /* Special case for setting key length */
+    of_object_u16_set(obj, 2, %(m_name)s->length);
+""" % dict(m_name=m_name))
         elif m_type not in ["of_match_t", "of_octets_t"]:
             out.write("""
     /* @fixme Shouldn't this precede copying value's data to buffer? */
@@ -2408,28 +1929,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
@@ -2470,96 +1970,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, of_object_id_t id);
-""")
-    # 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
@@ -2580,21 +1990,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
 ################################################################
@@ -2687,62 +2082,30 @@
 {
 """ % dict(cls=cls))
 
+    import loxi_globals
+    uclass = loxi_globals.unified.class_by_name(cls)
+    if uclass and not uclass.virtual and uclass.has_type_members:
+        out.write("""
+    %(cls)s_push_wire_types(obj);
+""" % dict(cls=cls))
+
     if loxi_utils.class_is_message(cls):
         out.write("""
-    /* Message obj; push version, length and type to wire */
+    /* Message obj; set length */
     of_message_t msg;
 
     if ((msg = OF_OBJECT_TO_MESSAGE(obj)) != NULL) {
-        of_message_version_set(msg, obj->version);
         of_message_length_set(msg, obj->length);
-        OF_TRY(of_wire_message_object_id_set(OF_OBJECT_TO_WBUF(obj),
-                 %(name)s));
     }
 """ % dict(name = enum_name(cls)))
 
-        for version in of_g.of_version_range:
-            if type_maps.class_is_extension(cls, version):
-                exp_name = type_maps.extension_to_experimenter_macro_name(cls)
-                subtype = type_maps.extension_message_to_subtype(cls, version)
-                if subtype is None or exp_name is None:
-                    print "Error in mapping extension message"
-                    print cls, version
-                    sys.exit(1)
-                out.write("""
-    if (obj->version == %(version)s) {
-        of_message_experimenter_id_set(OF_OBJECT_TO_MESSAGE(obj),
-                                       %(exp_name)s);
-        of_message_experimenter_subtype_set(OF_OBJECT_TO_MESSAGE(obj),
-                                            %(subtype)s);
-    }
-""" % dict(exp_name=exp_name, version=of_g.wire_ver_map[version],
-           subtype=str(subtype)))
-
     else: # Not a message
         if loxi_utils.class_is_tlv16(cls):
             out.write("""
-    /* TLV obj; set length and type */
+    /* TLV obj; set length */
     of_tlv16_wire_length_set((of_object_t *)obj, obj->length);
-    of_tlv16_wire_object_id_set((of_object_t *)obj,
-           %(enum)s);
 """ % dict(enum=enum_name(cls)))
-            # Some tlv16 types may be extensions requiring more work
-            if cls in ["of_action_bsn_mirror", "of_action_id_bsn_mirror",
-                       "of_action_bsn_set_tunnel_dst", "of_action_id_bsn_set_tunnel_dst",
-                       "of_action_nicira_dec_ttl", "of_action_id_nicira_dec_ttl",
-                       "of_instruction_bsn_disable_src_mac_check"]:
-                out.write("""
-    /* Extended TLV obj; Call specific accessor */
-    of_extension_object_id_set(obj, %(enum)s);
-""" % dict(cls=cls, enum=enum_name(cls)))
 
-
-        if loxi_utils.class_is_oxm(cls):
-            out.write("""\
-    /* OXM obj; set length and type */
-    of_oxm_wire_length_set((of_object_t *)obj, obj->length);
-    of_oxm_wire_object_id_set((of_object_t *)obj, %(enum)s);
-""" % dict(enum=enum_name(cls)))
         if loxi_utils.class_is_u16_len(cls) or cls == "of_packet_queue":
             out.write("""
     obj->wire_length_set((of_object_t *)obj, obj->length);
@@ -2791,7 +2154,7 @@
  */
 
 %(cls)s_t *
-%(cls)s_new_(of_version_t version)
+%(cls)s_new(of_version_t version)
 {
     %(cls)s_t *obj;
     int bytes;
@@ -2826,25 +2189,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))
 
 
@@ -2865,7 +2209,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;
@@ -2894,25 +2238,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))
 
 
@@ -2942,58 +2267,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);
@@ -3050,6 +2332,12 @@
     /* Set up the object's function pointers */
 """)
 
+    uclass = loxi_globals.unified.class_by_name(cls)
+    if uclass and not uclass.virtual and uclass.has_type_members:
+        out.write("""
+    obj->wire_type_set = %(cls)s_push_wire_types;
+""" % dict(cls=cls))
+
     if loxi_utils.class_is_message(cls):
         out.write("""
     obj->wire_length_get = of_object_message_wire_length_get;
@@ -3060,7 +2348,6 @@
             if not (cls in type_maps.inheritance_map): # Don't set for super
                 out.write("""
     obj->wire_length_set = of_tlv16_wire_length_set;
-    obj->wire_type_set = of_tlv16_wire_object_id_set;\
 """)
             out.write("""
     obj->wire_length_get = of_tlv16_wire_length_get;
@@ -3093,12 +2380,14 @@
                     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_length_set = of_oxm_wire_length_set;
     obj->wire_type_get = of_oxm_wire_object_id_get;
-    obj->wire_type_set = of_oxm_wire_object_id_set;
 """)
         if loxi_utils.class_is_u16_len(cls):
             out.write("""
@@ -3120,57 +2409,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
@@ -3438,232 +2687,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_test_gen.py b/c_gen/c_test_gen.py
index 83fa4a3..637819c 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -99,6 +99,7 @@
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
+        of_checksum_128_t="checksum_128",
         )
 
     if m_type.find("of_list_") == 0:
@@ -112,7 +113,7 @@
                  "of_match_bmap_t", "of_ipv4_t"]
 string_types = [ "of_port_name_t", "of_table_name_t",
                 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
-                "of_ipv6_t", "of_bitmap_128_t"]
+                "of_ipv6_t", "of_bitmap_128_t", "of_checksum_128_t"]
 
 scalar_types = integer_types[:]
 scalar_types.extend(string_types)
@@ -132,7 +133,21 @@
     classes = ["of_bsn_lacp_stats_request",
                "of_bsn_lacp_stats_reply",
                "of_bsn_switch_pipeline_stats_request",
-               "of_bsn_switch_pipeline_stats_reply"]
+               "of_bsn_switch_pipeline_stats_reply",
+               "of_bsn_port_counter_stats_request",
+               "of_bsn_port_counter_stats_reply",
+               "of_bsn_vlan_counter_stats_request",
+               "of_bsn_vlan_counter_stats_reply",
+               "of_bsn_gentable_entry_desc_stats_request",
+               "of_bsn_gentable_entry_desc_stats_reply",
+               "of_bsn_gentable_entry_stats_request",
+               "of_bsn_gentable_entry_stats_reply",
+               "of_bsn_gentable_desc_stats_request",
+               "of_bsn_gentable_desc_stats_reply",
+               "of_bsn_gentable_stats_request",
+               "of_bsn_gentable_stats_reply",
+               "of_bsn_gentable_bucket_stats_request",
+               "of_bsn_gentable_bucket_stats_reply"]
 
     if (cls in classes and (
             m_name == "experimenter" or
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 43cd4a8..d4525ba 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -39,133 +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, 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):
     """
@@ -232,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,
@@ -261,6 +132,9 @@
     gen_type_to_object_id(out, "hello_elem_type_to_id", "OF_HELLO_ELEM",
                           "OF_HELLO_ELEM_%s", type_maps.hello_elem_types,
                           max_type_value)
+    gen_type_to_object_id(out, "group_mod_type_to_id", "OF_GROUP_MOD",
+                          "OF_GROUP_%s", type_maps.group_mod_types,
+                          max_type_value)
 
     # FIXME:  Multipart re-organization
     gen_type_to_object_id(out, "stats_request_type_to_id", "OF_STATS_REQUEST",
@@ -277,15 +151,13 @@
     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)
-
+    gen_type_to_object_id(out, "bsn_tlv_type_to_id", "OF_BSN_TLV",
+                          "OF_BSN_TLV_%s", type_maps.bsn_tlv_types,
+                          max_type_value)
 
 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
     """
 
@@ -310,7 +182,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)) {
@@ -341,7 +213,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)) {
@@ -376,7 +248,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)) {
@@ -411,7 +283,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)) {
@@ -445,7 +317,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;
@@ -495,7 +367,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;
@@ -504,6 +376,7 @@
     uint16_t err_type;
     uint8_t flow_mod_cmd;
     uint32_t experimenter, subtype;
+    uint16_t group_mod_cmd;
 
     if (length < OF_MESSAGE_MIN_LENGTH) {
         return OF_OBJECT_INVALID;
@@ -570,6 +443,14 @@
         obj_id = of_error_msg_to_object_id(err_type, ver);
     }
 
+    if (obj_id == OF_GROUP_MOD) {
+        if (length < OF_MESSAGE_MIN_GROUP_MOD_LENGTH) {
+            return OF_OBJECT_INVALID;
+        }
+        group_mod_cmd = of_message_group_mod_command_get(msg);
+        obj_id = of_group_mod_to_object_id(group_mod_cmd, ver);
+    }
+
     return obj_id;
 }
 """
@@ -592,7 +473,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)) {
@@ -692,6 +573,11 @@
     out.write(map_template %
               dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
 
+    ar_len = type_maps.type_array_len(type_maps.group_mod_types,
+                                      max_type_value)
+    out.write(map_template %
+              dict(name="group_mod", u_name="GROUP_MOD", ar_len=ar_len))
+
     # OXM
     ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
     out.write("""
@@ -706,402 +592,11 @@
     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 */
-}
-
-""")
-
-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;
-}
-
-""")
-
-    # Generate the function that sets the object type fields
-    out.write("""
-
-/**
- * Map a message in a wire buffer object to its OF object id.
- * @param wbuf Pointer to a wire buffer object, populated with an OF message
- * @returns The object ID of the message
- * @returns OF_OBJECT_INVALID if unable to parse the message type
- *
- * Version must be set in the buffer prior to calling this routine
- */
-
-static inline int
-of_wire_message_object_id_set(of_wire_buffer_t *wbuf, of_object_id_t id)
-{
-    int type;
-    of_version_t ver;
-    of_message_t msg;
-
-    msg = (of_message_t)WBUF_BUF(wbuf);
-
-    ver = of_message_version_get(msg);
-
-    /* ASSERT(id is a message object) */
-
-    if ((type = of_object_to_wire_type(id, ver)) < 0) {
-        return OF_ERROR_PARAM;
-    }
-    of_message_type_set(msg, type);
-
-    if ((type = of_object_to_stats_type(id, ver)) >= 0) {
-        /* It's a stats obj */
-        of_message_stats_type_set(msg, type);
-        if (type == OF_STATS_TYPE_EXPERIMENTER) {
-            switch (id) {
-            case OF_BSN_LACP_STATS_REQUEST:
-            case OF_BSN_LACP_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 1);
-                break;
-            case OF_BSN_SWITCH_PIPELINE_STATS_REQUEST:
-            case OF_BSN_SWITCH_PIPELINE_STATS_REPLY:
-                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
-                of_message_stats_experimenter_subtype_set(msg, 6);
-                break;
-            default:
-                break;
-            }
-        }
-    }
-    if ((type = of_object_to_error_type(id, ver)) >= 0) {
-        /* It's an error obj */
-        of_message_error_type_set(msg, type);
-    }
-    if ((type = of_object_to_flow_mod_command(id, ver)) >= 0) {
-        /* It's a flow mod obj */
-        of_message_flow_mod_command_set(msg, ver, type);
-    }
-    if (of_object_id_is_extension(id, ver)) {
-        uint32_t val32;
-
-        /* Set the experimenter and subtype codes */
-        val32 = of_extension_to_experimenter_id(id, ver);
-        of_message_experimenter_id_set(msg, val32);
-        val32 = of_extension_to_experimenter_subtype(id, ver);
-        of_message_experimenter_subtype_set(msg, val32);
-    }
-
-    return OF_ERROR_NONE;
-}
-""")
+    # BSN TLV elem types array gen
+    ar_len = type_maps.type_array_len(type_maps.bsn_tlv_types,
+                                      max_type_value)
+    out.write(map_template %
+              dict(name="bsn_tlv", u_name="BSN_TLV", ar_len=ar_len))
 
 def gen_type_data_header(out):
 
@@ -1172,15 +667,11 @@
 extern void of_object_message_wire_length_set(of_object_t *obj, int bytes);
 
 extern void of_oxm_wire_length_get(of_object_t *obj, int *bytes);
-extern void of_oxm_wire_length_set(of_object_t *obj, int bytes);
 extern void of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
-extern void of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id);
 
 extern void of_tlv16_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_tlv16_wire_length_set(of_object_t *obj, int bytes);
 
-extern void of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id);
-
 /* Wire length is uint16 at front of structure */
 extern void of_u16_len_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_u16_len_wire_length_set(of_object_t *obj, int bytes);
@@ -1197,6 +688,8 @@
     of_object_id_t *id);
 extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
     of_object_id_t *id);
+extern void of_bsn_tlv_wire_object_id_get(of_object_t *obj,
+    of_object_id_t *id);
 
 #define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
 #define OF_OXM_LENGTH_SET(hdr, val)                         \\
@@ -1294,45 +787,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/c_validator_gen.py b/c_gen/c_validator_gen.py
index 126530a..9bb0407 100644
--- a/c_gen/c_validator_gen.py
+++ b/c_gen/c_validator_gen.py
@@ -222,6 +222,12 @@
         %(m_name)s_offset = %(match_offset)s + OF_MATCH_BYTES(match_len);
         %(m_name)s_len = len - %(m_name)s_offset;
 """ % dict(m_name=m_name, cls=cls, match_offset=match_offset))
+        elif cls == "of_bsn_gentable_entry_add" and m_name == "value":
+            continue;
+        elif cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value":
+            continue;
+        elif cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats":
+            continue;
         else:
             out.write("""
 
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
new file mode 100644
index 0000000..3249747
--- /dev/null
+++ b/c_gen/codegen.py
@@ -0,0 +1,145 @@
+# Copyright 2013, Big Switch Networks, Inc.
+#
+# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+# the following special exception:
+#
+# LOXI Exception
+#
+# As a special exception to the terms of the EPL, you may distribute libraries
+# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+# that copyright and licensing notices generated by LoxiGen are not altered or removed
+# from the LoxiGen Libraries and the notice provided below is (i) included in
+# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+# documentation for the LoxiGen Libraries, if distributed in binary form.
+#
+# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+#
+# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+# a copy of the EPL at:
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# EPL for the specific language governing permissions and limitations
+# under the EPL.
+
+"""
+Code generation
+
+These functions extract data from the IR and render templates with it.
+"""
+
+from collections import namedtuple
+from itertools import groupby
+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
+
+PushWireTypesData = namedtuple('PushWireTypesData',
+    ['class_name', 'versioned_type_members'])
+PushWireTypesMember = namedtuple('PushWireTypesMember',
+    ['name', 'offset', 'length', 'value'])
+
+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:
+        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)
+
+def generate_classes_header(install_dir):
+    # Collect legacy code
+    tmp = StringIO()
+    c_code_gen.gen_struct_typedefs(tmp)
+    c_code_gen.gen_new_function_declarations(tmp)
+    c_code_gen.gen_accessor_declarations(tmp)
+    c_code_gen.gen_generics(tmp)
+
+    with template_utils.open_output(install_dir, "loci/inc/loci/loci_classes.h") as out:
+        util.render_template(out, "loci_classes.h",
+            legacy_code=tmp.getvalue())
+
+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)
+
+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_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 699006f..4092d4f 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -118,6 +118,8 @@
         return True
     if cls == "of_match_v4":
         return True
+    if cls.find("of_bsn_tlv") == 0:
+        return True
     return False
 
 def class_is_u16_len(cls):
@@ -125,7 +127,10 @@
     Return True if cls_name is an object which uses initial uint16 length
     """
     return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
-                   "of_flow_stats_entry", "of_bucket", "of_table_features"]
+                   "of_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"]
 
 def class_is_oxm(cls):
     """
@@ -179,6 +184,8 @@
     """
     Return True if cls_name is an instruction object
     """
+    if cls.find("of_instruction_id") == 0:
+        return False
     if cls.find("of_instruction") == 0:
         return True
 
@@ -243,6 +250,14 @@
     """
     return (cls.find("of_list_") == 0)
 
+def class_is_bsn_tlv(cls):
+    """
+    Return True if cls_name is a BSN TLV object
+    """
+    if cls.find("of_bsn_tlv") == 0:
+        return True
+    return False
+
 def type_is_of_object(m_type):
     """
     Return True if m_type is an OF object type
@@ -319,30 +334,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 adf5c2b..1fadba0 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,23 +74,10 @@
 # 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",
-                "type_len", "actions_len", "_command"]
+                "type_len", "actions_len", "_command", "command", "key_length"]
 
 ## Some OpenFlow string length constants
 #
@@ -228,53 +206,14 @@
 #                         short_name="match_v4"),
     of_octets_t = dict(bytes=-1, short_name="octets"),
     of_bitmap_128_t = dict(bytes=16, short_name="bitmap_128"),
+    of_checksum_128_t = dict(bytes=16, short_name="checksum_128"),
 )
 
 of_scalar_types = ["char", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
                    "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
                    "of_match_bmap_t", "of_port_name_t", "of_table_name_t",
                    "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
-                   "of_ipv6_t", "of_ipv4_t", "of_bitmap_128_t"]
-
-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];
-"""
+                   "of_ipv6_t", "of_ipv4_t", "of_bitmap_128_t", "of_checksum_128_t"]
 
 ##
 # LOXI identifiers
diff --git a/c_gen/templates/_pragmas.c b/c_gen/templates/_pragmas.c
new file mode 100644
index 0000000..cbdc350
--- /dev/null
+++ b/c_gen/templates/_pragmas.c
@@ -0,0 +1,50 @@
+:: # 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.
+::
+#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,6)
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+
+#endif
diff --git a/c_gen/templates/_push_wire_types.c b/c_gen/templates/_push_wire_types.c
new file mode 100644
index 0000000..b7b6288
--- /dev/null
+++ b/c_gen/templates/_push_wire_types.c
@@ -0,0 +1,53 @@
+:: # 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.
+::
+static void
+${data.class_name}_push_wire_types(of_object_t *obj)
+{
+    unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
+    switch (obj->version) {
+:: for ms, versions in data.versioned_type_members:
+:: for version in versions:
+    case ${version.constant_version(prefix='OF_VERSION_')}:
+:: #endfor
+:: for m in ms:
+:: if m.length == 1:
+        *(uint8_t *)(buf + ${m.offset}) = ${m.value}; /* ${m.name} */
+:: elif m.length == 2:
+        *(uint16_t *)(buf + ${m.offset}) = htobe16(${m.value}); /* ${m.name} */
+:: elif m.length == 4:
+        *(uint32_t *)(buf + ${m.offset}) = htobe32(${m.value}); /* ${m.name} */
+:: else:
+:: raise("unsupported push_wire_types length %d" % m.length)
+:: #endif
+:: #endfor
+        break;
+:: #endfor
+    default:
+        UNREACHABLE();
+    }
+}
diff --git a/c_gen/templates/class.c b/c_gen/templates/class.c
new file mode 100644
index 0000000..044e03e
--- /dev/null
+++ b/c_gen/templates/class.c
@@ -0,0 +1,37 @@
+:: # 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('_pragmas.c')
+
+#include "loci_log.h"
+#include "loci_int.h"
+
+:: if push_wire_types_data:
+:: include("_push_wire_types.c", data=push_wire_types_data)
+
+:: #endif
diff --git a/c_gen/templates/loci_classes.h b/c_gen/templates/loci_classes.h
new file mode 100644
index 0000000..3486055
--- /dev/null
+++ b/c_gen/templates/loci_classes.h
@@ -0,0 +1,35 @@
+:: # Copyright 2013, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # Unless required by applicable law or agreed to in writing, software
+:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.c')
+::
+#ifndef __LOCI_CLASSES_H__
+#define __LOCI_CLASSES_H__
+
+${legacy_code}
+
+#endif
diff --git a/c_gen/templates/loci_dump.h b/c_gen/templates/loci_dump.h
index d44832a..9cc719c 100644
--- a/c_gen/templates/loci_dump.h
+++ b/c_gen/templates/loci_dump.h
@@ -96,6 +96,8 @@
 
 #define LOCI_DUMP_bitmap_128(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_DUMP_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
+
 /**
  * Generic version for any object
  */
diff --git a/c_gen/templates/loci_init_map.c b/c_gen/templates/loci_init_map.c
new file mode 100644
index 0000000..dc4616d
--- /dev/null
+++ b/c_gen/templates/loci_init_map.c
@@ -0,0 +1,41 @@
+:: # 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"
+
+/**
+ * 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
+};
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index 87cfd1e..01ad4a8 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,254 @@
 #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))
+
+/**
+ * Macro to calculate variable offset of value member in of_bsn_gentable_entry_add
+ * @param obj An object of type of_bsn_gentable_entry_add_t
+ */
+
+#define _BSN_GENTABLE_ENTRY_ADD_VALUE_OFFSET(obj) \
+    (of_object_u16_get(obj, 18) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_ADD])
+
+#define _BSN_GENTABLE_ENTRY_DESC_STATS_ENTRY_VALUE_OFFSET(obj) \
+    (of_object_u16_get(obj, 2) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_DESC_STATS_ENTRY])
+
+#define _BSN_GENTABLE_ENTRY_STATS_ENTRY_STATS_OFFSET(obj) \
+    (of_object_u16_get(obj, 2) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_STATS_ENTRY])
+
 #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_show.h b/c_gen/templates/loci_show.h
index 70f18d5..1856ae5 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -164,6 +164,8 @@
 
 #define LOCI_SHOW_bitmap_128(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_SHOW_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
+
 /**
  * Generic version for any object
  */
@@ -236,7 +238,14 @@
 #define LOCI_SHOW_u32_supported(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
 #define LOCI_SHOW_u32_peer(writer, cookie, val) LOCI_SHOW_x32(writer, cookie, val)
 #define LOCI_SHOW_u64_rx_packets(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_rx_packets_unicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_rx_packets_multicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_rx_packets_broadcast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_uint64_value(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_u64_tx_packets(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_tx_packets_unicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_tx_packets_multicast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_u64_tx_packets_broadcast(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_u64_rx_bytes(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_u64_tx_bytes(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_u64_rx_dropped(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
@@ -364,5 +373,14 @@
 #define LOCI_SHOW_u16_partner_port_num(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
 #define LOCI_SHOW_u16_partner_key(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
 #define LOCI_SHOW_u64_time_ms(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_desc_str_uri(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
+#define LOCI_SHOW_u8_state(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u16_table_id(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
+#define LOCI_SHOW_u32_deleted_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_u32_error_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_checksum_128_checksum(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
+#define LOCI_SHOW_checksum_128_checksum_mask(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
+#define LOCI_SHOW_u32_buckets_size(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_u32_entry_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
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_message.h b/c_gen/templates/of_message.h
index c1b6785..df74231 100644
--- a/c_gen/templates/of_message.h
+++ b/c_gen/templates/of_message.h
@@ -48,11 +48,13 @@
 #define OF_MESSAGE_ERROR_TYPE_OFFSET 8
 #define OF_MESSAGE_STATS_TYPE_OFFSET 8
 #define OF_MESSAGE_FLOW_MOD_COMMAND_OFFSET(version) ((version) == 1 ? 56 : 25)
+#define OF_MESSAGE_GROUP_MOD_COMMAND_OFFSET 8
 
 #define OF_MESSAGE_MIN_LENGTH 8
 #define OF_MESSAGE_MIN_STATS_LENGTH (OF_MESSAGE_STATS_TYPE_OFFSET + 2)
 #define OF_MESSAGE_MIN_ERROR_LENGTH (OF_MESSAGE_ERROR_TYPE_OFFSET + 4)
 #define OF_MESSAGE_MIN_FLOW_MOD_LENGTH(version)  ((version) == 1 ? 57 : 26)
+#define OF_MESSAGE_MIN_GROUP_MOD_LENGTH (OF_MESSAGE_GROUP_MOD_COMMAND_OFFSET + 2)
 
 #define OF_MESSAGE_EXPERIMENTER_ID_OFFSET 8
 #define OF_MESSAGE_EXPERIMENTER_SUBTYPE_OFFSET 12
@@ -103,11 +105,6 @@
     return (of_version_t)msg[OF_MESSAGE_VERSION_OFFSET];
 }
 
-static inline void
-of_message_version_set(of_message_t msg, of_version_t version) {
-    buf_u8_set(msg, (uint8_t)version);
-}
-
 /**
  * @brief Get/set OpenFlow type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -120,11 +117,6 @@
     return msg[OF_MESSAGE_TYPE_OFFSET];
 }
 
-static inline void
-of_message_type_set(of_message_t msg, uint8_t value) {
-    buf_u8_set(msg + OF_MESSAGE_TYPE_OFFSET, value);
-}
-
 /**
  * @brief Get/set in-buffer length of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -159,11 +151,6 @@
     return val;
 }
 
-static inline void
-of_message_xid_set(of_message_t msg, uint32_t xid) {
-    buf_u32_set(msg + OF_MESSAGE_XID_OFFSET, xid);
-}
-
 /**
  * @brief Get/set stats type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -178,11 +165,6 @@
     return val;
 }
 
-static inline void
-of_message_stats_type_set(of_message_t msg, uint16_t type) {
-    buf_u16_set(msg + OF_MESSAGE_STATS_TYPE_OFFSET, type);
-}
-
 /**
  * @brief Get/set error type of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -197,11 +179,6 @@
     return val;
 }
 
-static inline void
-of_message_error_type_set(of_message_t msg, uint16_t type) {
-    buf_u16_set(msg + OF_MESSAGE_ERROR_TYPE_OFFSET, type);
-}
-
 
 /**
  * @brief Get/set experimenter ID of a message
@@ -217,11 +194,6 @@
     return val;
 }
 
-static inline void
-of_message_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
-    buf_u32_set(msg + OF_MESSAGE_EXPERIMENTER_ID_OFFSET, experimenter_id);
-}
-
 
 /**
  * @brief Get/set experimenter message type (subtype) of a message
@@ -237,13 +209,6 @@
     return val;
 }
 
-static inline void
-of_message_experimenter_subtype_set(of_message_t msg,
-                                    uint32_t subtype) {
-    buf_u32_set(msg + OF_MESSAGE_EXPERIMENTER_SUBTYPE_OFFSET,
-                subtype);
-}
-
 /**
  * Flow mod command changed from 16 to 8 bits on the wire from 1.0 to 1.1
  */
@@ -261,19 +226,6 @@
     return val8;
 }
 
-static inline void
-of_message_flow_mod_command_set(of_message_t msg, of_version_t version, 
-                                uint8_t command) {
-    uint16_t val16;
-
-    if (version == OF_VERSION_1_0) {
-        val16 = command;
-        buf_u16_set(msg + OF_MESSAGE_FLOW_MOD_COMMAND_OFFSET(version), val16);
-    } else {
-        buf_u8_set(msg + OF_MESSAGE_FLOW_MOD_COMMAND_OFFSET(version), command);
-    }
-}
-
 /**
  * @brief Get/set stats request/reply experimenter ID of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -288,11 +240,6 @@
     return val;
 }
 
-static inline void
-of_message_stats_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
-    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, experimenter_id);
-}
-
 /**
  * @brief Get/set stats request/reply experimenter subtype of a message
  * @param msg Pointer to the message buffer of sufficient length
@@ -307,9 +254,18 @@
     return val;
 }
 
-static inline void
-of_message_stats_experimenter_subtype_set(of_message_t msg, uint32_t subtype) {
-    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, subtype);
+/**
+ * @brief Get/set group mod command of a message
+ * @param msg Pointer to the message buffer of sufficient length
+ * @param subtype Data for set operation
+ * @returns get returns command in host order
+ */
+
+static inline uint16_t
+of_message_group_mod_command_get(of_message_t msg) {
+    uint16_t val;
+    buf_u16_get(msg + OF_MESSAGE_GROUP_MOD_COMMAND_OFFSET, &val);
+    return val;
 }
 
 #endif /* _OF_MESSAGE_H_ */
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 0b3ec3a..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;
 }
 
@@ -510,7 +379,7 @@
     }
 
     if (child->wire_type_set) {
-        child->wire_type_set(child, child->object_id);
+        child->wire_type_set(child);
     }
 
     /* Update the parent's length */
@@ -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 fa3e05c..69c4154 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
  ****************************************************************/
@@ -139,30 +141,6 @@
 }
 
 /**
- * Set the object ID based on the wire buffer for any TLV object
- * @param obj The object being referenced
- * @param id The ID value representing what should be stored.
- */
-
-void
-of_tlv16_wire_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    int wire_type;
-    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
-
-    wire_type = of_object_to_type_map[obj->version][id];
-    ASSERT(wire_type >= 0);
-
-    of_wire_buffer_u16_set(wbuf, 
-        OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_TYPE_OFFSET), wire_type);
-
-    if (wire_type == OF_EXPERIMENTER_TYPE) {
-        of_extension_object_id_set(obj, id);
-    }
-}
-
-/**
  * Get the object ID of an extended action
  * @param obj The object being referenced
  * @param id Where to store the object ID
@@ -209,44 +187,6 @@
 }
 
 /**
- * Set wire data for extension objects, not messages.
- */
-
-void
-of_extension_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    uint8_t *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
-    
-    switch (id) {
-    case OF_ACTION_BSN_MIRROR:
-    case OF_ACTION_ID_BSN_MIRROR:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 1);
-        break;
-    case OF_ACTION_BSN_SET_TUNNEL_DST:
-    case OF_ACTION_ID_BSN_SET_TUNNEL_DST:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 2);
-        break;
-    case OF_ACTION_NICIRA_DEC_TTL:
-    case OF_ACTION_ID_NICIRA_DEC_TTL:
-        buf_u32_set(buf + OF_ACTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_NICIRA);
-        buf_u16_set(buf + OF_ACTION_EXPERIMENTER_SUBTYPE_OFFSET, 18);
-        break;
-    case OF_INSTRUCTION_BSN_DISABLE_SRC_MAC_CHECK:
-        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET,
-                    OF_EXPERIMENTER_ID_BSN);
-        buf_u32_set(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, 0);
-        break;
-    default:
-        break;
-    }
-}
-
-/**
  * Get the object ID of an extended action
  * @param obj The object being referenced
  * @param id Where to store the object ID
@@ -360,6 +300,7 @@
         buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, &subtype);
         switch (subtype) {
         case 0: *id = OF_INSTRUCTION_BSN_DISABLE_SRC_MAC_CHECK; break;
+        case 1: *id = OF_INSTRUCTION_BSN_ARP_OFFLOAD; break;
         }
         break;
     }
@@ -506,6 +447,23 @@
     ASSERT(*id != OF_OBJECT_INVALID);
 }
 
+/**
+ * Get the object ID based on the wire buffer for a bsn_tlv object
+ * @param obj The object being referenced
+ * @param id Where to store the object ID
+ */
+
+void
+of_bsn_tlv_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+    int wire_type;
+
+    of_tlv16_wire_type_get(obj, &wire_type);
+    ASSERT(wire_type >= 0 && wire_type < OF_BSN_TLV_ITEM_COUNT);
+    *id = of_bsn_tlv_type_to_id[obj->version][wire_type];
+    ASSERT(*id != OF_OBJECT_INVALID);
+}
+
 /****************************************************************
  * OXM type/length functions.
  ****************************************************************/
@@ -551,27 +509,6 @@
 }
 
 /**
- * Set the length of an OXM object in the wire buffer
- * @param obj The object whose wire buffer is an OXM type
- * @param bytes Value to store in wire buffer
- */
-
-void
-of_oxm_wire_length_set(of_object_t *obj, int bytes)
-{
-    uint32_t type_len;
-    of_wire_buffer_t *wbuf;
-
-    ASSERT(bytes >= 0 && bytes < 256);
-
-    /* Read-modify-write */
-    _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-    OF_OXM_LENGTH_SET(type_len, bytes);
-    of_wire_buffer_u32_set(wbuf, 
-           OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), type_len);
-}
-
-/**
  * Get the object ID of an OXM object based on the wire buffer type
  * @param obj The object whose wire buffer is an OXM type
  * @param id (out) Where the ID is stored 
@@ -587,80 +524,6 @@
     *id = of_oxm_to_object_id(type_len, obj->version);
 }
 
-/**
- * Set the wire type of an OXM object based on the object ID passed
- * @param obj The object whose wire buffer is an OXM type
- * @param id The object ID mapped to an OXM wire type which is stored
- */
-
-void
-of_oxm_wire_object_id_set(of_object_t *obj, of_object_id_t id)
-{
-    uint32_t type_len;
-    int wire_type;
-    of_wire_buffer_t *wbuf;
-
-    ASSERT(OF_OXM_VALID_ID(id));
-
-    /* Read-modify-write */
-    _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-
-    switch (id) {
-    case OF_OXM_BSN_IN_PORTS_128:
-        type_len = 0x00030000 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_IN_PORTS_128_MASKED:
-        type_len = 0x00030100 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_LAG_ID:
-        type_len = 0x00030200 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_LAG_ID_MASKED:
-        type_len = 0x00030300 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_VRF:
-        type_len = 0x00030400 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_VRF_MASKED:
-        type_len = 0x00030500 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_GLOBAL_VRF_ALLOWED:
-        type_len = 0x00030600 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_GLOBAL_VRF_ALLOWED_MASKED:
-        type_len = 0x00030700 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_INTERFACE_CLASS_ID:
-        type_len = 0x00030800 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_INTERFACE_CLASS_ID_MASKED:
-        type_len = 0x00030900 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_SRC_CLASS_ID:
-        type_len = 0x00030a00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_SRC_CLASS_ID_MASKED:
-        type_len = 0x00030b00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_DST_CLASS_ID:
-        type_len = 0x00030c00 | (type_len & 0xff);
-        break;
-    case OF_OXM_BSN_L3_DST_CLASS_ID_MASKED:
-        type_len = 0x00030d00 | (type_len & 0xff);
-        break;
-    default:
-        wire_type = of_object_to_wire_type(id, obj->version);
-        ASSERT(wire_type >= 0);
-        type_len = 0x80000000 | (wire_type << 8) | (type_len & 0xff);
-        break;
-    }
-
-    of_wire_buffer_u32_set(wbuf, 
-           OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), type_len);
-}
-
-
-
 #define OF_U16_LEN_LENGTH_OFFSET 0
 
 /**
@@ -870,7 +733,14 @@
     case OF_EXPERIMENTER_ID_BSN:
         switch (subtype) {
         case 1: return OF_BSN_LACP_STATS_REQUEST;
+        case 2: return OF_BSN_GENTABLE_ENTRY_DESC_STATS_REQUEST;
+        case 3: return OF_BSN_GENTABLE_ENTRY_STATS_REQUEST;
+        case 4: return OF_BSN_GENTABLE_DESC_STATS_REQUEST;
+        case 5: return OF_BSN_GENTABLE_BUCKET_STATS_REQUEST;
         case 6: return OF_BSN_SWITCH_PIPELINE_STATS_REQUEST;
+        case 7: return OF_BSN_GENTABLE_STATS_REQUEST;
+        case 8: return OF_BSN_PORT_COUNTER_STATS_REQUEST;
+        case 9: return OF_BSN_VLAN_COUNTER_STATS_REQUEST;
         }
     }
     return OF_OBJECT_INVALID;
@@ -883,7 +753,14 @@
     case OF_EXPERIMENTER_ID_BSN:
         switch (subtype) {
         case 1: return OF_BSN_LACP_STATS_REPLY;
+        case 2: return OF_BSN_GENTABLE_ENTRY_DESC_STATS_REPLY;
+        case 3: return OF_BSN_GENTABLE_ENTRY_STATS_REPLY;
+        case 4: return OF_BSN_GENTABLE_DESC_STATS_REPLY;
+        case 5: return OF_BSN_GENTABLE_BUCKET_STATS_REPLY;
         case 6: return OF_BSN_SWITCH_PIPELINE_STATS_REPLY;
+        case 7: return OF_BSN_GENTABLE_STATS_REPLY;
+        case 8: return OF_BSN_PORT_COUNTER_STATS_REPLY;
+        case 9: return OF_BSN_VLAN_COUNTER_STATS_REPLY;
         }
     }
     return OF_OBJECT_INVALID;
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index 117332c..f977004 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -900,6 +900,26 @@
 #define of_wire_buffer_bitmap_128_set(buf, offset, addr) \
     (of_wire_buffer_u64_set(buf, offset, addr.hi), of_wire_buffer_u64_set(buf, offset+8, addr.lo))
 
+/**
+ * Get a checksum_128 from a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param checksum Pointer to where to store the checksum_128
+ */
+
+#define of_wire_buffer_checksum_128_get(buf, offset, checksum) \
+    (of_wire_buffer_u64_get(buf, offset, &checksum->hi), of_wire_buffer_u64_get(buf, offset+8, &checksum->lo))
+
+/**
+ * Set a checksum_128 in a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param checksum The variable holding checksum_128 to store
+ */
+
+#define of_wire_buffer_checksum_128_set(buf, offset, checksum) \
+    (of_wire_buffer_u64_set(buf, offset, checksum.hi), of_wire_buffer_u64_set(buf, offset+8, checksum.lo))
+
 /* Relocate data from start offset to the end of the buffer to a new position */
 static inline void
 of_wire_buffer_move_end(of_wire_buffer_t *wbuf, int start_offset, int new_offset)
diff --git a/c_gen/translation.py b/c_gen/translation.py
index ef6c11b..fb64fa9 100644
--- a/c_gen/translation.py
+++ b/c_gen/translation.py
@@ -89,7 +89,7 @@
         dict(OFPM_ = "OF_METER_"),
         dict(OFPXMC_ = "OF_OXM_CLASS_"),
         dict(OFPVID_ = "OF_VLAN_TAG_"),
-        dict(OFPGC_ = "OF_GROUP_"),
+        dict(OFPGC_ = "OF_GROUP_MOD_COMMAND_"),
         dict(OFPGT_ = "OF_GROUP_TYPE_"),
         dict(OFPG_ = "OF_GROUP_"),
         dict(OFPET_ = "OF_ERROR_TYPE_"),
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 14e7048..2a53519 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -38,6 +38,7 @@
 from generic_utils import *
 import loxi_utils.loxi_utils as loxi_utils
 import c_gen.loxi_utils_legacy as loxi_utils
+import loxi_globals
 
 invalid_type = "invalid_type"
 invalid_value = "0xeeee"  # Note, as a string
@@ -60,21 +61,25 @@
     of_g.VERSION_1_3:dict()
     }
 
-# HACK shared between actions and action_ids
-of_1_3_action_types = dict()
+instruction_id_types = {
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict()
+    }
 
 action_types = {
     of_g.VERSION_1_0:dict(),
     of_g.VERSION_1_1:dict(),
     of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:of_1_3_action_types
+    of_g.VERSION_1_3:dict(),
     }
 
 action_id_types = {
     of_g.VERSION_1_0:dict(),
     of_g.VERSION_1_1:dict(),
     of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:of_1_3_action_types
+    of_g.VERSION_1_3:dict(),
     }
 
 queue_prop_types = {
@@ -131,9 +136,17 @@
     of_g.VERSION_1_3:dict(),
     }
 
+bsn_tlv_types = {
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(),
+    }
+
 # All inheritance data for non-messages
 inheritance_data = dict(
     of_instruction = instruction_types,
+    of_instruction_id = instruction_id_types,
     of_action = action_types,
     of_action_id = action_id_types,
     of_oxm = oxm_types,
@@ -142,23 +155,19 @@
     of_table_feature_prop = table_feature_prop_types,
     of_meter_band = meter_band_types,
     # BSN specific inheritance extensions
-    of_bsn_vport = bsn_vport_types
+    of_bsn_vport = bsn_vport_types,
+    of_bsn_tlv = bsn_tlv_types,
     )
 
 def class_is_virtual(cls):
     """
     Returns True if cls is a virtual class
     """
-    if cls in inheritance_map:
-        return True
     if cls.find("header") > 0:
         return True
     if loxi_utils.class_is_list(cls):
         return True
-    # TODO get this from the input file when we have virtual class syntax
-    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira", "of_bsn_stats_request", "of_bsn_stats_reply", "of_experimenter_stats_request", "of_experimenter_stats_reply", "of_instruction_experimenter", "of_instruction_bsn"]:
-        return True
-    return False
+    return loxi_globals.unified.class_by_name(cls).virtual
 
 ################################################################
 #
@@ -182,6 +191,7 @@
         error_msg               = 1,
         experimenter            = 4,
         flow_mod                = 14,
+        group_mod               = 15,
         stats_request           = 18,
         stats_reply             = 19,
         ),
@@ -191,6 +201,7 @@
         error_msg               = 1,
         experimenter            = 4,
         flow_mod                = 14,
+        group_mod               = 15,
         stats_request           = 18,
         stats_reply             = 19,
         ),
@@ -200,6 +211,7 @@
         error_msg               = 1,
         experimenter            = 4,
         flow_mod                = 14,
+        group_mod               = 15,
         stats_request           = 18,  # FIXME Multipart
         stats_reply             = 19,
         )
@@ -269,7 +281,9 @@
         port_desc = 13,
         experimenter = 0xffff,
         bsn_lacp = 0xffff,
-        bsn_switch_pipeline = 0xffff
+        bsn_switch_pipeline = 0xffff,
+        bsn_port_counter = 0xffff,
+        bsn_vlan_counter = 0xffff
         )
     }
 
@@ -353,6 +367,32 @@
         )
     }
 
+group_mod_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        add = 0,
+        modify = 1,
+        delete = 2
+        ),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        add = 0,
+        modify = 1,
+        delete = 2
+        ),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        add = 0,
+        modify = 1,
+        delete = 2
+        )
+    }
+
 ##
 # These are the objects whose length is specified by an external
 # reference, specifically another data member in the class.
@@ -458,6 +498,8 @@
     "of_bsn_stats_reply",
     "of_bsn_lacp_stats_reply",
     "of_bsn_switch_pipeline_stats_reply",
+    "of_bsn_port_counter_stats_reply",
+    "of_bsn_vlan_counter_stats_reply",
 ]
 
 stats_request_list = [
@@ -479,6 +521,8 @@
     "of_bsn_stats_request",
     "of_bsn_lacp_stats_request",
     "of_bsn_switch_pipeline_stats_request",
+    "of_bsn_port_counter_stats_request",
+    "of_bsn_vlan_counter_stats_request",
 ]
 
 flow_mod_list = [
@@ -507,6 +551,12 @@
     "of_experimenter_error_msg"
 ]
 
+group_mod_list = [
+    "of_group_add",
+    "of_group_modify",
+    "of_group_delete",
+]
+
 def sub_class_map(base_type, version):
     """
     Returns an iterable object giving the instance nameys and subclass types
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 8f5434e..8726632 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -47,6 +47,10 @@
 
 logger = logging.getLogger(__name__)
 
+
+def java_class_name(c_name):
+    return java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
+
 class JavaModel(object):
     # registry for enums that should not be generated
     # set(${java_enum_name})
@@ -54,7 +58,6 @@
     # registry for enum *entry* that should not be generated
     # map: ${java_enum_name} -> set(${java_entry_entry_name})
     enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
-
     # registry of interfaces that should not be generated
     # set(java_names)
     # OFUint structs are there for god-knows what in loci. We certainly don't need them.
@@ -68,7 +71,15 @@
         OFExperimenterStatsReply=set(('data','subtype')),
         OFInstructionExperimenter=set(('data',)))
     # map: $java_type -> set(java_name_property)
-    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
+    write_blacklist = defaultdict(
+        lambda: set(),
+        OFOxm=set(('typeLen',)),
+        OFAction=set(('type',)),
+        OFInstruction=set(('type',)),
+        OFFlowMod=set(('command', )),
+        OFExperimenter=set(('data','subtype')),
+        OFActionExperimenter=set(('data',)),
+        OFBsnTlv=set(('type',)))
     # interfaces that are virtual
     virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
 
@@ -201,7 +212,7 @@
 
         factories = OrderedDict()
 
-        sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
+        sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp", "OFErrorMsg", "OFActionId", "OFInstructionId", "OFBsnTlv")
         for base_class in sub_factory_classes:
             package = base_class[2:].lower()
             remove_prefix = base_class[2].lower() + base_class[3:]
@@ -210,7 +221,7 @@
             annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
 
             factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
-                    name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
+                    name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator= (base_class == "OFErrorMsg"))
 
         factories[""] = OFFactory(
                     package=prefix,
@@ -362,7 +373,7 @@
         self.c_name = ir_class.name
         self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
         # name: the Java Type name, e.g., OFFlowAdd
-        self.name = java_type.name_c_to_caps_camel(self.c_name) if self.c_name != "of_header" else "OFMessage"
+        self.name = java_class_name(self.c_name)
         # variable_name name to use for variables of this type. i.e., flowAdd
         self.variable_name = self.name[2].lower() + self.name[3:]
         self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
@@ -426,81 +437,66 @@
 
     def class_info(self):
         """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
-        # FIXME: This duplicates inheritance information that is now available in the loxi_ir
-        # model (note, that the loxi model is on versioned classes). Should check/infer the
-        # inheritance information from the versioned lox_ir classes.
-        if re.match(r'OFStatsRequest$', self.name):
-            return ("", "OFMessage", "T extends OFStatsReply")
+        # FIXME: This code could be cleaned up further. Maybe some of the exceptions
+        # here could be folded into ir, or the type arithmetic specified in a more general
+        # fashion
+        def calc_package(i):
+            if i.is_subclassof("of_error_msg"):
+                return "errormsg"
+            elif i.is_instanceof("of_action"):
+                return "action"
+            elif i.is_instanceof("of_action_id"):
+                return "actionid"
+            elif i.is_instanceof("of_instruction"):
+                return "instruction"
+            elif i.is_instanceof("of_instruction_id"):
+                return "instructionid"
+            elif i.is_instanceof("of_oxm"):
+                return "oxm"
+            elif i.is_instanceof("of_meter_band"):
+                return "meterband"
+            elif i.is_instanceof("of_queue_prop"):
+                return "queueprop"
+            elif i.is_instanceof("of_bsn_tlv"):
+                return "bsntlv"
+            else:
+                return ""
+
+        def calc_super_name(i):
+            if re.match('of_match_.*', i.name):
+                return "Match"
+            else:
+                ir_super_class = self.ir_class.superclass
+                return java_class_name(ir_super_class.name) if ir_super_class else ""
+
+        package = calc_package(self.ir_class)
+        super_name = calc_super_name(self.ir_class)
+
+        if self.name == "OFStatsRequest":
+            # stats_requests are special because of their type annotation
+            return (package, "OFMessage", "T extends OFStatsReply")
         elif self.ir_class.is_subclassof('of_stats_request'):
-            if self.ir_class.is_subclassof('of_bsn_stats_request'):
-                return ("", "OFBsnStatsRequest", None)
-            elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
-                return ("", "OFExperimenterStatsRequest", None)
-            else:
-                return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
-        elif self.ir_class.is_subclassof('of_stats_reply'):
-            if self.ir_class.is_subclassof('of_bsn_stats_reply'):
-                return ("", "OFBsnStatsReply", None)
-            elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
-                return ("", "OFExperimenterStatsReply", None)
-            else:
-                return ("", "OFStatsReply", None)
-        elif self.ir_class.is_subclassof('of_error_msg'):
-            return ("", "OFErrorMsg", None)
-        elif self.ir_class.is_subclassof('of_flow_mod'):
-            return ("", "OFFlowMod", None)
-        elif self.ir_class.is_subclassof('of_group_mod'):
-            return ("", "OFGroupMod", None)
-        elif self.ir_class.is_subclassof('of_bsn_header'):
-            return ("", "OFBsnHeader", None)
-        elif self.ir_class.is_subclassof('of_nicira_header'):
-            return ("", "OFNiciraHeader", None)
-        elif self.ir_class.is_subclassof('of_experimenter'):
-            return ("", "OFExperimenter", None)
-        elif re.match(r'OFMatch.*', self.name):
-            return ("", "Match", None)
-        elif self.ir_class.is_message:
-            return ("", "OFMessage", None)
-        elif self.ir_class.is_action:
-            if self.ir_class.is_subclassof('of_action_bsn'):
-                return ("action", "OFActionBsn", None)
-            elif self.ir_class.is_subclassof('of_action_nicira'):
-                return ("action", "OFActionNicira", None)
-            elif self.ir_class.is_subclassof('of_action_experimenter'):
-                return ("action", "OFActionExperimenter", None)
-            else:
-                return ("action", "OFAction", None)
-        elif self.ir_class.is_instruction:
-            if self.ir_class.is_subclassof('of_instruction_bsn'):
-                return ("instruction", "OFInstructionBsn", None)
-            elif self.ir_class.is_subclassof('of_instruction_experimenter'):
-                return ("instruction", "OFInstructionExperimenter", None)
-            else:
-                return ("instruction", "OFInstruction", None)
-        elif re.match(r'OFBsnVport.+$', self.name):
-            return ("", "OFBsnVport", None)
+            # stats_request subclasses  are special because of their type annotation
+            reply_name = re.sub(r'Request$', 'Reply', self.name)
+            super_type_annotation = "T" if self.ir_class.virtual else reply_name
+
+            type_annotation = "T extends {}".format(reply_name) if self.ir_class.virtual \
+                    else ""
+
+            return (package, "{}<{}>".format(super_name, super_type_annotation),
+                    type_annotation)
         elif self.name == "OFOxm":
-            return ("oxm", None, "T extends OFValueType<T>")
+            return (package, None, "T extends OFValueType<T>")
         elif loxi_utils.class_is_oxm(self.c_name):
+            # look up type from member value for OFValueType type annotation
             if self.member_by_name("value") is not None:
-                return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
+                return (package, "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
             else:
-                return ("oxm", "OFOxm", None)
-        elif loxi_utils.class_is_instruction(self.c_name):
-            return ("instruction", "OFInstruction", None)
-        elif loxi_utils.class_is_meter_band(self.c_name):
-            return ("meterband", "OFMeterBand", None)
-        elif loxi_utils.class_is_queue_prop(self.c_name):
-            return ("queueprop", "OFQueueProp", None)
-        elif loxi_utils.class_is_hello_elem(self.c_name):
-            return ("", "OFHelloElem", None)
-        elif loxi_utils.class_is_table_feature_prop(self.c_name):
-            return ("", "OFTableFeatureProp", None)
+                return (package, "OFOxm", None)
         else:
-            return ("", None, None)
+            return (package, super_name, None)
 
     @property
-
     @memoize
     def writeable_members(self):
         return [ m for m in self.members if m.is_writeable ]
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index eca00e7..351765b 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -298,6 +298,12 @@
                 write='ChannelUtils.writeList(bb, $name)',
                 default="ImmutableList.<U32>of()",
                 funnel="FunnelUtils.putList($name, sink)")
+u64_list = JType('List<U64>', 'int[]') \
+        .op(
+                read='ChannelUtils.readList(bb, $length, U64.READER)',
+                write='ChannelUtils.writeList(bb, $name)',
+                default="ImmutableList.<U64>of()",
+                funnel="FunnelUtils.putList($name, sink)")
 u8obj = JType('U8', 'U8') \
         .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
 u32obj = JType('U32', 'U32') \
@@ -412,6 +418,9 @@
 meter_features = JType("OFMeterFeatures")\
         .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
             write="$name.writeTo(bb)")
+bsn_vport_q_in_q = JType("OFBsnVportQInQ")\
+        .op(read="OFBsnVportQInQVer$version.READER.readFrom(bb)",
+            write="$name.writeTo(bb)")
 flow_wildcards = JType("int") \
         .op(read='bb.readInt()',
             write='bb.writeInt($name)',
@@ -461,6 +470,8 @@
             funnel='ChannelUtilsVer10.putSupportedActionsTo($name, sink)')
 of_group = JType("OFGroup") \
          .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ALL")
+of_group_default_any = JType("OFGroup") \
+         .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ANY")
 # the outgroup field of of_flow_stats_request has a special default value
 of_group_default_any = JType("OFGroup") \
          .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ANY")
@@ -474,6 +485,14 @@
          .op(version=ANY, read="ClassId.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="ClassId.NONE")
 boolean_value = JType('OFBooleanValue', 'OFBooleanValue') \
         .op(read='OFBooleanValue.of(bb.readByte() != 0)', write='bb.writeByte($name.getInt())', default="OFBooleanValue.FALSE")
+checksum = JType("OFChecksum128") \
+        .op(read='OFChecksum128.read16Bytes(bb)',
+            write='$name.write16Bytes(bb)',
+            default='OFChecksum128.ZERO')
+gen_table_id = JType("GenTableId") \
+        .op(read='GenTableId.read2Bytes(bb)',
+            write='$name.write2Bytes(bb)',
+           )
 
 generic_t = JType("T")
 
@@ -489,6 +508,7 @@
         'list(of_bucket_t)': buckets_list,
         'list(of_port_desc_t)' : port_desc_list,
         'list(of_packet_queue_t)' : packet_queue_list,
+        'list(of_uint64_t)' : u64_list,
         'list(of_uint32_t)' : u32_list,
         'list(of_uint8_t)' : u8_list,
         'list(of_oxm_t)' : oxm_list,
@@ -506,7 +526,9 @@
         'of_wc_bmap_t': flow_wildcards,
         'of_oxm_t': oxm,
         'of_meter_features_t': meter_features,
-        'of_bitmap_128_t': port_bitmap
+        'of_bitmap_128_t': port_bitmap,
+        'of_checksum_128_t': checksum,
+        'of_bsn_vport_q_in_q_t': bsn_vport_q_in_q,
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
@@ -612,6 +634,9 @@
         'of_group_delete' : { 'command' : group_mod_cmd },
 
         'of_bucket' : { 'watch_group': of_group },
+
+        'of_bsn_tlv_vlan_vid' : { 'value' : vlan_vid },
+        'of_bsn_gentable_entry_add' : { 'table_id' : gen_table_id },
 }
 
 
@@ -656,8 +681,10 @@
             .op(read='bb.readShort()', write='bb.writeShort($name)')
     elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
         return instruction_type
-    elif obj_name in ("of_flow_add", "of_flow_modify", "of_flow_modify_strict", "of_delete_strict") and  field_name == "table_id" and c_type == "uint8_t":
+    elif loxi_utils.class_is(obj_name, "of_flow_mod") and field_name == "table_id" and c_type == "uint8_t":
         return table_id_default_zero
+    elif loxi_utils.class_is(obj_name, "of_flow_mod") and field_name == "out_group" and c_type == "uint32_t":
+        return of_group_default_any
     elif field_name == "table_id" and c_type == "uint8_t":
         return table_id
     elif field_name == "version" and c_type == "uint8_t":
@@ -670,6 +697,8 @@
         return datapath_id
     elif field_name == 'actions' and obj_name == 'of_features_reply':
         return action_type_set
+    elif field_name == "table_id" and re.match(r'of_bsn_gentable.*', obj_name):
+        return gen_table_id
     elif c_type in default_mtype_to_jtype_convert_map:
         return default_mtype_to_jtype_convert_map[c_type]
     elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
diff --git a/java_gen/pre-written/pom.xml b/java_gen/pre-written/pom.xml
index 0cb42ac..a455016 100644
--- a/java_gen/pre-written/pom.xml
+++ b/java_gen/pre-written/pom.xml
@@ -10,7 +10,7 @@
 
     <groupId>org.projectfloodlight</groupId>
     <artifactId>openflowj</artifactId>
-    <version>0.3.1-SNAPSHOT</version>
+    <version>0.3.4-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <name>OpenFlowJ-Loxi</name>
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
index ed7c0c8..b4937ba 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
@@ -6,7 +6,6 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.protocol.OFActionType;
-import org.projectfloodlight.openflow.protocol.OFBsnVportQInQ;
 import org.projectfloodlight.openflow.protocol.match.Match;
 
 import com.google.common.hash.PrimitiveSink;
@@ -22,17 +21,6 @@
         return OFMatchV1Ver10.READER.readFrom(bb);
     }
 
-    // TODO these need to be figured out / removed
-    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
-        throw new UnsupportedOperationException("not implemented");
-    }
-
-    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
-            OFBsnVportQInQ vport) {
-        throw new UnsupportedOperationException("not implemented");
-
-    }
-
     public static Set<OFActionType> readSupportedActions(ChannelBuffer bb) {
         int actions = bb.readInt();
         EnumSet<OFActionType> supportedActions = EnumSet.noneOf(OFActionType.class);
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver11/ChannelUtilsVer11.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver11/ChannelUtilsVer11.java
index 735fe3b..b090e47 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver11/ChannelUtilsVer11.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver11/ChannelUtilsVer11.java
@@ -4,8 +4,6 @@
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.protocol.OFMatchBmap;
 import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.ver11.OFMatchV2Ver11;
-import org.projectfloodlight.openflow.protocol.OFBsnVportQInQ;
 
 /**
  * Collection of helper functions for reading and writing into ChannelBuffers
@@ -18,17 +16,6 @@
         return OFMatchV2Ver11.READER.readFrom(bb);
     }
 
-    // TODO these need to be figured out / removed
-    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
-        throw new UnsupportedOperationException("not implemented");
-    }
-
-    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
-            OFBsnVportQInQ vport) {
-        throw new UnsupportedOperationException("not implemented");
-    }
-
-
     public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
         throw new UnsupportedOperationException("not implemented");
     }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver13/ChannelUtilsVer13.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver13/ChannelUtilsVer13.java
index 0be26ae..8216bb0 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver13/ChannelUtilsVer13.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver13/ChannelUtilsVer13.java
@@ -4,8 +4,6 @@
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.protocol.OFMatchBmap;
 import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.ver13.OFMatchV3Ver13;
-import org.projectfloodlight.openflow.protocol.OFBsnVportQInQ;
 
 /**
  * Collection of helper functions for reading and writing into ChannelBuffers
@@ -18,17 +16,6 @@
         return OFMatchV3Ver13.READER.readFrom(bb);
     }
 
-    // TODO these need to be figured out / removed
-
-    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
-        throw new UnsupportedOperationException("not implemented");
-    }
-
-    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
-            OFBsnVportQInQ vport) {
-        throw new UnsupportedOperationException("not implemented");
-    }
-
     public static OFMatchBmap readOFMatchBmap(ChannelBuffer bb) {
         throw new UnsupportedOperationException("not implemented");
     }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/GenTableId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/GenTableId.java
new file mode 100644
index 0000000..cfa7cdf
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/GenTableId.java
@@ -0,0 +1,93 @@
+package org.projectfloodlight.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.UnsignedInts;
+
+public class GenTableId implements OFValueType<GenTableId>, Comparable<GenTableId> {
+    final static int LENGTH = 2;
+
+    private static final int VALIDATION_MASK = 0xFFFF;
+
+    private static final int ALL_VAL = 0xFFFF;
+    private static final int NONE_VAL = 0x0000;
+    public static final GenTableId NONE = new GenTableId(NONE_VAL);
+
+    public static final GenTableId ALL = new GenTableId(ALL_VAL);
+    public static final GenTableId ZERO = NONE;
+
+    private final int id;
+
+    private GenTableId(int id) {
+        this.id = id;
+    }
+
+    public static GenTableId of(int id) {
+        switch(id) {
+            case NONE_VAL:
+                return NONE;
+            case ALL_VAL:
+                return ALL;
+            default:
+                if ((id & VALIDATION_MASK) != id)
+                    throw new IllegalArgumentException("Illegal Table id value: " + id);
+                return new GenTableId(id);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "0x" + Integer.toHexString(id);
+    }
+
+    public int getValue() {
+        return id;
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    public void write2Bytes(ChannelBuffer c) {
+        c.writeShort(this.id);
+    }
+
+    public static GenTableId read2Bytes(ChannelBuffer c) throws OFParseError {
+        return GenTableId.of(c.readUnsignedShort());
+    }
+
+    @Override
+    public GenTableId applyMask(GenTableId mask) {
+        return GenTableId.of(this.id & mask.id);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof GenTableId))
+            return false;
+        GenTableId other = (GenTableId)obj;
+        if (other.id != this.id)
+            return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int prime = 13873;
+        return this.id * prime;
+    }
+
+    @Override
+    public int compareTo(GenTableId other) {
+        return UnsignedInts.compare(this.id, other.id);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort((byte) id);
+    }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
index 7c50aed..c96be83 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
@@ -4,7 +4,32 @@
 
     public abstract IPVersion getIpVersion();
 
+    /**
+     * Checks if this IPAddress represents a valid CIDR style netmask, i.e.,
+     * it has a set of leading "1" bits followed by only "0" bits
+     * @return true if this represents a valid CIDR style netmask, false
+     * otherwise
+     */
+    public abstract boolean isCidrMask();
+
+    /**
+     * If this IPAddress represents a valid CIDR style netmask (see
+     * isCidrMask()) returns the length of the prefix (the number of "1" bits).
+     * @return length of CIDR mask if this represents a valid CIDR mask
+     * @throws IllegalStateException if isCidrMask() == false
+     */
+    public abstract int asCidrMaskLength();
+
+    @Override
+    public abstract boolean equals(Object other);
+
+    @Override
+    public abstract int hashCode();
+
     public static IPAddress<?> of(String ip) {
+        if (ip == null) {
+            throw new NullPointerException("String ip must not be null");
+        }
         if (ip.indexOf('.') != -1)
             return IPv4Address.of(ip);
         else if (ip.indexOf(':') != -1)
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
index 11ef103..2087ab4 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
@@ -10,6 +10,9 @@
     public abstract IPVersion getIpVersion();
 
     public static IPAddressWithMask<?> of(String ip) {
+        if (ip == null) {
+            throw new NullPointerException("String ip must not be null");
+        }
         if (ip.indexOf('.') != -1)
             return IPv4AddressWithMask.of(ip);
         else if (ip.indexOf(':') != -1)
@@ -18,4 +21,21 @@
             throw new IllegalArgumentException("IP Address not well formed: " + ip);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder res = new StringBuilder();
+        res.append(value.toString());
+
+        res.append('/');
+        if (mask.isCidrMask()) {
+            // CIDR notation
+            res.append(mask.asCidrMaskLength());
+        } else {
+            // Full address mask
+            res.append(mask.toString());
+        }
+
+        return res.toString();
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index 51d10f3..a75c2ee 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -18,6 +18,11 @@
     static final int LENGTH = 4;
     private final int rawValue;
 
+    private static final int NOT_A_CIDR_MASK = -1;
+    private static final int CIDR_MASK_CACHE_UNSET = -2;
+    // Must appear before the static IPv4Address constant assignments
+    private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
+
     private final static int NONE_VAL = 0x0;
     public final static IPv4Address NONE = new IPv4Address(NONE_VAL);
 
@@ -33,7 +38,41 @@
         return IPVersion.IPv4;
     }
 
+    private int asCidrMaskLengthInternal() {
+        if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
+            // No lock required. We only write cidrMaskLengthCache once
+            int maskint = getInt();
+            if (maskint == 0) {
+                cidrMaskLengthCache = 0;
+            } else if (Integer.bitCount((~maskint) + 1) == 1) {
+                // IP represents a true CIDR prefix length
+                cidrMaskLengthCache = Integer.bitCount(maskint);
+            } else {
+                cidrMaskLengthCache = NOT_A_CIDR_MASK;
+            }
+        }
+        return cidrMaskLengthCache;
+    }
+
+    @Override
+    public boolean isCidrMask() {
+        return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
+    }
+
+    @Override
+    public int asCidrMaskLength() {
+        if (!isCidrMask()) {
+            throw new IllegalStateException("IP is not a valid CIDR prefix " +
+                    "mask " + toString());
+        } else {
+            return asCidrMaskLengthInternal();
+        }
+    }
+
     public static IPv4Address of(final byte[] address) {
+        if (address == null) {
+            throw new NullPointerException("Address must not be null");
+        }
         if (address.length != LENGTH) {
             throw new IllegalArgumentException(
                     "Invalid byte array length for IPv4Address address: " + address.length);
@@ -52,6 +91,9 @@
     }
 
     public static IPv4Address of(final String string) {
+        if (string == null) {
+            throw new NullPointerException("String must not be null");
+        }
         int start = 0;
         int shift = 24;
 
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
index f30fcbb..9b60c6a 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4AddressWithMask.java
@@ -22,28 +22,19 @@
     }
 
     public static IPv4AddressWithMask of(IPv4Address value, IPv4Address mask) {
+        if (value == null) {
+            throw new NullPointerException("Value must not be null");
+        }
+        if (mask == null) {
+            throw new NullPointerException("Mask must not be null");
+        }
         return new IPv4AddressWithMask(value, mask);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder res = new StringBuilder();
-        res.append(value.toString());
-
-        int maskint = mask.getInt();
-        res.append('/');
-        if (Integer.bitCount((~maskint) + 1) == 1) {
-            // CIDR notation
-            res.append(Integer.bitCount(maskint));
-        } else {
-            // Full address mask
-            res.append(mask.toString());
-        }
-
-        return res.toString();
-    }
-
     public static IPv4AddressWithMask of(final String string) {
+        if (string == null) {
+            throw new NullPointerException("String must not be null");
+        }
         int slashPos;
         String ip = string;
         int maskBits = 32;
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index 1aad85b..4e7b856 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -4,7 +4,6 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
-
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
@@ -19,10 +18,16 @@
     private final long raw1;
     private final long raw2;
 
+    private static final int NOT_A_CIDR_MASK = -1;
+    private static final int CIDR_MASK_CACHE_UNSET = -2;
+    // Must appear before the static IPv4Address constant assignments
+    private volatile int cidrMaskLengthCache = CIDR_MASK_CACHE_UNSET;
+
     private final static long NONE_VAL1 = 0x0L;
     private final static long NONE_VAL2 = 0x0L;
     public static final IPv6Address NONE = new IPv6Address(NONE_VAL1, NONE_VAL2);
 
+
     public static final IPv6Address NO_MASK = IPv6Address.of(0xFFFFFFFFFFFFFFFFl, 0xFFFFFFFFFFFFFFFFl);
     public static final IPv6Address FULL_MASK = IPv6Address.of(0x0, 0x0);
 
@@ -36,7 +41,60 @@
         return IPVersion.IPv6;
     }
 
+
+    private int computeCidrMask64(long raw) {
+        long mask = raw;
+        if (raw == 0)
+            return 0;
+        else if (Long.bitCount((~mask) + 1) == 1) {
+            // represent a true CIDR prefix length
+            return Long.bitCount(mask);
+        }
+        else {
+            // Not a true prefix
+            return NOT_A_CIDR_MASK;
+        }
+    }
+
+    private int asCidrMaskLengthInternal() {
+        if (cidrMaskLengthCache == CIDR_MASK_CACHE_UNSET) {
+            // No synchronization needed. Writing cidrMaskLengthCache only once
+            if (raw1 == 0 && raw2 == 0) {
+                cidrMaskLengthCache = 0;
+            } else if (raw1 == -1L) {
+                // top half is all 1 bits
+                int tmpLength = computeCidrMask64(raw2);
+                if (tmpLength != NOT_A_CIDR_MASK)
+                    tmpLength += 64;
+                cidrMaskLengthCache = tmpLength;
+            } else if (raw2 == 0) {
+                cidrMaskLengthCache = computeCidrMask64(raw1);
+            } else {
+                cidrMaskLengthCache = NOT_A_CIDR_MASK;
+            }
+        }
+        return cidrMaskLengthCache;
+    }
+
+    @Override
+    public boolean isCidrMask() {
+        return asCidrMaskLengthInternal() != NOT_A_CIDR_MASK;
+    }
+
+    @Override
+    public int asCidrMaskLength() {
+        if (!isCidrMask()) {
+            throw new IllegalStateException("IP is not a valid CIDR prefix " +
+                    "mask " + toString());
+        } else {
+            return asCidrMaskLengthInternal();
+        }
+    }
+
     public static IPv6Address of(final byte[] address) {
+        if (address == null) {
+            throw new NullPointerException("Address must not be null");
+        }
         if (address.length != LENGTH) {
             throw new IllegalArgumentException(
                     "Invalid byte array length for IPv6 address: " + address.length);
@@ -82,6 +140,9 @@
     private final static Pattern colonPattern = Pattern.compile(":");
 
     public static IPv6Address of(final String string) {
+        if (string == null) {
+            throw new NullPointerException("String must not be null");
+        }
         IPv6Builder builder = new IPv6Builder();
         String[] parts = colonPattern.split(string, -1);
 
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
index 6faf0b8..7259c7f 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6AddressWithMask.java
@@ -16,28 +16,20 @@
     }
 
     public static IPv6AddressWithMask of(IPv6Address value, IPv6Address mask) {
+        if (value == null) {
+            throw new NullPointerException("Value must not be null");
+        }
+        if (mask == null) {
+            throw new NullPointerException("Mask must not be null");
+        }
         return new IPv6AddressWithMask(value, mask);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder res = new StringBuilder();
-        res.append(value.toString());
-        res.append('/');
-
-        BigInteger maskint = new BigInteger(mask.getBytes());
-        if (maskint.not().add(BigInteger.ONE).bitCount() == 1) {
-            // CIDR notation
-            res.append(maskint.bitCount());
-        } else {
-            // Full address mask
-            res.append(mask.toString());
-        }
-
-        return res.toString();
-    }
 
     public static IPv6AddressWithMask of(final String string) {
+        if (string == null) {
+            throw new NullPointerException("String must not be null");
+        }
         int slashPos;
         String ip = string;
         int maskBits = 128;
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
index ea2317a..b5a995d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
@@ -5,8 +5,13 @@
 
 
 public class Masked<T extends OFValueType<T>> implements OFValueType<Masked<T>> {
-    protected T value;
-    protected T mask;
+    protected final T value;
+
+    /** bitmask of the value. Note: a set (1) bit in this mask means 'match on this value'.
+     *  This the natural mask represenation as in IPv[46] netmasks. It is the inverse of the
+     *  OpenFlow 1.0 'wildcard' meaning.
+     */
+    protected final T mask;
 
     protected Masked(T value, T mask) {
         this.value = value.applyMask(mask);
@@ -38,6 +43,21 @@
         return sb.toString();
     }
 
+    /** Determine whether candidate value is matched by this masked value
+     *  (i.e., does candiate lie in the 'network/range' specified by this masked
+     *  value).
+     *
+     * @param candidate the candidate value to test
+     * @return true iff the candidate lies in the area specified by this masked
+     *         value.
+     */
+    public boolean matches(T candidate) {
+        // candidate lies in the area of this masked value if its
+        // value with the masked bit zero'ed out equals this's value
+        // (e.g., our 'network address' for networks)
+        return candidate.applyMask(this.mask).equals(this.value);
+    }
+
     @Override
     public Masked<T> applyMask(Masked<T> mask) {
         return this;
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFChecksum128.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFChecksum128.java
new file mode 100644
index 0000000..7578dc6
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFChecksum128.java
@@ -0,0 +1,80 @@
+package org.projectfloodlight.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+import com.google.common.hash.PrimitiveSink;
+
+public class OFChecksum128 implements OFValueType<OFChecksum128> {
+
+    static final int LENGTH = 16;
+
+    private final long raw1; // MSBs
+    private final long raw2; // LSBs
+
+    public static final OFChecksum128 ZERO = new OFChecksum128(0, 0);
+
+    private OFChecksum128(long raw1, long raw2) {
+        this.raw1 = raw1;
+        this.raw2 = raw2;
+    }
+
+    public static OFChecksum128 of(long raw1, long raw2) {
+        if (raw1 == 0 && raw2 == 0)
+            return ZERO;
+        return new OFChecksum128(raw1, raw2);
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public OFChecksum128 applyMask(OFChecksum128 mask) {
+        return of(this.raw1 & mask.raw1, this.raw2 & mask.raw2);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof OFChecksum128))
+            return false;
+        OFChecksum128 other = (OFChecksum128)obj;
+        return (other.raw1 == this.raw1 && other.raw2 == this.raw2);
+    }
+
+    @Override
+    public int hashCode() {
+        return (int)(31 * raw1 + raw2);
+    }
+
+    public void write16Bytes(ChannelBuffer cb) {
+        cb.writeLong(raw1);
+        cb.writeLong(raw2);
+    }
+
+    public static OFChecksum128 read16Bytes(ChannelBuffer cb) {
+        long raw1 = cb.readLong();
+        long raw2 = cb.readLong();
+        return of(raw1, raw2);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("0x%016x%016x", raw1, raw2);
+    }
+
+    @Override
+    public int compareTo(OFChecksum128 o) {
+        long c = this.raw1 - o.raw1;
+        if (c != 0)
+            return Long.signum(c);
+        return Long.signum(this.raw2 - o.raw2);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(raw1);
+        sink.putLong(raw2);
+    }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
index d77d700..f480c47 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
@@ -20,6 +20,8 @@
 import java.math.BigInteger;
 
 import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.OFMessageReader;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
 import com.google.common.hash.PrimitiveSink;
@@ -125,4 +127,13 @@
     public void putTo(PrimitiveSink sink) {
         sink.putLong(raw);
     }
+
+    public final static Reader READER = new Reader();
+
+    private static class Reader implements OFMessageReader<U64> {
+        @Override
+        public U64 readFrom(ChannelBuffer bb) throws OFParseError {
+            return U64.ofRaw(bb.readLong());
+        }
+    }
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
new file mode 100644
index 0000000..25fc943
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPAddressTest.java
@@ -0,0 +1,54 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * Most tests are in IPv4AddressTest and IPv6AddressTest
+ * Just exception testing here
+ * @author gregor
+ *
+ */
+public class IPAddressTest {
+    @Test
+    public void testOfException() {
+        try {
+            IPAddress.of("Foobar");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            IPAddressWithMask.of("Foobar");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            IPAddress.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPAddressWithMask.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPAddress.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPAddressWithMask.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+    }
+
+}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
index 38d60b3..334ec0d 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
@@ -1,8 +1,12 @@
 package org.projectfloodlight.openflow.types;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import org.hamcrest.CoreMatchers;
@@ -38,6 +42,7 @@
             "1.2..3.4",
             "1.2.3.4.",
             "257.11.225.1",
+            "256.11.225.1",
             "-1.2.3.4",
             "1.2.3.4.5",
             "1.x.3.4",
@@ -49,7 +54,10 @@
                             "192.168.130.140/255.255.192.0",
                             "127.0.0.1/8",
                             "8.8.8.8",
-                            "0.0.0.0/0"
+                            "8.8.8.8/32",
+                            "0.0.0.0/0",
+                            "192.168.130.140/255.0.255.0",
+                            "1.2.3.4/0.127.0.255"
     };
 
     boolean[] hasMask = {
@@ -57,6 +65,9 @@
                          true,
                          true,
                          false,
+                         false,
+                         true,
+                         true,
                          true
     };
 
@@ -64,10 +75,110 @@
                              new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x00 } },
                              new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xC0, (byte)0x00 } },
                              new byte[][] { new byte[] { (byte)0x7F, (byte)0x00, (byte)0x00, (byte)0x01 }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00 } },
-                             new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, null },
-                             new byte[][] { new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 } }
+                             new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
+                             new byte[][] { new byte[] { (byte)0x08, (byte)0x08, (byte)0x08, (byte)0x08 }, new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF } },
+                             new byte[][] { new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 } },
+                             new byte[][] { new byte[] { (byte)0xC0, (byte)0xA8, (byte)0x82, (byte)0x8C }, new byte[] { (byte)0xFF, (byte)0x00, (byte)0xFF, (byte)0x00 } },
+                             new byte[][] { new byte[] { (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04 }, new byte[] { (byte)0x00, (byte)0x7F, (byte)0x00, (byte)0xFF } }
     };
 
+    int[] ipsWithMaskLengths = {
+                                24,
+                                18,
+                                8,
+                                32,
+                                32,
+                                0,
+                                -1,
+                                -1
+    };
+
+    String[] invalidIpsWithMask = {
+                                   "asdf",
+                                   "1.2.3.4/33",
+                                   "1.2.3.4/34",
+                                   "1.2.3.4/-1",
+                                   "1.2.3.4/256.0.0.0",
+                                   "1.256.3.4/255.255.0.0",
+                                   "1.2.3.4/255.255.0.0.0",
+    };
+
+    @Test
+    public void testMaskedMatchesCidr() {
+        IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("10.0.42.16/28");
+
+        String[] notContained = {"0.0.0.0", "11.0.42.16", "10.0.41.1", "10.0.42.0", "10.0.42.15",
+                                 "10.0.42.32", "255.255.255.255" };
+
+        for(String n: notContained) {
+            assertThat(String.format("slash 28 %s should not contain address %s",
+                                     slash28, n),
+                    slash28.matches(IPv4Address.of(n)), equalTo(false));
+        }
+        for(int i=16; i < 32; i++) {
+            IPv4Address c = IPv4Address.of(String.format("10.0.42.%d", i));
+            assertThat(String.format("slash 28 %s should contain address %s",
+                                     slash28, c),
+                       slash28.matches(c), equalTo(true));
+        }
+    }
+
+    @Test
+    public void testMaskedMatchesArbitrary() {
+        // irregular octect on the 3rd bitmask requires '1'bit to be set
+        // 4 bit unset, all others arbitrary
+        IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("1.2.1.4/255.255.5.255");
+
+        String[] notContained = {"0.0.0.0", "1.2.3.5", "1.2.3.3",
+                                 "1.2.0.4", "1.2.2.4", "1.2.4.4", "1.2.5.4", "1.2.6.4", "1.2.7.4",
+                                 "1.2.8.4", "1.2.12.4", "1.2.13.4"
+                                 };
+        String[] contained = {"1.2.1.4", "1.2.3.4", "1.2.9.4", "1.2.11.4", "1.2.251.4",
+                };
+
+        for(String n: notContained) {
+            assertThat(String.format("slash 28 %s should not contain address %s",
+                                     slash28, n),
+                    slash28.matches(IPv4Address.of(n)), equalTo(false));
+        }
+        for(String c: contained) {
+            IPv4Address addr = IPv4Address.of(c);
+            assertThat(String.format("slash 28 %s should contain address %s",
+                                     slash28, addr),
+                       slash28.matches(addr), equalTo(true));
+        }
+
+    }
+
+
+    @Test
+    public void testConstants() {
+        byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
+        byte[] ones =  { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+        // Make sure class initializtation and static assignment don't get
+        // messed up. Test everything twice for cached values
+        assertTrue(IPv4Address.NONE.isCidrMask());
+        assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
+        assertTrue(IPv4Address.NONE.isCidrMask());
+        assertEquals(0, IPv4Address.NONE.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv4Address.NONE.getBytes());
+
+        assertTrue(IPv4Address.NO_MASK.isCidrMask());
+        assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
+        assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
+        assertTrue(IPv4Address.NO_MASK.isCidrMask());
+        assertEquals(32, IPv4Address.NO_MASK.asCidrMaskLength());
+        assertArrayEquals(ones, IPv4Address.NO_MASK.getBytes());
+
+        assertTrue(IPv4Address.FULL_MASK.isCidrMask());
+        assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
+        assertTrue(IPv4Address.FULL_MASK.isCidrMask());
+        assertEquals(0, IPv4Address.FULL_MASK.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv4Address.FULL_MASK.getBytes());
+    }
+
 
     @Test
     public void testOfString() {
@@ -119,18 +230,111 @@
             if (!hasMask[i]) {
                 IPv4Address ip = value.getValue();
                 assertArrayEquals(ipsWithMaskValues[i][0], ip.getBytes());
-            } else if (hasMask[i]) {
-                byte[] ipBytes = new byte[4];
-                System.arraycopy(ipsWithMaskValues[i][0], 0, ipBytes, 0, 4);
-                assertEquals(ipBytes.length, value.getValue().getBytes().length);
-                for (int j = 0; j < ipBytes.length; j++) {
-                    ipBytes[j] &= ipsWithMaskValues[i][1][j];
-                }
-
-                assertArrayEquals(ipBytes, value.getValue().getBytes());
-                assertThat(String.format("Byte comparison for mask of %s (%s)", ipsWithMask[i], value),
-                        value.getMask().getBytes(), CoreMatchers.equalTo(ipsWithMaskValues[i][1]));
             }
+            IPv4Address mask = value.getMask();
+            if (ipsWithMaskLengths[i] == -1) {
+                assertFalse(mask.isCidrMask());
+                try {
+                    mask.asCidrMaskLength();
+                    fail("Expected IllegalStateException not thrown");
+                } catch(IllegalStateException e) {
+                    //expected
+                }
+            } else {
+                assertTrue(mask.isCidrMask());
+                assertEquals(ipsWithMaskLengths[i], mask.asCidrMaskLength());
+            }
+            assertArrayEquals(ipsWithMaskValues[i][1], mask.getBytes());
+            byte[] ipBytes = new byte[4];
+            System.arraycopy(ipsWithMaskValues[i][0], 0, ipBytes, 0, 4);
+            assertEquals(ipBytes.length, value.getValue().getBytes().length);
+            for (int j = 0; j < ipBytes.length; j++) {
+                ipBytes[j] &= ipsWithMaskValues[i][1][j];
+            }
+
+            assertArrayEquals(ipBytes, value.getValue().getBytes());
+            assertThat(String.format("Byte comparison for mask of %s (%s)", ipsWithMask[i], value),
+                    value.getMask().getBytes(), CoreMatchers.equalTo(ipsWithMaskValues[i][1]));
+        }
+    }
+
+    @Test
+    public void testOfMaskedInvalid() throws Exception {
+        for(String invalid : invalidIpsWithMask) {
+            try {
+                IPv4Address.of(invalid);
+                fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
+            } catch(IllegalArgumentException e) {
+                // ok
+            }
+        }
+    }
+
+    @Test
+    public void testSuperclass() throws Exception {
+        for(String ipString: testStrings) {
+            IPAddress<?> superIp = IPAddress.of(ipString);
+            assertEquals(IPVersion.IPv4, superIp.getIpVersion());
+            assertEquals(IPv4Address.of(ipString), superIp);
+        }
+
+        for(String ipMaskedString: ipsWithMask) {
+            IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
+            assertEquals(IPVersion.IPv4, superIp.getIpVersion());
+            assertEquals(IPv4AddressWithMask.of(ipMaskedString), superIp);
+        }
+    }
+
+    @Test
+    public void testOfExceptions() {
+        // We check if the message of a caught NPE is set to a useful message
+        // as a hacky way of verifying that we got an NPE thrown by use rather
+        // than one the JVM created for a null access.
+        try {
+            String s = null;
+            IPv4Address.of(s);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            byte[] b = null;
+            IPv4Address.of(b);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            byte[] b = new byte[3];
+            IPv4Address.of(b);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            byte[] b = new byte[5];
+            IPv4Address.of(b);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            IPv4AddressWithMask.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPv4AddressWithMask.of(IPv4Address.of("1.2.3.4"), null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPv4AddressWithMask.of(null, IPv4Address.of("255.0.0.0"));
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
         }
     }
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
index 6eb5743..c521292 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -1,9 +1,6 @@
 package org.projectfloodlight.openflow.types;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -31,6 +28,7 @@
     private class WithMaskTaskCase {
         final String input;
         boolean hasMask;
+        int expectedMaskLength = 128;
         byte[] expectedMask = hex.decode("ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff".replaceAll(" ", ""));
 
         public WithMaskTaskCase(String input) {
@@ -45,22 +43,73 @@
             return this;
         }
 
+        public WithMaskTaskCase expectedMaskLength(int expectedLength) {
+            this.expectedMaskLength = expectedLength;
+            return this;
+        }
+
     }
 
     WithMaskTaskCase[] withMasks = new WithMaskTaskCase[] {
             new WithMaskTaskCase("1::1/80")
-                .maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00"),
+                .maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00")
+                .expectedMaskLength(80),
 
             new WithMaskTaskCase("ffff:ffee:1::/ff00:ff00:ff00:ff00::")
-                .maskHex("ff 00 ff 00 ff 00 ff 00 00 00 00 00 00 00 00 00"),
+                .maskHex("ff 00 ff 00 ff 00 ff 00 00 00 00 00 00 00 00 00")
+                .expectedMaskLength(-1),
+            new WithMaskTaskCase("1:2:3:4:5:6:7:8/1::ff00:ff00")
+                .maskHex("00 01 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
+                .expectedMaskLength(-1),
+            new WithMaskTaskCase("1:2:3:4:5:6:7:8/::ff00:ff00")
+                .maskHex("00 00 00 00 00 00 00 00 00 00 00 00 ff 00 ff 00")
+                .expectedMaskLength(-1),
+            new WithMaskTaskCase("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff::ff00:ff00")
+                .maskHex("ff ff ff ff ff ff ff ff ff ff 00 00 ff 00 ff 00")
+                .expectedMaskLength(-1),
             new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
             new WithMaskTaskCase("8:8:8:8:8:8:8:8"),
             new WithMaskTaskCase("1:2:3:4:5:6:7:8/128"),
             new WithMaskTaskCase("::/0")
                 .maskHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")
+                .expectedMaskLength(0),
     };
 
     @Test
+    public void testConstants() {
+        byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                         (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                         (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+                         (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
+        byte[] ones = { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+                        (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+                        (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+                        (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
+        // Make sure class initializtation and static assignment don't get
+        // messed up. Test everything twice for cached values
+        assertTrue(IPv6Address.NONE.isCidrMask());
+        assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
+        assertTrue(IPv6Address.NONE.isCidrMask());
+        assertEquals(0, IPv6Address.NONE.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv6Address.NONE.getBytes());
+
+        assertTrue(IPv6Address.NO_MASK.isCidrMask());
+        assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
+        assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
+        assertTrue(IPv6Address.NO_MASK.isCidrMask());
+        assertEquals(128, IPv6Address.NO_MASK.asCidrMaskLength());
+        assertArrayEquals(ones, IPv6Address.NO_MASK.getBytes());
+
+        assertTrue(IPv6Address.FULL_MASK.isCidrMask());
+        assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
+        assertTrue(IPv6Address.FULL_MASK.isCidrMask());
+        assertEquals(0, IPv6Address.FULL_MASK.asCidrMaskLength());
+        assertArrayEquals(zeros, IPv6Address.FULL_MASK.getBytes());
+    }
+
+    @Test
     public void testMasked() throws UnknownHostException {
         for(WithMaskTaskCase w: withMasks) {
             IPv6AddressWithMask value = IPv6AddressWithMask.of(w.input);
@@ -70,19 +119,37 @@
 
                 assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
                 assertEquals(w.input.split("/")[0], ip.toString());
-            } else {
-                InetAddress inetAddress = InetAddress.getByName(w.input.substring(0, w.input.indexOf('/')));
-
-                byte[] address = inetAddress.getAddress();
-                assertEquals(address.length, value.getValue().getBytes().length);
-
-                for (int j = 0; j < address.length; j++) {
-                    address[j] &= w.expectedMask[j];
-                }
-
-                assertThat("Address bytes for input " + w.input + ", value=" + value, value.getValue().getBytes(), CoreMatchers.equalTo(address));
-                assertThat("mask check for input " + w.input + ", value=" + value, value.getMask().getBytes(), CoreMatchers.equalTo(w.expectedMask));
             }
+            InetAddress inetAddress = InetAddress.getByName(w.input.split("/")[0]);
+
+            if (w.expectedMaskLength == -1) {
+                assertFalse(value.getMask().isCidrMask());
+                try {
+                    value.getMask().asCidrMaskLength();
+                    fail("Expected IllegalStateException not thrown");
+                } catch(IllegalStateException e) {
+                    //expected
+                }
+            } else {
+                assertTrue(value.getMask().isCidrMask());
+                assertEquals("Input " + w.input, w.expectedMaskLength,
+                             value.getMask().asCidrMaskLength());
+            }
+
+            byte[] address = inetAddress.getAddress();
+            assertEquals(address.length, value.getValue().getBytes().length);
+
+            for (int j = 0; j < address.length; j++) {
+                address[j] &= w.expectedMask[j];
+            }
+
+            assertThat("Address bytes for input " + w.input + ", value=" + value, value.getValue().getBytes(), CoreMatchers.equalTo(address));
+            assertThat("mask check for input " + w.input + ", value=" + value, value.getMask().getBytes(), CoreMatchers.equalTo(w.expectedMask));
+        }
+        for (int i = 0; i <= 128; i++) {
+            String ipString = String.format("8001:2::1/%d", i);
+            IPv6AddressWithMask value = IPv6AddressWithMask.of(ipString);
+            assertEquals("Input " + ipString, i, value.getMask().asCidrMaskLength());
         }
     }
 
@@ -150,4 +217,70 @@
         assertEquals("1::4:5:6:0:8", IPv6Address.of("1:0:0:4:5:6:0:8").toString(true, false));
         assertEquals("1:0:0:4::8", IPv6Address.of("1:0:0:4:0:0:0:8").toString(true, false));
     }
+
+    @Test
+    public void testSuperclass() throws Exception {
+        for(String ipString: testStrings) {
+            IPAddress<?> superIp = IPAddress.of(ipString);
+            assertEquals(IPVersion.IPv6, superIp.getIpVersion());
+            assertEquals(IPv6Address.of(ipString), superIp);
+        }
+
+        for(WithMaskTaskCase w: withMasks) {
+            String ipMaskedString = w.input;
+            IPAddressWithMask<?> superIp = IPAddressWithMask.of(ipMaskedString);
+            assertEquals(IPVersion.IPv6, superIp.getIpVersion());
+            assertEquals(IPv6AddressWithMask.of(ipMaskedString), superIp);
+        }
+    }
+
+    @Test
+    public void testOfExceptions() throws Exception {
+        try {
+            IPv6AddressWithMask.of(null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            String s = null;
+            IPv6Address.of(s);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            byte[] b = null;
+            IPv6Address.of(b);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            byte[] b = new byte[7];
+            IPv6Address.of(b);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            byte[] b = new byte[9];
+            IPv6Address.of(b);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            IPv6AddressWithMask.of(IPv6Address.of("1::"), null);
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+        try {
+            IPv6AddressWithMask.of(null, IPv6Address.of("255::"));
+            fail("Should have thrown NullPointerException");
+        } catch (NullPointerException e) {
+            assertNotNull(e.getMessage());
+        }
+    }
 }
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index cf7334d..0c95916 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -7,8 +7,12 @@
 import java.util.Map;
 import org.projectfloodlight.openflow.protocol.*;
 import org.projectfloodlight.openflow.protocol.action.*;
+import org.projectfloodlight.openflow.protocol.actionid.*;
+import org.projectfloodlight.openflow.protocol.bsntlv.*;
+import org.projectfloodlight.openflow.protocol.errormsg.*;
 import org.projectfloodlight.openflow.protocol.meterband.*;
 import org.projectfloodlight.openflow.protocol.instruction.*;
+import org.projectfloodlight.openflow.protocol.instructionid.*;
 import org.projectfloodlight.openflow.protocol.match.*;
 import org.projectfloodlight.openflow.protocol.oxm.*;
 import org.projectfloodlight.openflow.protocol.queueprop.*;
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.java b/java_gen/templates/custom/OFMatchV1Ver10.java
index 7817f10..8a24b2f 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.java
@@ -328,10 +328,10 @@
                 return srcCidrLen > 0 && srcCidrLen < 32;
             case ARP_TPA:
             case IPV4_DST:
-                int dstCidrLen = getIpv4SrcCidrMaskLen();
+                int dstCidrLen = getIpv4DstCidrMaskLen();
                 return dstCidrLen > 0 && dstCidrLen < 32;
             default:
-                throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
+                return false;
         }
     }
 
diff --git a/java_gen/templates/custom/OFMatchV1Ver10_toString.java b/java_gen/templates/custom/OFMatchV1Ver10_toString.java
new file mode 100644
index 0000000..3b2783b
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV1Ver10_toString.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatch_toString.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatchV3Ver13_toString.java b/java_gen/templates/custom/OFMatchV3Ver13_toString.java
new file mode 100644
index 0000000..3b2783b
--- /dev/null
+++ b/java_gen/templates/custom/OFMatchV3Ver13_toString.java
@@ -0,0 +1 @@
+//:: include("custom/OFMatch_toString.java", msg=msg, has_parent=False)
diff --git a/java_gen/templates/custom/OFMatch_toString.java b/java_gen/templates/custom/OFMatch_toString.java
new file mode 100644
index 0000000..1eaf8a5
--- /dev/null
+++ b/java_gen/templates/custom/OFMatch_toString.java
@@ -0,0 +1,18 @@
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder("${msg.name}(");
+        boolean first = true;
+        for(MatchField<?> field : getMatchFields()) {
+            if(first)
+                first = false;
+            else
+                b.append(", ");
+            String name = field.getName();
+            b.append(name).append('=').append(this.get(field));
+            if(isPartiallyMasked(field)) {
+                b.append('/').append(this.getMasked(field).getMask());
+            }
+        }
+        b.append(")");
+        return b.toString();
+    }
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index b35df1c..f1d72b2 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -363,6 +363,9 @@
         }
     }
 
+    //:: if os.path.exists("%s/custom/%s_toString.java" % (template_dir, msg.name)):
+    //:: include("custom/%s_toString.java" % msg.name, msg=msg, has_parent=False)
+    //:: else:
     @Override
     public String toString() {
         StringBuilder b = new StringBuilder("${msg.name}(");
@@ -375,7 +378,7 @@
         b.append(")");
         return b.toString();
     }
-
+    //:: #endif
 
     @Override
     public boolean equals(Object obj) {
diff --git a/lang_c.py b/lang_c.py
index 762f82c..0a881e9 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -41,6 +41,7 @@
 import c_gen.c_show_gen as c_show_gen
 import c_gen.c_validator_gen as c_validator_gen
 import c_gen.util
+import c_gen.codegen
 import loxi_utils.loxi_utils as loxi_utils
 import template_utils
 
@@ -71,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,
@@ -83,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,
@@ -115,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()
@@ -173,3 +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.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)
diff --git a/lang_python.py b/lang_python.py
index f40cecc..019b62d 100644
--- a/lang_python.py
+++ b/lang_python.py
@@ -50,6 +50,8 @@
             of12: ...           # (code generation incomplete)
                 oxm.py          # OXM classes
             of13: ...           # (code generation incomplete)
+                action_id.py    # Action ID classes
+                instruction_id.py # Instruction ID classes
                 meter_band.py   # Meter band classes
 
 The user will add the pyloxi directory to PYTHONPATH. Then they can
@@ -83,7 +85,7 @@
     1: ["action", "common", "const", "message", "util"],
     2: ["action", "common", "const", "instruction", "message", "util"],
     3: ["action", "common", "const", "instruction", "message", "oxm", "util"],
-    4: ["action", "common", "const", "instruction", "message", "meter_band", "oxm", "util"],
+    4: ["action", "action_id", "common", "const", "instruction", "instruction_id", "message", "meter_band", "oxm", "bsn_tlv", "util"],
 }
 
 def make_gen(name, version):
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index 545b5bc..bc79ed9 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -52,10 +52,11 @@
         if m_ast[2] == 'length' or m_ast[2] == 'len': # Should be moved to parser
             return ir.OFLengthMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
         elif m_ast[2] == 'actions_len':
-            # HACK only usage so far
             return ir.OFFieldLengthMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx), field_name='actions')
         if m_ast[2] == 'version': # Should be moved to parser
             return ir.OFVersionMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
+        elif m_ast[2] == 'key_length':
+            return ir.OFFieldLengthMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx), field_name='key')
         else:
             return ir.OFDataMember(name=m_ast[2], oftype=get_type(m_ast[1], ctx))
     elif m_ast[0] == 'discriminator':
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index aaa54ca..6a053c6 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -187,6 +187,10 @@
     def has_external_alignment(self):
         return self.params.get('length_includes_align') == 'False'
 
+    @property
+    def has_type_members(self):
+        return find(lambda m: isinstance(m, OFTypeMember), self.members) is not None
+
 """ one class unified across openflow versions. Keeps around a map version->versioned_class """
 class OFUnifiedClass(OFClass):
     def __new__(cls, version_classes, *a, **kw):
@@ -423,9 +427,52 @@
         build_touch_classes.remove(name)
         return c
 
+    def build_id_class(orig_name, base_name):
+        name = base_name + '_id' + orig_name[len(base_name):]
+        if name in name_classes:
+            return name_classes[name]
+        orig_fe, _ = name_frontend_classes[orig_name]
+
+        if orig_fe.superclass:
+            superclass_name = base_name + '_id' + orig_fe.superclass[len(base_name):]
+            superclass = build_id_class(orig_fe.superclass, base_name)
+        else:
+            superclass_name = None
+            superclass = None
+
+        fe = frontend_ir.OFClass(
+            name=name,
+            superclass=superclass_name,
+            members=[m for m in orig_fe.members if not isinstance(m, frontend_ir.OFDataMember)],
+            virtual=orig_fe.virtual,
+            params={})
+
+        base_length, is_fixed_length, member_lengths = \
+           ir_offset.calc_lengths(version, fe, name_classes, name_enums)
+        assert fe.virtual or is_fixed_length
+
+        members = []
+        c = OFClass(name=fe.name, superclass=superclass,
+                members=members, virtual=fe.virtual, params=fe.params,
+                is_fixed_length=is_fixed_length, base_length=base_length)
+
+        members.extend( build_member(c, fe_member, member_lengths[fe_member])
+                  for fe_member in fe.members)
+
+        name_classes[name] = c
+        return c
+
+    id_class_roots = ["of_action", "of_instruction"]
+
     for name in sorted(name_frontend_classes.keys()):
         c = build_class(name)
 
+        # Build ID classes for OF 1.3+
+        if version.wire_version >= 4:
+            for root in id_class_roots:
+                if c.is_instanceof(root):
+                    build_id_class(name, root)
+
     protocol = OFProtocol(version=version, classes=tuple(name_classes.values()), enums=tuple(name_enums.values()))
     for e in chain(protocol.classes, protocol.enums):
         e.protocol = protocol
diff --git a/loxi_ir/ir_offset.py b/loxi_ir/ir_offset.py
index 0f27f5e..e705fcc 100644
--- a/loxi_ir/ir_offset.py
+++ b/loxi_ir/ir_offset.py
@@ -100,6 +100,7 @@
     of_match_v3_t = (8, False),
     of_octets_t = (0, False),
     of_bitmap_128_t = (16, True),
+    of_checksum_128_t = (16, True),
 )
 
 def type_dec_to_count_base(m_type):
diff --git a/loxi_utils/loxi_utils.py b/loxi_utils/loxi_utils.py
index d5937ac..865891f 100644
--- a/loxi_utils/loxi_utils.py
+++ b/loxi_utils/loxi_utils.py
@@ -145,12 +145,21 @@
     u = _unified_by_name(cls)
     return u.is_instanceof("of_stats_request") or u.ir_instanceof("of_stats_reply")
 
+def class_is_bsn_tlv(cls):
+    """
+    Return True if cls_name is a bsn_tlv object
+    """
+    return _unified_by_name(cls).is_instanceof("of_bsn_tlv")
+
 def class_is_list(cls):
     """
     Return True if cls_name is a list object
     """
     return (cls.find("of_list_") == 0)
 
+def class_is(cls, cand_name):
+    return _unified_by_name(cls).is_instanceof(cand_name)
+
 def type_is_of_object(m_type):
     """
     Return True if m_type is an OF object type
diff --git a/openflow_input/bsn_arp_offload b/openflow_input/bsn_arp_offload
new file mode 100644
index 0000000..5a229b1
--- /dev/null
+++ b/openflow_input/bsn_arp_offload
@@ -0,0 +1,40 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// Also derived from the OpenFlow header files which have these copyrights:
+// Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
+// Copyright (c) 2011, 2012 Open Networking Foundation
+
+#version 4
+
+struct of_instruction_bsn_arp_offload : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 1;
+    pad(4);
+};
diff --git a/openflow_input/bsn_controller_connections b/openflow_input/bsn_controller_connections
new file mode 100644
index 0000000..eae315e
--- /dev/null
+++ b/openflow_input/bsn_controller_connections
@@ -0,0 +1,71 @@
+// 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.
+
+// Retrieve a list of configured controller connections and their status.
+// When auxiliary connections are used there may be multiple connections
+// to the same controller. All connections to a given controller will
+// share the same role (so there may be multiple master connections in
+// the list).
+
+// The URIs are of the form tcp://1.2.3.4:6553
+
+#version 4
+
+enum ofp_bsn_controller_connection_state(wire_type=uint8_t) {
+    OFP_BSN_CONTROLLER_CONNECTION_STATE_DISCONNECTED = 0,
+    OFP_BSN_CONTROLLER_CONNECTION_STATE_CONNECTED = 1,
+};
+
+struct of_bsn_controller_connections_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 56;
+};
+
+struct of_bsn_controller_connection {
+    enum ofp_bsn_controller_connection_state state;
+    uint8_t auxiliary_id;
+    pad(2);
+    enum ofp_controller_role role;
+    of_desc_str_t uri;
+};
+
+struct of_bsn_controller_connections_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 57;
+    list(of_bsn_controller_connection_t) connections;
+};
diff --git a/openflow_input/bsn_gentable b/openflow_input/bsn_gentable
new file mode 100644
index 0000000..674d298
--- /dev/null
+++ b/openflow_input/bsn_gentable
@@ -0,0 +1,353 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+
+// We have a number of switch agents that need to be configured by the
+// controller and report stats. Some of them will have large tables (1000+
+// entries) and so need an efficient synchronization mechanism (as can be
+// accomplished using the cookie field in flowtable entries). It's a
+// significant amount of work to do this from scratch for each new table.
+// This extension (and the corresponding Indigo code) provides a framework
+// to ease implementing new tables.
+
+// We don't plan on replacing our use of the OpenFlow flow table and group
+// table with this scheme. This is intended for controlling switch
+// functionality like the ARP and LACP agents which don't map at all to
+// flow-mods.
+
+// Each switch will have a number of tables indexed by a 16-bit table ID. Each
+// table has a name, id, a set of entries, and an array of checksum buckets.
+// There is no order to the entries; stats requests will return them in an
+// arbitrary order. The controller is expected to use the table name to
+// determine the semantics of a table.
+
+// Each entry has a key, value, stats, and checksum. The key and value are TLV
+// lists given by the controller in a gentable_entry_add message. The switch must
+// return these lists in stats replies exactly as it received them. The stats
+// are a list of TLVs controlled by the switch. The stats are expected to
+// include more than simple counters (for example, last hit time or seen TCP
+// flags). The checksum is an opaque value used for table synchronization.
+
+// LOXI includes a built-in type of_checksum_128_t, which is 128 bits but
+// only requires 32-bit alignment.
+
+
+// These TLV classes are used for keys, values, and stats. Like OXM, lists of
+// TLVs are tightly packed without padding. TLV lists may include duplicates
+// and the semantics of this is left to the particular table.
+//
+// If this is eventually standardized it would be good to add a "class" type
+// member as in OXM.
+struct of_bsn_tlv {
+    uint16_t type == ?;
+    uint16_t length;
+};
+
+
+// This message sets key=value in the given table. If key already exists in the
+// table then it modifies the value, preserving stats.
+//
+// If the switch cannot process the message then it should reply with an error
+// message. The contents of the table must not be changed in case of an error.
+struct of_bsn_gentable_entry_add : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 46;
+    uint16_t table_id;
+    uint16_t key_length;
+    of_checksum_128_t checksum;
+    list(of_bsn_tlv_t) key;
+    list(of_bsn_tlv_t) value;
+};
+
+
+// This message deletes the entry with the given key in the given table.
+//
+// If the switch cannot process the message then it should reply with an error
+// message. The contents of the table must not be changed in case of an error.
+// If the key does not exist in the table an error message will be generated.
+struct of_bsn_gentable_entry_delete : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 47;
+    uint16_t table_id;
+    list(of_bsn_tlv_t) key;
+};
+
+
+// This message deletes a range of table entries. The checksum_mask must be a
+// prefix mask. The checksum must be zero in the bits where the checksum_mask
+// is zero.
+//
+// The switch may fail to delete some table entries. No error messages will be
+// sent, but the error_count in the reply message will be incremented.
+struct of_bsn_gentable_clear_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 48;
+    uint16_t table_id;
+    pad(2);
+    of_checksum_128_t checksum;
+    of_checksum_128_t checksum_mask;
+};
+
+struct of_bsn_gentable_clear_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 49;
+    uint16_t table_id;
+    pad(2);
+    uint32_t deleted_count;
+    uint32_t error_count;
+};
+
+
+// This message sets the size of the buckets array. The switch may reject this
+// message if the table has entries. buckets_size must be a power of 2.
+struct of_bsn_gentable_set_buckets_size : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 50;
+    uint16_t table_id;
+    pad(2);
+    uint32_t buckets_size;
+};
+
+
+// Retrieve the configuration state (key, value, and checksum) for each table
+// entry in a range of buckets.
+//
+// The checksum_mask must be a prefix mask. The checksum must be zero in the
+// bits where the checksum_mask is zero.
+struct of_bsn_gentable_entry_desc_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 2;
+    uint16_t table_id;
+    pad(2);
+    of_checksum_128_t checksum;
+    of_checksum_128_t checksum_mask;
+};
+
+struct of_bsn_gentable_entry_desc_stats_entry {
+    uint16_t length;
+    uint16_t key_length;
+    of_checksum_128_t checksum;
+    list(of_bsn_tlv_t) key;
+    list(of_bsn_tlv_t) value;
+};
+
+struct of_bsn_gentable_entry_desc_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 2;
+    list(of_bsn_gentable_entry_desc_stats_entry_t) entries;
+};
+
+
+// Retrieve the runtime state (key and stats) for each table entry in a range
+// of buckets.
+//
+// The checksum_mask must be a prefix mask. The checksum must be zero in the
+// bits where the checksum_mask is zero.
+struct of_bsn_gentable_entry_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 3;
+    uint16_t table_id;
+    pad(2);
+    of_checksum_128_t checksum;
+    of_checksum_128_t checksum_mask;
+};
+
+struct of_bsn_gentable_entry_stats_entry {
+    uint16_t length;
+    uint16_t key_length;
+    list(of_bsn_tlv_t) key;
+    list(of_bsn_tlv_t) stats;
+};
+
+struct of_bsn_gentable_entry_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 3;
+    list(of_bsn_gentable_entry_stats_entry_t) entries;
+};
+
+
+// Retrieve the description for all tables.
+struct of_bsn_gentable_desc_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 4;
+};
+
+struct of_bsn_gentable_desc_stats_entry {
+    uint16_t length;
+    uint16_t table_id;
+    of_table_name_t name;
+    uint32_t buckets_size;
+    uint32_t max_entries;
+    pad(4);
+    /* TODO properties */
+};
+
+struct of_bsn_gentable_desc_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 4;
+    list(of_bsn_gentable_desc_stats_entry_t) entries;
+};
+
+
+// Retrieves stats for every table. This includes the total checksum, so the
+// controller can quickly check whether the whole table is in sync.
+//
+// The checksum of a table is the XOR of the checksums of all entries in the
+// table.
+struct of_bsn_gentable_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 7;
+};
+
+struct of_bsn_gentable_stats_entry {
+    uint16_t table_id;
+    pad(2);
+    uint32_t entry_count;
+    of_checksum_128_t checksum;
+};
+
+struct of_bsn_gentable_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 7;
+    list(of_bsn_gentable_stats_entry_t) entries;
+};
+
+
+// Retrieves the checksum for every bucket in a table. The entries are ordered
+// by bucket index.
+//
+// The checksum of a bucket is the XOR of the checksums of all entries in the
+// bucket.
+struct of_bsn_gentable_bucket_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 5;
+    uint16_t table_id;
+};
+
+struct of_bsn_gentable_bucket_stats_entry {
+    of_checksum_128_t checksum;
+};
+
+struct of_bsn_gentable_bucket_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 5;
+    list(of_bsn_gentable_bucket_stats_entry_t) entries;
+};
diff --git a/openflow_input/bsn_global_vrf_allowed b/openflow_input/bsn_global_vrf_allowed
index 543c6fd..ee26308 100644
--- a/openflow_input/bsn_global_vrf_allowed
+++ b/openflow_input/bsn_global_vrf_allowed
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_global_vrf_allowed_masked : of_oxm {
-    uint32_t type_len == 0x00030701;
+    uint32_t type_len == 0x00030702;
     uint8_t value;
     uint8_t value_mask;
 };
diff --git a/openflow_input/bsn_in_ports b/openflow_input/bsn_in_ports
index 05003b9..b23df63 100644
--- a/openflow_input/bsn_in_ports
+++ b/openflow_input/bsn_in_ports
@@ -50,7 +50,7 @@
  */
 
 struct of_oxm_bsn_in_ports_128 : of_oxm {
-    uint32_t type_len == 0x00030020;
+    uint32_t type_len == 0x00030010;
     of_bitmap_128_t value;
 };
 
diff --git a/openflow_input/bsn_l3_dst_class_id b/openflow_input/bsn_l3_dst_class_id
index 385add7..8d324a1 100644
--- a/openflow_input/bsn_l3_dst_class_id
+++ b/openflow_input/bsn_l3_dst_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_dst_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030d04;
+    uint32_t type_len == 0x00030d08;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_l3_interface_class_id b/openflow_input/bsn_l3_interface_class_id
index efeb949..80d1e37 100644
--- a/openflow_input/bsn_l3_interface_class_id
+++ b/openflow_input/bsn_l3_interface_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_interface_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030904;
+    uint32_t type_len == 0x00030908;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_l3_src_class_id b/openflow_input/bsn_l3_src_class_id
index f18aab9..58f60c6 100644
--- a/openflow_input/bsn_l3_src_class_id
+++ b/openflow_input/bsn_l3_src_class_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_l3_src_class_id_masked : of_oxm {
-    uint32_t type_len == 0x00030b04;
+    uint32_t type_len == 0x00030b08;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_lag_id b/openflow_input/bsn_lag_id
index c96c1d6..63645a3 100644
--- a/openflow_input/bsn_lag_id
+++ b/openflow_input/bsn_lag_id
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_lag_id_masked : of_oxm {
-    uint32_t type_len == 0x00030304;
+    uint32_t type_len == 0x00030308;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/bsn_port_counter b/openflow_input/bsn_port_counter
new file mode 100644
index 0000000..f3d149f
--- /dev/null
+++ b/openflow_input/bsn_port_counter
@@ -0,0 +1,79 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+
+enum ofp_bsn_port_counter(wire_type=uint8_t, complete=False) {
+  OFP_BSN_PORT_COUNTER_RX_BYTES = 0,
+  OFP_BSN_PORT_COUNTER_RX_PACKETS_UNICAST = 1,
+  OFP_BSN_PORT_COUNTER_RX_PACKETS_BROADCAST = 2,
+  OFP_BSN_PORT_COUNTER_RX_PACKETS_MULTICAST = 3,
+  OFP_BSN_PORT_COUNTER_RX_DROPPED = 4,
+  OFP_BSN_PORT_COUNTER_RX_ERRORS = 5,
+  OFP_BSN_PORT_COUNTER_TX_BYTES = 6,
+  OFP_BSN_PORT_COUNTER_TX_PACKETS_UNICAST = 7,
+  OFP_BSN_PORT_COUNTER_TX_PACKETS_BROADCAST = 8,
+  OFP_BSN_PORT_COUNTER_TX_PACKETS_MULTICAST = 9,
+  OFP_BSN_PORT_COUNTER_TX_DROPPED = 10,
+  OFP_BSN_PORT_COUNTER_TX_ERRORS = 11,
+};
+
+struct of_bsn_port_counter_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 8;
+    of_port_no_t port_no;
+};
+
+struct of_bsn_port_counter_stats_entry {
+    uint16_t length;
+    pad(2);
+    of_port_no_t port_no;
+    list(of_uint64_t) values;
+};
+
+struct of_bsn_port_counter_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 8;
+    list(of_bsn_port_counter_stats_entry_t) entries;
+};
diff --git a/openflow_input/bsn_role_status b/openflow_input/bsn_role_status
new file mode 100644
index 0000000..f53ff23
--- /dev/null
+++ b/openflow_input/bsn_role_status
@@ -0,0 +1,55 @@
+// 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.
+
+// Backport the OpenFlow 1.4 role status message
+//
+// This message will be sent when a controller's role changes for any reason
+// other than it using OFPT_ROLE_REQUEST.
+
+#version 4
+
+enum ofp_bsn_controller_role_reason(wire_type=uint8_t) {
+    OFP_BSN_CONTROLLER_ROLE_REASON_MASTER_REQUEST = 0,
+    OFP_BSN_CONTROLLER_ROLE_REASON_CONFIG = 1,
+    OFP_BSN_CONTROLLER_ROLE_REASON_EXPERIMENTER = 2,
+};
+
+struct of_bsn_role_status : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 55;
+    enum ofp_controller_role role;
+    enum ofp_bsn_controller_role_reason reason;
+    pad(3);
+    uint64_t generation_id;
+};
diff --git a/openflow_input/bsn_tlv b/openflow_input/bsn_tlv
new file mode 100644
index 0000000..ec91065
--- /dev/null
+++ b/openflow_input/bsn_tlv
@@ -0,0 +1,114 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+
+struct of_bsn_tlv_port : of_bsn_tlv {
+    uint16_t type == 0;
+    uint16_t length;
+    of_port_no_t value;
+};
+
+struct of_bsn_tlv_mac : of_bsn_tlv {
+    uint16_t type == 1;
+    uint16_t length;
+    of_mac_addr_t value;
+};
+
+struct of_bsn_tlv_rx_packets : of_bsn_tlv {
+    uint16_t type == 2;
+    uint16_t length;
+    uint64_t value;
+};
+
+struct of_bsn_tlv_tx_packets : of_bsn_tlv {
+    uint16_t type == 3;
+    uint16_t length;
+    uint64_t value;
+};
+
+struct of_bsn_tlv_ipv4 : of_bsn_tlv {
+    uint16_t type == 4;
+    uint16_t length;
+    of_ipv4_t value;
+};
+
+struct of_bsn_tlv_idle_time : of_bsn_tlv {
+    uint16_t type == 5;
+    uint16_t length;
+    uint64_t value; /* Milliseconds */
+};
+
+struct of_bsn_tlv_vlan_vid : of_bsn_tlv {
+    uint16_t type == 6;
+    uint16_t length;
+    uint16_t value;
+};
+
+struct of_bsn_tlv_idle_notification : of_bsn_tlv {
+    uint16_t type == 7;
+    uint16_t length;
+};
+
+struct of_bsn_tlv_idle_timeout : of_bsn_tlv {
+    uint16_t type == 8;
+    uint16_t length;
+    uint32_t value; /* Milliseconds */
+};
+
+struct of_bsn_tlv_unicast_query_timeout : of_bsn_tlv {
+    uint16_t type == 9;
+    uint16_t length;
+    uint32_t value; /* Milliseconds */
+};
+
+struct of_bsn_tlv_broadcast_query_timeout : of_bsn_tlv {
+    uint16_t type == 10;
+    uint16_t length;
+    uint32_t value; /* Milliseconds */
+};
+
+struct of_bsn_tlv_request_packets : of_bsn_tlv {
+    uint16_t type == 11;
+    uint16_t length;
+    uint64_t value;
+};
+
+struct of_bsn_tlv_reply_packets : of_bsn_tlv {
+    uint16_t type == 12;
+    uint16_t length;
+    uint64_t value;
+};
+
+struct of_bsn_tlv_miss_packets : of_bsn_tlv {
+    uint16_t type == 13;
+    uint16_t length;
+    uint64_t value;
+};
diff --git a/openflow_input/bsn_vlan_counter b/openflow_input/bsn_vlan_counter
new file mode 100644
index 0000000..51dd356
--- /dev/null
+++ b/openflow_input/bsn_vlan_counter
@@ -0,0 +1,71 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+
+enum of_bsn_vlan_counter_t(wire_type=uint8_t, complete=False) {
+  OFP_BSN_VLAN_COUNTER_RX_BYTES = 0,
+  OFP_BSN_VLAN_COUNTER_RX_PACKETS = 1,
+  OFP_BSN_VLAN_COUNTER_TX_BYTES = 2,
+  OFP_BSN_VLAN_COUNTER_TX_PACKETS = 3,
+};
+
+struct of_bsn_vlan_counter_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 9;
+    uint16_t vlan_vid;
+};
+
+struct of_bsn_vlan_counter_stats_entry {
+    uint16_t length;
+    uint16_t vlan_vid;
+    pad(4);
+    list(of_uint64_t) values;
+};
+
+struct of_bsn_vlan_counter_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 9;
+    list(of_bsn_vlan_counter_stats_entry_t) entries;
+};
diff --git a/openflow_input/bsn_vrf b/openflow_input/bsn_vrf
index 3641faa..26959bd 100644
--- a/openflow_input/bsn_vrf
+++ b/openflow_input/bsn_vrf
@@ -41,7 +41,7 @@
 };
 
 struct of_oxm_bsn_vrf_masked : of_oxm {
-    uint32_t type_len == 0x00030504;
+    uint32_t type_len == 0x00030508;
     uint32_t value;
     uint32_t value_mask;
 };
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index 87adcc4..bb85231 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -284,6 +284,13 @@
     OFPR_BSN_STATION_MOVE = 129,
     OFPR_BSN_BAD_VLAN = 130,
     OFPR_BSN_DESTINATION_LOOKUP_FAILURE = 131,
+    OFPR_BSN_NO_ROUTE = 132,
+    OFPR_BSN_ICMP_ECHO_REQUEST = 133,
+    OFPR_BSN_DEST_NETWORK_UNREACHABLE = 134,
+    OFPR_BSN_DEST_HOST_UNREACHABLE = 135,
+    OFPR_BSN_DEST_PORT_UNREACHABLE = 136,
+    OFPR_BSN_FRAGMENTATION_REQUIRED = 137,
+    OFPR_BSN_ARP = 139,
 };
 
 enum ofp_flow_removed_reason(wire_type=uint8_t) {
@@ -567,6 +574,10 @@
     uint32_t xid;
 };
 
+struct of_uint64 {
+    uint64_t value;
+};
+
 // Special structures used for managing scalar list elements
 struct of_uint32 {
     uint32_t value;
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index 2c4a135..44b4814 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -40,9 +40,12 @@
 roots = {
     'of_header': 'message',
     'of_action': 'action',
+    'of_action_id': 'action_id',
     'of_oxm': 'oxm',
     'of_instruction': 'instruction',
+    'of_instruction_id': 'instruction_id',
     'of_meter_band': 'meter_band',
+    'of_bsn_tlv': 'bsn_tlv',
 }
 
 # Return the module and class names for the generated Python class
@@ -74,6 +77,11 @@
                          ofclasses=modules_by_version[version]['action'],
                          version=version)
 
+def generate_action_id(out, name, version):
+    util.render_template(out, 'module.py',
+                         ofclasses=modules_by_version[version]['action_id'],
+                         version=version)
+
 def generate_oxm(out, name, version):
     util.render_template(out, 'module.py',
                          ofclasses=modules_by_version[version]['oxm'],
@@ -94,6 +102,11 @@
                          ofclasses=modules_by_version[version]['instruction'],
                          version=version)
 
+def generate_instruction_id(out, name, version):
+    util.render_template(out, 'module.py',
+                         ofclasses=modules_by_version[version]['instruction_id'],
+                         version=version)
+
 def generate_message(out, name, version):
     util.render_template(out, 'module.py',
                          ofclasses=modules_by_version[version]['message'],
@@ -111,6 +124,11 @@
 def generate_util(out, name, version):
     util.render_template(out, 'util.py', version=version)
 
+def generate_bsn_tlv(out, name, version):
+    util.render_template(out, 'module.py',
+                         ofclasses=modules_by_version[version]['bsn_tlv'],
+                         version=version)
+
 def init():
     for version in loxi_globals.OFVersions.target_versions:
         modules_by_version[version] = build_ofclasses(version)
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 40bcb40..7e28a0c 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -111,6 +111,11 @@
         init='None',
         pack='%s.pack()',
         unpack='oxm.oxm.unpack(%s)'),
+
+    'of_checksum_128_t': OFTypeData(
+        init='0',
+        pack='util.pack_checksum_128(%s)',
+        unpack="util.unpack_checksum_128(%s)"),
 }
 
 ## Fixed length strings
diff --git a/py_gen/templates/init.py b/py_gen/templates/init.py
index f66e62a..3b73baa 100644
--- a/py_gen/templates/init.py
+++ b/py_gen/templates/init.py
@@ -38,6 +38,7 @@
 :: #endif
 :: if version >= 4:
 import meter_band
+import bsn_tlv
 :: #endif
 from const import *
 from common import *
diff --git a/py_gen/templates/module.py b/py_gen/templates/module.py
index 252bf0d..02f0002 100644
--- a/py_gen/templates/module.py
+++ b/py_gen/templates/module.py
@@ -43,7 +43,10 @@
 import oxm
 :: #endif
 :: if version >= OFVersions.VERSION_1_3:
+import action_id
+import instruction_id
 import meter_band
+import bsn_tlv
 :: #endif
 import util
 import loxi.generic_util
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
index 8ad246a..d690939 100644
--- a/py_gen/templates/util.py
+++ b/py_gen/templates/util.py
@@ -41,6 +41,8 @@
 import oxm
 :: #endif
 :: if version >= OFVersions.VERSION_1_3:
+import action_id
+import instruction_id
 import meter_band
 :: #endif
 
@@ -180,3 +182,10 @@
         except loxi.ProtocolError:
             return None
     return [x for x in loxi.generic_util.unpack_list(reader, deserializer) if x != None]
+
+def pack_checksum_128(value):
+    return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64)
+
+def unpack_checksum_128(reader):
+    hi, lo = reader.read("!QQ")
+    return (hi << 64) | lo
diff --git a/test_data/of10/packet_in.data b/test_data/of10/packet_in.data
index a8de82c..d5ccf32 100644
--- a/test_data/of10/packet_in.data
+++ b/test_data/of10/packet_in.data
@@ -18,7 +18,7 @@
     data='abc')
 -- c
 obj = of_packet_in_new(OF_VERSION_1_0);
-of_packet_in_buffer_id_set(obj, 2882400001);
+of_packet_in_buffer_id_set(obj, 0xabcdef01);
 {
     of_octets_t data = { .bytes=3, .data=(uint8_t *)"\x61\x62\x63" };
     of_packet_in_data_set(obj, &data);
diff --git a/test_data/of10/packet_out.data b/test_data/of10/packet_out.data
index fdd1c3d..a3c642b 100644
--- a/test_data/of10/packet_out.data
+++ b/test_data/of10/packet_out.data
@@ -25,7 +25,7 @@
     data='abc')
 -- c
 obj = of_packet_out_new(OF_VERSION_1_0);
-of_packet_out_buffer_id_set(obj, 2882400001);
+of_packet_out_buffer_id_set(obj, 0xabcdef01);
 of_packet_out_in_port_set(obj, 65534);
 of_packet_out_xid_set(obj, 305419896);
 {
diff --git a/test_data/of10/port_mod.data b/test_data/of10/port_mod.data
index 53e09ce..754e139 100644
--- a/test_data/of10/port_mod.data
+++ b/test_data/of10/port_mod.data
@@ -18,12 +18,12 @@
     advertise=0xCAFE6789)
 -- c
 obj = of_port_mod_new(OF_VERSION_1_0);
-of_port_mod_advertise_set(obj, 3405670281);
-of_port_mod_config_set(obj, 2427178479);
+of_port_mod_advertise_set(obj, 0xCAFE6789);
+of_port_mod_config_set(obj, 0x90ABCDEF);
 {
     of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
     of_port_mod_hw_addr_set(obj, hw_addr);
 }
-of_port_mod_mask_set(obj, 4279369489);
+of_port_mod_mask_set(obj, 0xFF11FF11);
 of_port_mod_port_no_set(obj, 65533);
 of_port_mod_xid_set(obj, 2);
diff --git a/test_data/of13/bsn_gentable_bucket_stats_reply.data b/test_data/of13/bsn_gentable_bucket_stats_reply.data
new file mode 100644
index 0000000..8e0772f
--- /dev/null
+++ b/test_data/of13/bsn_gentable_bucket_stats_reply.data
@@ -0,0 +1,54 @@
+-- binary
+04 13 # version, type
+00 38 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 05 # subtype
+88 77 66 55 44 33 22 11 FF EE DD CC BB AA 99 88 # entries[0].checksum
+12 34 23 45 34 56 45 67 56 78 67 89 78 9A 89 AB # entries[1].checksum
+-- python
+ofp.message.bsn_gentable_bucket_stats_reply(
+    xid=0x12345678,
+    entries=[
+        ofp.bsn_gentable_bucket_stats_entry(
+            checksum=0x8877665544332211FFEEDDCCBBAA9988),
+        ofp.bsn_gentable_bucket_stats_entry(
+            checksum=0x123423453456456756786789789A89AB),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setEntries(
+        ImmutableList.<OFBsnGentableBucketStatsEntry>of(
+            factory.bsnGentableBucketStatsEntry(OFChecksum128.of(0x8877665544332211L, 0xFFEEDDCCBBAA9988L)),
+            factory.bsnGentableBucketStatsEntry(OFChecksum128.of(0x1234234534564567L, 0x56786789789A89ABL))
+        )
+    )
+-- c
+obj = of_bsn_gentable_bucket_stats_reply_new(OF_VERSION_1_3);
+of_bsn_gentable_bucket_stats_reply_xid_set(obj, 0x12345678);
+{
+    of_object_t *list = of_list_bsn_gentable_bucket_stats_entry_new(OF_VERSION_1_3);
+    {
+        of_object_t *entry = of_bsn_gentable_bucket_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_checksum_128_t checksum = { 0x8877665544332211L, 0xFFEEDDCCBBAA9988L };
+            of_bsn_gentable_bucket_stats_entry_checksum_set(entry, checksum);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    {
+        of_object_t *entry = of_bsn_gentable_bucket_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_checksum_128_t checksum = { 0x1234234534564567L, 0x56786789789A89ABL };
+            of_bsn_gentable_bucket_stats_entry_checksum_set(entry, checksum);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    of_bsn_gentable_bucket_stats_reply_entries_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_bucket_stats_request.data b/test_data/of13/bsn_gentable_bucket_stats_request.data
new file mode 100644
index 0000000..b756b54
--- /dev/null
+++ b/test_data/of13/bsn_gentable_bucket_stats_request.data
@@ -0,0 +1,14 @@
+-- binary
+04 12 # version, type
+00 1a # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 05 # subtype
+12 34 # table_id
+-- python
+ofp.message.bsn_gentable_bucket_stats_request(
+    xid=0x12345678,
+    table_id=0x1234)
diff --git a/test_data/of13/bsn_gentable_clear_request.data b/test_data/of13/bsn_gentable_clear_request.data
new file mode 100644
index 0000000..847af3c
--- /dev/null
+++ b/test_data/of13/bsn_gentable_clear_request.data
@@ -0,0 +1,33 @@
+-- binary
+04 04 # version, type
+00 34 # length
+12 34 56 78 # xid
+00 5c 16 c7 # experimenter
+00 00 00 30 # subtype
+00 14 # table_id
+00 00 # pad
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 00 00 # checksum
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 00 # checksum_mask
+-- python
+ofp.message.bsn_gentable_clear_request(
+    xid=0x12345678,
+    table_id=20,
+    checksum=     0xFEDCBA9876543210FFEECCBBAA990000,
+    checksum_mask=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000)
+-- java
+builder.setXid(0x12345678)
+    .setChecksum(OFChecksum128.of(0xFEDCBA9876543210L, 0xFFEECCBBAA990000L))
+    .setChecksumMask(OFChecksum128.of(0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFF0000L))
+    .setTableId(GenTableId.of(20))
+-- c
+obj = of_bsn_gentable_clear_request_new(OF_VERSION_1_3);
+of_bsn_gentable_clear_request_xid_set(obj, 0x12345678);
+of_bsn_gentable_clear_request_table_id_set(obj, 20);
+{
+    of_checksum_128_t checksum = { 0xFEDCBA9876543210L, 0xFFEECCBBAA990000L };
+    of_bsn_gentable_clear_request_checksum_set(obj, checksum);
+}
+{
+    of_checksum_128_t checksum_mask = { 0xFFFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFF0000L };
+    of_bsn_gentable_clear_request_checksum_mask_set(obj, checksum_mask);
+}
diff --git a/test_data/of13/bsn_gentable_desc_stats_reply.data b/test_data/of13/bsn_gentable_desc_stats_reply.data
new file mode 100644
index 0000000..180a8a1
--- /dev/null
+++ b/test_data/of13/bsn_gentable_desc_stats_reply.data
@@ -0,0 +1,86 @@
+-- binary
+04 13 # version, type
+00 78 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 04 # subtype
+
+# entries[0]
+00 30 # length
+00 00 # table id
+74 61 62 6c 65 20 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # name
+00 00 00 20 # buckets_size
+00 00 00 40 # max_entries
+00 00 00 00 # pad
+
+# entries[1]
+00 30 # length
+00 01 # table id
+74 61 62 6c 65 20 31 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e # name
+00 00 00 40 # buckets_size
+00 00 00 80 # max_entries
+00 00 00 00 # pad
+-- python
+ofp.message.bsn_gentable_desc_stats_reply(
+    xid=0x12345678,
+    entries=[
+        ofp.bsn_gentable_desc_stats_entry(
+            table_id=0,
+            name="table 0",
+            buckets_size=32,
+            max_entries=64),
+        ofp.bsn_gentable_desc_stats_entry(
+            table_id=1,
+            name="table 1".ljust(32, '.'),
+            buckets_size=64,
+            max_entries=128),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setEntries(
+        ImmutableList.<OFBsnGentableDescStatsEntry>of(
+            factory.buildBsnGentableDescStatsEntry()
+                .setTableId(GenTableId.of(0))
+                .setName("table 0")
+                .setBucketsSize(32)
+                .setMaxEntries(64)
+                .build(),
+            factory.buildBsnGentableDescStatsEntry()
+                .setTableId(GenTableId.of(1))
+                .setName("table 1.........................")
+                .setBucketsSize(64)
+                .setMaxEntries(128)
+                .build()
+        )
+    )
+-- c
+obj = of_bsn_gentable_desc_stats_reply_new(OF_VERSION_1_3);
+of_bsn_gentable_desc_stats_reply_xid_set(obj, 0x12345678);
+{
+    of_object_t *list = of_list_bsn_gentable_desc_stats_entry_new(OF_VERSION_1_3);
+    {
+        of_table_name_t name = "table 0";
+        of_object_t *entry = of_bsn_gentable_desc_stats_entry_new(OF_VERSION_1_3);
+        of_bsn_gentable_desc_stats_entry_table_id_set(entry, 0);
+        of_bsn_gentable_desc_stats_entry_name_set(entry, name);
+        of_bsn_gentable_desc_stats_entry_buckets_size_set(entry, 32);
+        of_bsn_gentable_desc_stats_entry_max_entries_set(entry, 64);
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    {
+        of_table_name_t name = "table 1.........................";
+        of_object_t *entry = of_bsn_gentable_desc_stats_entry_new(OF_VERSION_1_3);
+        of_bsn_gentable_desc_stats_entry_table_id_set(entry, 1);
+        of_bsn_gentable_desc_stats_entry_name_set(entry, name);
+        of_bsn_gentable_desc_stats_entry_buckets_size_set(entry, 64);
+        of_bsn_gentable_desc_stats_entry_max_entries_set(entry, 128);
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    of_bsn_gentable_desc_stats_reply_entries_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_desc_stats_request.data b/test_data/of13/bsn_gentable_desc_stats_request.data
new file mode 100644
index 0000000..977fe29
--- /dev/null
+++ b/test_data/of13/bsn_gentable_desc_stats_request.data
@@ -0,0 +1,12 @@
+-- binary
+04 12 # version, type
+00 18 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 04 # subtype
+-- python
+ofp.message.bsn_gentable_desc_stats_request(
+    xid=0x12345678)
diff --git a/test_data/of13/bsn_gentable_entry_add.data b/test_data/of13/bsn_gentable_entry_add.data
new file mode 100644
index 0000000..02c2bb4
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_add.data
@@ -0,0 +1,98 @@
+-- binary
+04 04 # version, type
+00 48 # length
+12 34 56 78 # xid
+00 5c 16 c7 # experimenter
+00 00 00 2e # subtype
+00 14 # table_id
+00 12 # key_length
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 88 77 # checksum
+
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 05 # key[0].value
+
+00 01 # key[1].type
+00 0a # key[1].length
+01 23 45 67 89 ab # key[1].value
+
+00 00 # value[0].type
+00 08 # value[0].length
+00 00 00 06 # value[0].value
+
+00 01 # value[1].type
+00 0a # value[1].length
+ff ee dd cc bb aa # value[1].value
+-- python
+ofp.message.bsn_gentable_entry_add(
+    xid=0x12345678,
+    checksum=0xFEDCBA9876543210FFEECCBBAA998877,
+    table_id=20,
+    key=[
+        ofp.bsn_tlv.port(5),
+        ofp.bsn_tlv.mac([0x01, 0x23, 0x45, 0x67, 0x89, 0xab]),
+    ],
+    value=[
+        ofp.bsn_tlv.port(6),
+        ofp.bsn_tlv.mac([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa]),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setChecksum(OFChecksum128.of(0xFEDCBA9876543210L, 0xFFEECCBBAA998877L))
+    .setTableId(GenTableId.of(20))
+    .setKey(
+        ImmutableList.<OFBsnTlv>of(
+            factory.bsnTlvs().port(OFPort.of(5)),
+            factory.bsnTlvs().mac(MacAddress.of("01:23:45:67:89:ab"))
+        )
+    )
+    .setValue(
+        ImmutableList.<OFBsnTlv>of(
+            factory.bsnTlvs().port(OFPort.of(6)),
+            factory.bsnTlvs().mac(MacAddress.of("ff:ee:dd:cc:bb:aa"))
+        )
+    )
+-- c
+obj = of_bsn_gentable_entry_add_new(OF_VERSION_1_3);
+of_bsn_gentable_entry_add_xid_set(obj, 0x12345678);
+of_bsn_gentable_entry_add_table_id_set(obj, 20);
+{
+    of_checksum_128_t checksum = { 0xFEDCBA9876543210L, 0xFFEECCBBAA998877L };
+    of_bsn_gentable_entry_add_checksum_set(obj, checksum);
+}
+{
+    of_object_t *list = of_list_bsn_tlv_new(OF_VERSION_1_3);
+    {
+        of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+        of_bsn_tlv_port_value_set(tlv, 5);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    {
+        of_mac_addr_t mac = { { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } };
+        of_object_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
+        of_bsn_tlv_mac_value_set(tlv, mac);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    of_bsn_gentable_entry_add_key_set(obj, list);
+    of_object_delete(list);
+}
+{
+    of_object_t *list = of_list_bsn_tlv_new(OF_VERSION_1_3);
+    {
+        of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+        of_bsn_tlv_port_value_set(tlv, 6);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    {
+        of_mac_addr_t mac = { { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa } };
+        of_object_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
+        of_bsn_tlv_mac_value_set(tlv, mac);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    of_bsn_gentable_entry_add_value_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_entry_delete.data b/test_data/of13/bsn_gentable_entry_delete.data
new file mode 100644
index 0000000..58c6c03
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_delete.data
@@ -0,0 +1,54 @@
+-- binary
+04 04 # version, type
+00 24 # length
+12 34 56 78 # xid
+00 5c 16 c7 # experimenter
+00 00 00 2f # subtype
+00 14 # table_id
+
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 05 # key[0].value
+
+00 01 # key[1].type
+00 0a # key[1].length
+01 23 45 67 89 ab # key[1].value
+-- python
+ofp.message.bsn_gentable_entry_delete(
+    xid=0x12345678,
+    table_id=20,
+    key=[
+        ofp.bsn_tlv.port(5),
+        ofp.bsn_tlv.mac([0x01, 0x23, 0x45, 0x67, 0x89, 0xab]),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setTableId(GenTableId.of(20))
+    .setKey(
+        ImmutableList.<OFBsnTlv>of(
+            factory.bsnTlvs().port(OFPort.of(5)),
+            factory.bsnTlvs().mac(MacAddress.of("01:23:45:67:89:ab"))
+        )
+    )
+-- c
+obj = of_bsn_gentable_entry_delete_new(OF_VERSION_1_3);
+of_bsn_gentable_entry_delete_xid_set(obj, 0x12345678);
+of_bsn_gentable_entry_delete_table_id_set(obj, 20);
+{
+    of_object_t *list = of_list_bsn_tlv_new(OF_VERSION_1_3);
+    {
+        of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+        of_bsn_tlv_port_value_set(tlv, 5);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    {
+        of_mac_addr_t mac = { { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } };
+        of_object_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
+        of_bsn_tlv_mac_value_set(tlv, mac);
+        of_list_append(list, tlv);
+        of_object_delete(tlv);
+    }
+    of_bsn_gentable_entry_delete_key_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_entry_desc_stats_reply.data b/test_data/of13/bsn_gentable_entry_desc_stats_reply.data
new file mode 100644
index 0000000..4035f4c
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_desc_stats_reply.data
@@ -0,0 +1,148 @@
+-- binary
+04 13 # version, type
+00 64 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 2 # subtype
+
+# entries[0]
+00 26 # length
+00 08 # key_length
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 88 00 # checksum
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 05 # key[0].value
+00 01 # value[0].type
+00 0a # value[0].length
+ff ee dd cc bb 00 # value[0].value
+
+# entries[1]
+00 26 # length
+00 08 # key_length
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 88 01 # checksum
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 06 # key[0].value
+00 01 # value[0].type
+00 0a # value[0].length
+ff ee dd cc bb 01 # value[0].value
+-- python
+ofp.message.bsn_gentable_entry_desc_stats_reply(
+    xid=0x12345678,
+    entries=[
+        ofp.bsn_gentable_entry_desc_stats_entry(
+            checksum=0xFEDCBA9876543210FFEECCBBAA998800,
+            key=[
+                ofp.bsn_tlv.port(5),
+            ],
+            value=[
+                ofp.bsn_tlv.mac([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0x00]),
+            ]),
+        ofp.bsn_gentable_entry_desc_stats_entry(
+            checksum=0xFEDCBA9876543210FFEECCBBAA998801,
+            key=[
+                ofp.bsn_tlv.port(6),
+            ],
+            value=[
+                ofp.bsn_tlv.mac([0xff, 0xee, 0xdd, 0xcc, 0xbb, 0x01]),
+            ]),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setEntries(
+        ImmutableList.<OFBsnGentableEntryDescStatsEntry>of(
+            factory.buildBsnGentableEntryDescStatsEntry()
+                .setChecksum(OFChecksum128.of(0xFEDCBA9876543210L, 0xFFEECCBBAA998800L))
+                .setKey(ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().port(OFPort.of(5))
+                ))
+                .setValue(ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().mac(MacAddress.of("ff:ee:dd:cc:bb:00"))
+                ))
+                .build(),
+            factory.buildBsnGentableEntryDescStatsEntry()
+                .setChecksum(OFChecksum128.of(0xFEDCBA9876543210L, 0xFFEECCBBAA998801L))
+                .setKey(ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().port(OFPort.of(6))
+                ))
+                .setValue(ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().mac(MacAddress.of("ff:ee:dd:cc:bb:01"))
+                ))
+                .build()
+        )
+    )
+-- c
+obj = of_bsn_gentable_entry_desc_stats_reply_new(OF_VERSION_1_3);
+of_bsn_gentable_entry_desc_stats_reply_xid_set(obj, 0x12345678);
+{
+    of_object_t *list = of_list_bsn_gentable_entry_desc_stats_entry_new(OF_VERSION_1_3);
+    {
+        of_object_t *entry = of_bsn_gentable_entry_desc_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_checksum_128_t checksum = { 0xFEDCBA9876543210L, 0xFFEECCBBAA998800L };
+            of_bsn_gentable_entry_desc_stats_entry_checksum_set(entry, checksum);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+                of_bsn_tlv_port_value_set(tlv, 5);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_desc_stats_entry_key_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
+                of_mac_addr_t mac = { { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0x00 } };
+                of_bsn_tlv_mac_value_set(tlv, mac);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_desc_stats_entry_value_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    {
+        of_object_t *entry = of_bsn_gentable_entry_desc_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_checksum_128_t checksum = { 0xFEDCBA9876543210L, 0xFFEECCBBAA998801L };
+            of_bsn_gentable_entry_desc_stats_entry_checksum_set(entry, checksum);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+                of_bsn_tlv_port_value_set(tlv, 6);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_desc_stats_entry_key_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_mac_new(OF_VERSION_1_3);
+                of_mac_addr_t mac = { { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0x01 } };
+                of_bsn_tlv_mac_value_set(tlv, mac);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_desc_stats_entry_value_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    of_bsn_gentable_entry_desc_stats_reply_entries_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_entry_desc_stats_request.data b/test_data/of13/bsn_gentable_entry_desc_stats_request.data
new file mode 100644
index 0000000..4971f06
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_desc_stats_request.data
@@ -0,0 +1,19 @@
+-- binary
+04 12 # version, type
+00 3c # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 2 # subtype
+00 14 # table_id
+00 00 # pad
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 00 00 # checksum
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 00 # checksum_mask
+-- python
+ofp.message.bsn_gentable_entry_desc_stats_request(
+    xid=0x12345678,
+    table_id=20,
+    checksum=     0xFEDCBA9876543210FFEECCBBAA990000,
+    checksum_mask=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000)
diff --git a/test_data/of13/bsn_gentable_entry_stats_reply.data b/test_data/of13/bsn_gentable_entry_stats_reply.data
new file mode 100644
index 0000000..255de88
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_stats_reply.data
@@ -0,0 +1,154 @@
+-- binary
+04 13 # version, type
+00 60 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 03 # subtype
+
+# entries[0]
+00 24 # length
+00 08 # key_length
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 05 # key[0].value
+00 02 # stats[0].type
+00 0c # stats[0].length
+00 00 00 00 00 00 00 64 # stats[0].value
+00 03 # stats[0].type
+00 0c # stats[0].length
+00 00 00 00 00 00 00 65 # stats[0].value
+
+# entries[1]
+00 24 # length
+00 08 # key_length
+00 00 # key[0].type
+00 08 # key[0].length
+00 00 00 06 # key[0].value
+00 02 # stats[0].type
+00 0c # stats[0].length
+00 00 00 00 00 00 00 64 # stats[0].value
+00 03 # stats[0].type
+00 0c # stats[0].length
+00 00 00 00 00 00 00 65 # stats[0].value
+-- python
+ofp.message.bsn_gentable_entry_stats_reply(
+    xid=0x12345678,
+    entries=[
+        ofp.bsn_gentable_entry_stats_entry(
+            key=[
+                ofp.bsn_tlv.port(5),
+            ],
+            stats=[
+                ofp.bsn_tlv.rx_packets(100),
+                ofp.bsn_tlv.tx_packets(101),
+            ]),
+        ofp.bsn_gentable_entry_stats_entry(
+            key=[
+                ofp.bsn_tlv.port(6),
+            ],
+            stats=[
+                ofp.bsn_tlv.rx_packets(100),
+                ofp.bsn_tlv.tx_packets(101),
+            ]),
+    ])
+-- java
+builder.setXid(0x12345678)
+    .setEntries(
+        ImmutableList.<OFBsnGentableEntryStatsEntry>of(
+            factory.bsnGentableEntryStatsEntry(
+                ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().port(OFPort.of(5))
+                ),
+                ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().rxPackets(U64.of(100)),
+                    factory.bsnTlvs().txPackets(U64.of(101))
+                )
+            ),
+            factory.bsnGentableEntryStatsEntry(
+                ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().port(OFPort.of(6))
+                ),
+                ImmutableList.<OFBsnTlv>of(
+                    factory.bsnTlvs().rxPackets(U64.of(100)),
+                    factory.bsnTlvs().txPackets(U64.of(101))
+                )
+            )
+        )
+    )
+-- c
+obj = of_bsn_gentable_entry_stats_reply_new(OF_VERSION_1_3);
+of_bsn_gentable_entry_stats_reply_xid_set(obj, 0x12345678);
+{
+    of_object_t *list = of_list_bsn_gentable_entry_stats_entry_new(OF_VERSION_1_3);
+    {
+        of_object_t *entry = of_bsn_gentable_entry_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+                of_bsn_tlv_port_value_set(tlv, 5);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_stats_entry_key_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_rx_packets_new(OF_VERSION_1_3);
+                of_bsn_tlv_rx_packets_value_set(tlv, 100);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            {
+                of_object_t *tlv = of_bsn_tlv_tx_packets_new(OF_VERSION_1_3);
+                of_bsn_tlv_tx_packets_value_set(tlv, 101);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_stats_entry_stats_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    {
+        of_object_t *entry = of_bsn_gentable_entry_stats_entry_new(OF_VERSION_1_3);
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_port_new(OF_VERSION_1_3);
+                of_bsn_tlv_port_value_set(tlv, 6);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_stats_entry_key_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        {
+            of_object_t *tlvs = of_list_bsn_tlv_new(OF_VERSION_1_3);
+            {
+                of_object_t *tlv = of_bsn_tlv_rx_packets_new(OF_VERSION_1_3);
+                of_bsn_tlv_rx_packets_value_set(tlv, 100);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            {
+                of_object_t *tlv = of_bsn_tlv_tx_packets_new(OF_VERSION_1_3);
+                of_bsn_tlv_tx_packets_value_set(tlv, 101);
+                of_list_append(tlvs, tlv);
+                of_object_delete(tlv);
+            }
+            of_bsn_gentable_entry_stats_entry_stats_set(entry, tlvs);
+            of_object_delete(tlvs);
+        }
+        of_list_append(list, entry);
+        of_object_delete(entry);
+    }
+    of_bsn_gentable_entry_stats_reply_entries_set(obj, list);
+    of_object_delete(list);
+}
diff --git a/test_data/of13/bsn_gentable_entry_stats_request.data b/test_data/of13/bsn_gentable_entry_stats_request.data
new file mode 100644
index 0000000..a288a55
--- /dev/null
+++ b/test_data/of13/bsn_gentable_entry_stats_request.data
@@ -0,0 +1,19 @@
+-- binary
+04 12 # version, type
+00 3c # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 3 # subtype
+00 14 # table_id
+00 00 # pad
+fe dc ba 98 76 54 32 10 ff ee cc bb aa 99 00 00 # checksum
+ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 00 # checksum_mask
+-- python
+ofp.message.bsn_gentable_entry_stats_request(
+    xid=0x12345678,
+    table_id=20,
+    checksum=     0xFEDCBA9876543210FFEECCBBAA990000,
+    checksum_mask=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000)
diff --git a/test_data/of13/bsn_gentable_set_buckets_size.data b/test_data/of13/bsn_gentable_set_buckets_size.data
new file mode 100644
index 0000000..7833736
--- /dev/null
+++ b/test_data/of13/bsn_gentable_set_buckets_size.data
@@ -0,0 +1,14 @@
+-- binary
+04 04 # version, type
+00 18 # length
+12 34 56 78 # xid
+00 5c 16 c7 # experimenter
+00 00 00 32 # subtype
+00 14 # table_id
+00 00 # pad
+00 11 22 33 # buckets_size
+-- python
+ofp.message.bsn_gentable_set_buckets_size(
+    xid=0x12345678,
+    table_id=20,
+    buckets_size=0x00112233)
diff --git a/test_data/of13/bsn_port_counter_stats_reply.data b/test_data/of13/bsn_port_counter_stats_reply.data
new file mode 100644
index 0000000..15e98b4
--- /dev/null
+++ b/test_data/of13/bsn_port_counter_stats_reply.data
@@ -0,0 +1,42 @@
+-- binary
+04 13 # version, type
+00 50 # length
+12 34 56 78 # xid
+ff ff # stats_type
+00 00 # flags
+00 00 00 00 # pad
+00 5c 16 c7 # experimenter
+00 00 00 8 # subtype
+# entries[0]
+00 18 # length
+00 00 # pad
+00 00 00 03 # port
+12 34 56 78 9a bc de f0 # values[0]
+11 22 33 44 55 66 77 88 # values[1]
+# entries[0]
+00 20 # length
+00 00 # pad
+00 00 00 04 # port
+12 34 56 78 9a bc de f0 # values[0]
+11 22 33 44 55 66 77 88 # values[1]
+ff ff ff ff ff ff ff ff # values[2]
+-- python
+ofp.message.bsn_port_counter_stats_reply(
+    xid=0x12345678,
+    flags=0,
+    entries=[
+        ofp.bsn_port_counter_stats_entry(
+            port_no=3,
+            values=[
+                ofp.uint64(0x123456789abcdef0),
+                ofp.uint64(0x1122334455667788),
+            ]),
+        ofp.bsn_port_counter_stats_entry(
+            port_no=4,
+            values=[
+                ofp.uint64(0x123456789abcdef0),
+                ofp.uint64(0x1122334455667788),
+                ofp.uint64(0xffffffffffffffff),
+            ])
+    ]
+)
diff --git a/test_data/of13/bsn_tlv_port.data b/test_data/of13/bsn_tlv_port.data
new file mode 100644
index 0000000..303b0ec
--- /dev/null
+++ b/test_data/of13/bsn_tlv_port.data
@@ -0,0 +1,6 @@
+-- binary
+00 00 # type
+00 08 # length
+00 00 00 05 # value
+-- python
+ofp.bsn_tlv.port(5)
diff --git a/test_data/of13/flow_add.data b/test_data/of13/flow_add.data
index 0766375..d566096 100644
--- a/test_data/of13/flow_add.data
+++ b/test_data/of13/flow_add.data
@@ -82,7 +82,7 @@
     .setPriority(6000)
     .setBufferId(OFBufferId.of(50))
     .setOutPort(OFPort.of(6))
-    .setOutGroup(8)
+    .setOutGroup(OFGroup.of(8))
     .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
diff --git a/test_data/of13/flow_delete.data b/test_data/of13/flow_delete.data
index 6148d21..bf9c453 100644
--- a/test_data/of13/flow_delete.data
+++ b/test_data/of13/flow_delete.data
@@ -82,7 +82,7 @@
     .setPriority(6000)
     .setBufferId(OFBufferId.of(50))
     .setOutPort(OFPort.of(6))
-    .setOutGroup(8)
+    .setOutGroup(OFGroup.of(8))
     .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
diff --git a/test_data/of13/flow_delete_strict.data b/test_data/of13/flow_delete_strict.data
index 7e4d233..c33e4f8 100644
--- a/test_data/of13/flow_delete_strict.data
+++ b/test_data/of13/flow_delete_strict.data
@@ -82,7 +82,7 @@
     .setPriority(6000)
     .setBufferId(OFBufferId.of(50))
     .setOutPort(OFPort.of(6))
-    .setOutGroup(8)
+    .setOutGroup(OFGroup.of(8))
     .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
diff --git a/test_data/of13/flow_modify.data b/test_data/of13/flow_modify.data
index 83234f5..6f3ebee 100644
--- a/test_data/of13/flow_modify.data
+++ b/test_data/of13/flow_modify.data
@@ -82,7 +82,7 @@
     .setPriority(6000)
     .setBufferId(OFBufferId.of(50))
     .setOutPort(OFPort.of(6))
-    .setOutGroup(8)
+    .setOutGroup(OFGroup.of(8))
     .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
diff --git a/test_data/of13/flow_modify_strict.data b/test_data/of13/flow_modify_strict.data
index 1d6f4c3..26e55a4 100644
--- a/test_data/of13/flow_modify_strict.data
+++ b/test_data/of13/flow_modify_strict.data
@@ -82,7 +82,7 @@
     .setPriority(6000)
     .setBufferId(OFBufferId.of(50))
     .setOutPort(OFPort.of(6))
-    .setOutGroup(8)
+    .setOutGroup(OFGroup.of(8))
     .setFlags(ImmutableSet.<OFFlowModFlags>of())
     .setMatch(
         factory.buildMatch()
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index 7f081a8..c13c206 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -90,6 +90,10 @@
     end
 end
 
+function read_of_checksum_128_t(reader, version, subtree, field_name)
+    read_scalar(reader, subtree, field_name, 16)
+end
+
 function read_of_octets_t(reader, version, subtree, field_name)
     if not reader.is_empty() then
         subtree:add(fields[field_name], reader.read_all())