Merge into master from pull request #203:
loci: fix byte swapping on OS X (https://github.com/floodlight/loxigen/pull/203)
diff --git a/README.md b/README.md
index 1e70f9d..98ec28e 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,8 @@
 itself. We do ask you to install it and use it before submitting pull requests,
 though.
 
+Running the Java unit tests requires Maven 3: `sudo apt-get install maven`.
+
 Usage
 =====
 
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index b655433..ff9a654 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -437,6 +437,7 @@
 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_instruction_id_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);
@@ -467,7 +468,7 @@
  * underlying wire buffer's current bytes.
  */
 #define OF_LENGTH_CHECK_ASSERT(obj) \\
-    ASSERT(((obj)->parent != NULL) || \\
+    LOCI_ASSERT(((obj)->parent != NULL) || \\
      ((obj)->wire_object.wbuf == NULL) || \\
      (WBUF_CURRENT_BYTES((obj)->wire_object.wbuf) == (obj)->length))
 
@@ -609,14 +610,21 @@
 
 extern const char *const of_error_strings[];
 
-#ifndef NDEBUG
-/* #define ASSERT(val) assert(val) */
-#define FORCE_FAULT *(volatile int *)0 = 1
-#define ASSERT(val) if (!(val)) \\
-    fprintf(stderr, "\\nASSERT %s. %s:%d\\n", #val, __FILE__, __LINE__), \\
-    FORCE_FAULT
+#ifdef __GNUC__
+#define LOCI_NORETURN_ATTR __attribute__((__noreturn__))
 #else
-#define ASSERT(val)
+#define LOCI_NORETURN_ATTR
+#endif
+
+extern void loci_assert_fail(
+    const char *cond,
+    const char *file,
+    unsigned int line) LOCI_NORETURN_ATTR;
+
+#ifndef NDEBUG
+#define LOCI_ASSERT(val) ((val) ? (void)0 : loci_assert_fail(#val, __FILE__, __LINE__))
+#else
+#define LOCI_ASSERT(val)
 #endif
 
 /*
@@ -1650,13 +1658,13 @@
            out.write("    OF_PORT_NO_VALUE_CHECK(*%s, ver);\n" % m_name)
     elif m_type == "of_octets_t":
         out.write("""\
-    ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
+    LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
     %(m_name)s->bytes = cur_len;
     %(m_name)s->data = OF_WIRE_BUFFER_INDEX(wbuf, abs_offset);
 """ % dict(m_name=m_name))
     elif m_type == "of_match_t":
         out.write("""
-    ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
+    LOCI_ASSERT(cur_len + abs_offset <= WBUF_CURRENT_BYTES(wbuf));
     match_octets.bytes = cur_len;
     match_octets.data = OF_OBJECT_BUFFER_INDEX(obj, offset);
     OF_TRY(of_match_deserialize(ver, %(m_name)s, &match_octets));
@@ -1714,8 +1722,8 @@
     if (obj->wire_object.wbuf == %(m_name)s->wire_object.wbuf) {
         of_wire_buffer_grow(wbuf, abs_offset + new_len);
         /* Verify that the offsets are correct */
-        ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
-        /* ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
+        LOCI_ASSERT(abs_offset == OF_OBJECT_ABSOLUTE_OFFSET(%(m_name)s, 0));
+        /* LOCI_ASSERT(new_len == cur_len); */ /* fixme: may fail for OXM lists */
         return %(ret_success)s;
     }
 
@@ -1831,10 +1839,10 @@
 """)
 
     out.write("""
-    ASSERT(%(assert_str)s);
+    LOCI_ASSERT(%(assert_str)s);
     ver = obj->version;
     wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     /* By version, determine offset and current length (where needed) */
     switch (ver) {
@@ -1863,14 +1871,14 @@
     gen_accessor_offsets(out, cls, m_name, next, a_type, m_type, prev_o)
     out.write("""\
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 
     abs_offset = OF_OBJECT_ABSOLUTE_OFFSET(obj, offset);
-    ASSERT(abs_offset >= 0);
+    LOCI_ASSERT(abs_offset >= 0);
 """)
     if not loxi_utils.type_is_scalar(m_type):
-        out.write("    ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
+        out.write("    LOCI_ASSERT(cur_len >= 0 && cur_len < 64 * 1024);\n")
 
     # Now generate the common accessor code
     if a_type in ["get", "bind"]:
@@ -2038,7 +2046,7 @@
 """ % cls)
 
     out.write("""
-    ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
+    LOCI_ASSERT(of_object_fixed_len[version][%(enum)s] >= 0);
     if (clean_wire) {
         MEMSET(obj, 0, sizeof(*obj));
     }
@@ -2364,6 +2372,10 @@
                 out.write("""
     obj->wire_type_get = of_instruction_wire_object_id_get;
 """)
+            if loxi_utils.class_is_instruction_id(cls):
+                out.write("""
+    obj->wire_type_get = of_instruction_id_wire_object_id_get;
+""")
             if loxi_utils.class_is_queue_prop(cls):
                     out.write("""
     obj->wire_type_get = of_queue_prop_wire_object_id_get;
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index cf03e0e..5b74649 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -68,6 +68,8 @@
 import c_gen.identifiers as identifiers
 import util
 import test_data
+import loxi_globals
+from loxi_ir import *
 
 def var_name_map(m_type):
     """
@@ -124,40 +126,14 @@
     or those that should not be messed with
     or whose types we're not ready to deal with yet.
     """
-    # This will probably need more granularity as more extensions are added
-    if (type_maps.class_is_extension(cls, version) and (
-            m_name == "experimenter" or
-            m_name == "subtype")):
+
+    uclass = loxi_globals.unified.class_by_name(cls)
+    if not uclass:
         return True
 
-    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_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",
-               "of_bsn_flow_checksum_bucket_stats_request",
-               "of_bsn_flow_checksum_bucket_stats_reply",
-               "of_bsn_table_checksum_stats_request",
-               "of_bsn_table_checksum_stats_reply",
-            ]
-
-    if (cls in classes and (
-            m_name == "experimenter" or
-            m_name == "subtype")):
+    if not isinstance(uclass.member_by_name(m_name), OFDataMember):
         return True
+
     return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
 
 def gen_fill_string(out):
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index d4525ba..a13e23e 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -118,6 +118,9 @@
     gen_type_to_object_id(out, "instruction_type_to_id", "OF_INSTRUCTION",
                           "OF_INSTRUCTION_%s", type_maps.instruction_types,
                           max_type_value)
+    gen_type_to_object_id(out, "instruction_id_type_to_id", "OF_INSTRUCTION_ID",
+                          "OF_INSTRUCTION_ID_%s", type_maps.instruction_id_types,
+                          max_type_value)
     gen_type_to_object_id(out, "queue_prop_type_to_id", "OF_QUEUE_PROP",
                           "OF_QUEUE_PROP_%s", type_maps.queue_prop_types,
                           max_type_value)
@@ -229,7 +232,43 @@
     return of_%(name)s_type_to_id[version][%(name)s];
 }
 """
+    table_features_prop_template = """
+/**
+ * %(name)s wire type to object ID array.
+ * Treat as private; use function accessor below
+ */
 
+extern const of_object_id_t *const of_%(name)s_type_to_id[OF_VERSION_ARRAY_MAX];
+
+#define OF_%(u_name)s_ITEM_COUNT %(ar_len)d\n
+
+/**
+ * Map an %(name)s wire value to an OF object
+ * @param %(name)s The %(name)s type wire value
+ * @param version The version associated with the check
+ * @return The %(name)s OF object type
+ * @return OF_OBJECT_INVALID if type does not map to an object
+ *
+ */
+of_object_id_t
+of_%(name)s_to_object_id(int %(name)s, of_version_t version)
+{
+    if (!OF_VERSION_OKAY(version)) {
+        return OF_OBJECT_INVALID;
+    }
+    if (%(name)s == 0xfffe) {
+        return OF_%(u_name)s_EXPERIMENTER;
+    }
+    if (%(name)s == 0xffff) {
+        return OF_%(u_name)s_EXPERIMENTER_MISS;
+    }
+    if (%(name)s < 0 || %(name)s >= OF_%(u_name)s_ITEM_COUNT) {
+        return OF_OBJECT_INVALID;
+    }
+
+    return of_%(name)s_type_to_id[version][%(name)s];
+}
+"""
     stats_template = """
 /**
  * %(name)s wire type to object ID array.
@@ -529,6 +568,11 @@
     out.write(map_with_experimenter_template %
               dict(name="instruction", u_name="INSTRUCTION", ar_len=ar_len))
 
+    # Instruction ID types array gen
+    ar_len = type_maps.type_array_len(type_maps.instruction_id_types, max_type_value)
+    out.write(map_with_experimenter_template %
+              dict(name="instruction_id", u_name="INSTRUCTION_ID", ar_len=ar_len))
+
     # Queue prop types array gen
     ar_len = type_maps.type_array_len(type_maps.queue_prop_types,
                                       max_type_value)
@@ -538,7 +582,7 @@
     # Table feature prop types array gen
     ar_len = type_maps.type_array_len(type_maps.table_feature_prop_types,
                                       max_type_value)
-    out.write(map_with_experimenter_template %
+    out.write(table_features_prop_template  %
               dict(name="table_feature_prop", u_name="TABLE_FEATURE_PROP",
                    ar_len=ar_len))
 
@@ -680,6 +724,8 @@
 extern void of_action_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
 extern void of_instruction_wire_object_id_get(of_object_t *obj,
     of_object_id_t *id);
+extern void of_instruction_id_wire_object_id_get(of_object_t *obj,
+    of_object_id_t *id);
 extern void of_queue_prop_wire_object_id_get(of_object_t *obj,
     of_object_id_t *id);
 extern void of_table_feature_prop_wire_object_id_get(of_object_t *obj,
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 3249747..121bc42 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -35,6 +35,7 @@
 from itertools import groupby
 from StringIO import StringIO
 import template_utils
+from generic_utils import chunks
 import loxi_globals
 import loxi_ir.ir as ir
 import util
@@ -43,6 +44,8 @@
 import c_gen.type_maps as type_maps
 import c_gen.c_type_maps as c_type_maps
 
+CLASS_CHUNK_SIZE = 32
+
 PushWireTypesData = namedtuple('PushWireTypesData',
     ['class_name', 'versioned_type_members'])
 PushWireTypesMember = namedtuple('PushWireTypesMember',
@@ -75,14 +78,18 @@
         class_name=uclass.name,
         versioned_type_members=versioned_type_members)
 
+# Output multiple LOCI classes into each C file. This reduces the overhead of
+# parsing header files, which takes longer than compiling the actual code
+# for many classes. It also reduces the compiled code size.
 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)
+    for i, chunk in enumerate(chunks(loxi_globals.unified.classes, CLASS_CHUNK_SIZE)):
+        with template_utils.open_output(install_dir, "loci/src/class%02d.c" % i) as out:
+            for uclass in chunk:
+                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):
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 4092d4f..df93c2b 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -191,7 +191,26 @@
 
     # For each vendor, check for vendor specific action
     for exp in of_g.experimenter_name_to_id:
-        if cls.find("of_instruction_" + exp) == 0:
+        if cls.find("of_instruction" + exp) == 0:
+            return True
+
+    return False
+
+def class_is_instruction_id(cls):
+    """
+    Return True if cls_name is an action object
+
+    Note that instruction_id is not an instruction object, though it has
+    the same header.  It looks like an instruction header, but the type
+    is used to identify a kind of instruction, it does not indicate the
+    type of the object following.
+    """
+    if cls.find("of_instruction_id") == 0:
+        return True
+
+    # For each vendor, check for vendor specific action
+    for exp in of_g.experimenter_name_to_id:
+        if cls.find("of_instruction_id_" + exp) == 0:
             return True
 
     return False
diff --git a/c_gen/templates/locitest/test_ext.c b/c_gen/templates/locitest/test_ext.c
index 87f9916..75f4a00 100644
--- a/c_gen/templates/locitest/test_ext.c
+++ b/c_gen/templates/locitest/test_ext.c
@@ -61,9 +61,13 @@
     TEST_ASSERT(of_meter_band_to_object_id(OF_EXPERIMENTER_TYPE, OF_VERSION_1_0) ==
                 OF_METER_BAND_EXPERIMENTER);
 
-    TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE,
+    TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE-1,
                                                    OF_VERSION_1_3) ==
                 OF_TABLE_FEATURE_PROP_EXPERIMENTER);
 
+    TEST_ASSERT(of_table_feature_prop_to_object_id(OF_EXPERIMENTER_TYPE,
+                                                   OF_VERSION_1_3) ==
+                OF_TABLE_FEATURE_PROP_EXPERIMENTER_MISS);
+
     return TEST_PASS;
 }
diff --git a/c_gen/templates/locitest/test_list_limits.c b/c_gen/templates/locitest/test_list_limits.c
index d8368ff..68ead8f 100644
--- a/c_gen/templates/locitest/test_list_limits.c
+++ b/c_gen/templates/locitest/test_list_limits.c
@@ -44,19 +44,19 @@
 
     of_flow_stats_reply_entries_bind(obj, &list);
 
-    ASSERT(element != NULL);
+    LOCI_ASSERT(element != NULL);
 
 
     while (1) {
         int rv = of_list_flow_stats_entry_append(&list, element);
-        ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
+        LOCI_ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
         if (rv != OF_ERROR_NONE) {
             break;
         }
         i++;
     }
 
-    ASSERT(i == 744);
+    LOCI_ASSERT(i == 744);
 
     of_flow_stats_entry_delete(element);
     of_flow_stats_reply_delete(obj);
@@ -77,14 +77,14 @@
         int rv; 
         of_flow_stats_entry_init(&element, OF_VERSION_1_0, -1, 1);
         rv = of_list_flow_stats_entry_append_bind(&list, &element);
-        ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
+        LOCI_ASSERT(rv == OF_ERROR_NONE || rv == OF_ERROR_RESOURCE);
         if (rv != OF_ERROR_NONE) {
             break;
         }
         i++;
     }
 
-    ASSERT(i == 744);
+    LOCI_ASSERT(i == 744);
 
     of_flow_stats_reply_delete(obj);
     return TEST_PASS;
diff --git a/c_gen/templates/locitest/test_utils.c b/c_gen/templates/locitest/test_utils.c
index bcd4194..563f510 100644
--- a/c_gen/templates/locitest/test_utils.c
+++ b/c_gen/templates/locitest/test_utils.c
@@ -118,10 +118,32 @@
     return TEST_PASS;
 }
 
+static int
+test_of_object_new_from_message_preallocated(void)
+{
+    /* v1 OFPT_HELLO, xid=0x12345678 */
+    uint8_t buf[] = { 0x01, 0x00, 0x00, 0x08, 0x12, 0x34, 0x56, 0x78 };
+
+    of_object_storage_t storage;
+    of_object_t *obj = of_object_new_from_message_preallocated(
+        &storage, buf, sizeof(buf));
+
+    TEST_ASSERT(obj != NULL);
+    TEST_ASSERT(obj->version = OF_VERSION_1_0);
+    TEST_ASSERT(obj->object_id = OF_HELLO);
+
+    uint32_t xid;
+    of_hello_xid_get(obj, &xid);
+    TEST_ASSERT(xid == 0x12345678);
+
+    return TEST_PASS;
+}
+
 int
 run_utility_tests(void)
 {
     RUN_TEST(has_outport);
+    RUN_TEST(of_object_new_from_message_preallocated);
     RUN_TEST(dump_objs);
 
     return TEST_PASS;
diff --git a/c_gen/templates/locitest/unittest.h b/c_gen/templates/locitest/unittest.h
index c897d67..06568d3 100644
--- a/c_gen/templates/locitest/unittest.h
+++ b/c_gen/templates/locitest/unittest.h
@@ -41,9 +41,9 @@
     } while (0)
 
 #define TEST_ASSERT(result) if (!(result)) do {                         \
-        fprintf(stderr, "\nTEST ASSERT FAILURE "                        \
+        fprintf(stderr, "\nTEST LOCI_ASSERT FAILURE "                        \
                #result " :: %s:%d\n",__FILE__,__LINE__);                \
-        ASSERT(0);                                                      \
+        LOCI_ASSERT(0);                                                      \
         return TEST_FAIL;                                               \
     } while (0)
 
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 9b1bafd..8fd0aab 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -160,7 +160,7 @@
     }
 
     object_id = of_message_to_object_id(msg, len);
-    ASSERT(object_id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(object_id != OF_OBJECT_INVALID);
 
     if ((obj = of_object_new(-1)) == NULL) {
         return NULL;
@@ -180,6 +180,54 @@
 }
 
 /**
+ * Parse a message without allocating memory
+ *
+ * @param storage Pointer to an uninitialized of_object_storage_t
+ * @param buf Pointer to the buffer
+ * @param length Length of buf
+ * @returns Pointer to an initialized of_object_t
+ *
+ * The lifetime of the returned object is the minimum of the lifetimes of
+ * 'buf' and 'storage'.
+ */
+
+of_object_t *
+of_object_new_from_message_preallocated(of_object_storage_t *storage,
+                                        uint8_t *buf, int len)
+{
+    of_object_t *obj = &storage->obj;
+    of_wire_buffer_t *wbuf = &storage->wbuf;
+    of_message_t msg = buf;
+    of_version_t version;
+    of_object_id_t object_id;
+
+    memset(storage, 0, sizeof(*storage));
+
+    version = of_message_version_get(msg);
+    if (!OF_VERSION_OKAY(version)) {
+        return NULL;
+    }
+
+    if (of_validate_message(msg, len) != 0) {
+        LOCI_LOG_ERROR("message validation failed\n");
+        return NULL;
+    }
+
+    object_id = of_message_to_object_id(msg, len);
+    /* Already validated */
+    LOCI_ASSERT(object_id != OF_OBJECT_INVALID);
+
+    of_object_init_map[object_id](obj, version, len, 0);
+
+    obj->wire_object.wbuf = wbuf;
+    wbuf->buf = msg;
+    wbuf->alloc_bytes = len;
+    wbuf->current_bytes = len;
+
+    return obj;
+}
+
+/**
  * Bind an existing buffer to an LOCI object
  *
  * @param obj Pointer to the object to be updated
@@ -199,9 +247,9 @@
     of_wire_object_t *wobj;
     of_wire_buffer_t *wbuf;
 
-    ASSERT(buf != NULL);
-    ASSERT(bytes > 0);
-    // ASSERT(wobj is not bound);
+    LOCI_ASSERT(buf != NULL);
+    LOCI_ASSERT(bytes > 0);
+    // LOCI_ASSERT(wobj is not bound);
 
     wobj = &obj->wire_object;
     MEMSET(wobj, 0, sizeof(*wobj));
@@ -487,7 +535,7 @@
 {
     int offset;
 
-    ASSERT(child->length > 0);
+    LOCI_ASSERT(child->length > 0);
 
     /* Get offset of parent */
     if (of_list_is_last(parent, child)) {
@@ -505,7 +553,7 @@
 void
 of_object_wire_buffer_steal(of_object_t *obj, uint8_t **buffer)
 {
-    ASSERT(obj != NULL);
+    LOCI_ASSERT(obj != NULL);
     of_wire_buffer_steal(obj->wire_object.wbuf, buffer);
     obj->wire_object.wbuf = NULL;
 }
@@ -530,7 +578,7 @@
 #endif
 
     while (obj != NULL) {
-        ASSERT(count++ < _MAX_PARENT_ITERATIONS);
+        LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
         obj->length += delta;
         if (obj->wire_length_set != NULL) {
             obj->wire_length_set(obj, obj->length);
@@ -540,10 +588,10 @@
 #endif
 
         /* Asserts for wire length checking */
-        ASSERT(obj->length + obj->wire_object.obj_offset <=
+        LOCI_ASSERT(obj->length + obj->wire_object.obj_offset <=
                WBUF_CURRENT_BYTES(wbuf));
         if (obj->parent == NULL) {
-            ASSERT(obj->length + obj->wire_object.obj_offset ==
+            LOCI_ASSERT(obj->length + obj->wire_object.obj_offset ==
                    WBUF_CURRENT_BYTES(wbuf));
         }
 
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index 0e761fd..3172ad1 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -122,6 +122,11 @@
 
 extern of_object_t *of_object_new_from_message(of_message_t msg, int len);
 
+typedef struct of_object_storage_s of_object_storage_t;
+
+of_object_t *of_object_new_from_message_preallocated(
+    of_object_storage_t *storage, uint8_t *buf, int len);
+
 /* Delete an OpenFlow object without reference to its type */
 extern void of_object_delete(of_object_t *obj);
 
@@ -169,4 +174,9 @@
     uint64_t metadata[(OF_OBJECT_METADATA_BYTES + 7) / 8];
 };
 
+struct of_object_storage_s {
+    of_object_t obj;
+    of_wire_buffer_t wbuf;
+};
+
 #endif /* _OF_OBJECT_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 6026512..ef3f82b 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -55,8 +55,8 @@
 void
 of_object_message_wire_length_get(of_object_t *obj, int *bytes)
 {
-    ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
-    // ASSERT(obj is message)
+    LOCI_ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
+    // LOCI_ASSERT(obj is message)
     *bytes = of_message_length_get(OF_OBJECT_TO_MESSAGE(obj));
 }
 
@@ -69,8 +69,8 @@
 void
 of_object_message_wire_length_set(of_object_t *obj, int bytes)
 {
-    ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
-    // ASSERT(obj is message)
+    LOCI_ASSERT(OF_OBJECT_TO_WBUF(obj) != NULL);
+    // LOCI_ASSERT(obj is message)
     of_message_length_set(OF_OBJECT_TO_MESSAGE(obj), bytes);
 }
 
@@ -97,7 +97,7 @@
 {
     uint16_t val16;
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     of_wire_buffer_u16_get(wbuf, 
            OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_LENGTH_OFFSET), &val16);
@@ -115,7 +115,7 @@
 of_tlv16_wire_length_set(of_object_t *obj, int bytes)
 {
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     of_wire_buffer_u16_set(wbuf, 
         OF_OBJECT_ABSOLUTE_OFFSET(obj, TLV16_WIRE_LENGTH_OFFSET), bytes);
@@ -247,10 +247,10 @@
         return;
     }
 
-    ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ITEM_COUNT);
 
     *id = of_action_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 /**
@@ -271,10 +271,10 @@
         return;
     }
 
-    ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ID_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_ACTION_ID_ITEM_COUNT);
 
     *id = of_action_id_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 /**
@@ -303,6 +303,45 @@
         case 1: *id = OF_INSTRUCTION_BSN_ARP_OFFLOAD; break;
         case 2: *id = OF_INSTRUCTION_BSN_DHCP_OFFLOAD; break;
         case 3: *id = OF_INSTRUCTION_BSN_DISABLE_SPLIT_HORIZON_CHECK; break;
+        case 4: *id = OF_INSTRUCTION_BSN_PERMIT; break;
+        case 5: *id = OF_INSTRUCTION_BSN_DENY; break;
+        }
+        break;
+    }
+    }
+
+    return OF_ERROR_NONE;
+}
+
+
+/**
+ * @fixme to do when we have instruction extensions
+ * See extension_action above
+ */
+
+static int
+extension_instruction_id_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+    uint32_t exp_id;
+    uint8_t *buf;
+
+    *id = OF_INSTRUCTION_ID_EXPERIMENTER;
+
+    buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
+
+    buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_ID_OFFSET, &exp_id);
+
+    switch (exp_id) {
+    case OF_EXPERIMENTER_ID_BSN: {
+        uint32_t subtype;
+        buf_u32_get(buf + OF_INSTRUCTION_EXPERIMENTER_SUBTYPE_OFFSET, &subtype);
+        switch (subtype) {
+        case 0: *id = OF_INSTRUCTION_ID_BSN_DISABLE_SRC_MAC_CHECK; break;
+        case 1: *id = OF_INSTRUCTION_ID_BSN_ARP_OFFLOAD; break;
+        case 2: *id = OF_INSTRUCTION_ID_BSN_DHCP_OFFLOAD; break;
+        case 3: *id = OF_INSTRUCTION_ID_BSN_DISABLE_SPLIT_HORIZON_CHECK; break;
+        case 4: *id = OF_INSTRUCTION_ID_BSN_PERMIT; break;
+        case 5: *id = OF_INSTRUCTION_ID_BSN_DENY; break;
         }
         break;
     }
@@ -328,12 +367,35 @@
         return;
     }
 
-    ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ITEM_COUNT);
 
     *id = of_instruction_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
+/**
+ * Get the object ID based on the wire buffer for an instruction ID object
+ * @param obj The object being referenced
+ * @param id Where to store the object ID
+ */
+
+
+void
+of_instruction_id_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+    int wire_type;
+
+    of_tlv16_wire_type_get(obj, &wire_type);
+    if (wire_type == OF_EXPERIMENTER_TYPE) {
+        extension_instruction_id_object_id_get(obj, id);
+        return;
+    }
+
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_INSTRUCTION_ID_ITEM_COUNT);
+
+    *id = of_instruction_id_type_to_id[obj->version][wire_type];
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
+}
 
 /**
  * @fixme to do when we have queue_prop extensions
@@ -365,27 +427,14 @@
         return;
     }
 
-    ASSERT(wire_type >= 0 && wire_type < OF_QUEUE_PROP_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_QUEUE_PROP_ITEM_COUNT);
 
     *id = of_queue_prop_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 
 /**
- * @fixme to do when we have table_feature_prop extensions
- * See extension_action above
- */
-
-static void
-extension_table_feature_prop_object_id_get(of_object_t *obj, of_object_id_t *id)
-{
-    (void)obj;
-
-    *id = OF_TABLE_FEATURE_PROP_EXPERIMENTER;
-}
-
-/**
  * Table feature property object ID determination
  *
  * @param obj The object being referenced
@@ -398,15 +447,7 @@
     int wire_type;
 
     of_tlv16_wire_type_get(obj, &wire_type);
-    if (wire_type == OF_EXPERIMENTER_TYPE) {
-        extension_table_feature_prop_object_id_get(obj, id);
-        return;
-    }
-
-    ASSERT(wire_type >= 0 && wire_type < OF_TABLE_FEATURE_PROP_ITEM_COUNT);
-
-    *id = of_table_feature_prop_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    *id = of_table_feature_prop_to_object_id(wire_type, obj->version);
 }
 
 /**
@@ -426,10 +467,10 @@
         return;
     }
 
-    ASSERT(wire_type >= 0 && wire_type < OF_METER_BAND_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_METER_BAND_ITEM_COUNT);
 
     *id = of_meter_band_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 /**
@@ -444,9 +485,9 @@
     int wire_type;
 
     of_tlv16_wire_type_get(obj, &wire_type);
-    ASSERT(wire_type >= 0 && wire_type < OF_HELLO_ELEM_ITEM_COUNT);
+    LOCI_ASSERT(wire_type >= 0 && wire_type < OF_HELLO_ELEM_ITEM_COUNT);
     *id = of_hello_elem_type_to_id[obj->version][wire_type];
-    ASSERT(*id != OF_OBJECT_INVALID);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 /**
@@ -461,9 +502,9 @@
     int wire_type;
 
     of_tlv16_wire_type_get(obj, &wire_type);
-    ASSERT(wire_type >= 0 && wire_type < OF_BSN_TLV_ITEM_COUNT);
+    LOCI_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);
+    LOCI_ASSERT(*id != OF_OBJECT_INVALID);
 }
 
 /****************************************************************
@@ -482,14 +523,14 @@
 
 #define _GET_OXM_TYPE_LEN(obj, tl_p, wbuf) do {                         \
         wbuf = OF_OBJECT_TO_WBUF(obj);                                  \
-        ASSERT(wbuf != NULL);                                           \
+        LOCI_ASSERT(wbuf != NULL);                                           \
         of_wire_buffer_u32_get(wbuf,                                    \
             OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), (tl_p));    \
     } while (0)
 
 #define _SET_OXM_TYPE_LEN(obj, tl_p, wbuf) do {                         \
         wbuf = OF_OBJECT_TO_WBUF(obj);                                  \
-        ASSERT(wbuf != NULL);                                           \
+        LOCI_ASSERT(wbuf != NULL);                                           \
         of_wire_buffer_u32_set(wbuf,                                    \
             OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), (tl_p));    \
     } while (0)
@@ -539,7 +580,7 @@
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
     uint16_t u16;
 
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     of_wire_buffer_u16_get(wbuf, 
            OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_U16_LEN_LENGTH_OFFSET),
@@ -558,9 +599,9 @@
 of_u16_len_wire_length_set(of_object_t *obj, int bytes)
 {
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
-    /* ASSERT(obj is u16-len entry) */
+    /* LOCI_ASSERT(obj is u16-len entry) */
 
     of_wire_buffer_u16_set(wbuf, 
            OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_U16_LEN_LENGTH_OFFSET),
@@ -585,9 +626,9 @@
     uint16_t u16;
     int offset;
 
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
-    /* ASSERT(obj is packet queue obj) */
+    /* LOCI_ASSERT(obj is packet queue obj) */
     offset = OF_PACKET_QUEUE_LENGTH_OFFSET(obj->version);
     of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, offset),
                            &u16);
@@ -609,9 +650,9 @@
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
     int offset;
 
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
-    /* ASSERT(obj is packet queue obj) */
+    /* LOCI_ASSERT(obj is packet queue obj) */
     offset = OF_PACKET_QUEUE_LENGTH_OFFSET(obj->version);
     of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, offset),
                                   bytes);
@@ -628,8 +669,8 @@
 void
 of_list_meter_band_stats_wire_length_get(of_object_t *obj, int *bytes)
 {
-    ASSERT(obj->parent != NULL);
-    ASSERT(obj->parent->object_id == OF_METER_STATS);
+    LOCI_ASSERT(obj->parent != NULL);
+    LOCI_ASSERT(obj->parent->object_id == OF_METER_STATS);
 
     /* We're counting on the parent being properly initialized already.
      * The length is stored in a uint16 at offset 4 of the parent.
@@ -652,7 +693,7 @@
 {
     uint16_t val16;
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
     of_wire_buffer_u16_get(wbuf, 
                OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET),
                &val16);
@@ -663,7 +704,7 @@
 of_meter_stats_wire_length_set(of_object_t *obj, int bytes)
 {
     of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     of_wire_buffer_u16_set(wbuf, 
         OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET), bytes);
diff --git a/c_gen/templates/of_utils.c b/c_gen/templates/of_utils.c
index ba22536..373ad59 100644
--- a/c_gen/templates/of_utils.c
+++ b/c_gen/templates/of_utils.c
@@ -35,6 +35,8 @@
  ****************************************************************/
 
 #include <loci/of_utils.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 
 /**
@@ -76,3 +78,9 @@
     return rv;
 }
 
+void
+loci_assert_fail(const char *msg, const char *file, unsigned int line)
+{
+    fprintf(stderr, "\\nASSERT %s. %s:%d\\n", msg, file, line);
+    abort();
+}
diff --git a/c_gen/templates/of_wire_buf.c b/c_gen/templates/of_wire_buf.c
index 13da8e3..7f759f9 100644
--- a/c_gen/templates/of_wire_buf.c
+++ b/c_gen/templates/of_wire_buf.c
@@ -131,12 +131,12 @@
     uint8_t *src_ptr, *dst_ptr;
     int cur_bytes;
 
-    ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf != NULL);
 
     cur_bytes = wbuf->current_bytes;
 
     /* Doesn't make sense; mismatch in current buffer info */
-    ASSERT(old_len + offset <= wbuf->current_bytes);
+    LOCI_ASSERT(old_len + offset <= wbuf->current_bytes);
 
     wbuf->current_bytes += (new_len - old_len); // may decrease size
 
@@ -151,5 +151,5 @@
     dst_ptr = &wbuf->buf[offset];
     MEMCPY(dst_ptr, data, new_len);
 
-    ASSERT(wbuf->current_bytes == cur_bytes + (new_len - old_len));
+    LOCI_ASSERT(wbuf->current_bytes == cur_bytes + (new_len - old_len));
 }
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index f977004..4736ac0 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -88,7 +88,7 @@
  * @param offset The extent of the buffer required
  */
 #define OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset)                      \
-    ASSERT(((wbuf) != NULL) && (WBUF_BUF(wbuf) != NULL) &&             \
+    LOCI_ASSERT(((wbuf) != NULL) && (WBUF_BUF(wbuf) != NULL) &&             \
            (offset > 0) && (WBUF_CURRENT_BYTES(wbuf) >= offset))
 
 /*
@@ -242,8 +242,8 @@
 static inline void
 of_wire_buffer_grow(of_wire_buffer_t *wbuf, int bytes)
 {
-    ASSERT(wbuf != NULL);
-    ASSERT(wbuf->alloc_bytes >= bytes);
+    LOCI_ASSERT(wbuf != NULL);
+    LOCI_ASSERT(wbuf->alloc_bytes >= bytes);
     if (bytes > wbuf->current_bytes) {
         wbuf->current_bytes = bytes;
     }
@@ -426,7 +426,7 @@
 of_wire_buffer_match_get(int version, of_wire_buffer_t *wbuf, int offset,
                       of_match_t *value)
 {
-    ASSERT(0);
+    LOCI_ASSERT(0);
 }
 
 /**
@@ -443,7 +443,7 @@
 of_wire_buffer_match_set(int version, of_wire_buffer_t *wbuf, int offset,
                       of_match_t *value)
 {
-    ASSERT(0);
+    LOCI_ASSERT(0);
 }
 
 /**
@@ -461,7 +461,7 @@
 of_wire_buffer_of_port_desc_get(int version, of_wire_buffer_t *wbuf, int offset,
                              void *value)
 {
-    ASSERT(0);
+    LOCI_ASSERT(0);
 }
 
 /**
@@ -479,7 +479,7 @@
 of_wire_buffer_of_port_desc_set(int version, of_wire_buffer_t *wbuf, int offset,
                              void *value)
 {
-    ASSERT(0);
+    LOCI_ASSERT(0);
 }
 
 /**
@@ -510,7 +510,7 @@
         *value = v32;
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -538,7 +538,7 @@
         of_wire_buffer_u32_set(wbuf, offset, (uint32_t)value);
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -568,7 +568,7 @@
         *value = v8;
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -593,7 +593,7 @@
         of_wire_buffer_u8_set(wbuf, offset, (uint8_t)value);
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -623,7 +623,7 @@
         *value = v64;
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -648,7 +648,7 @@
         of_wire_buffer_u64_set(wbuf, offset, (uint64_t)value);
         break;
     default:
-        ASSERT(0);
+        LOCI_ASSERT(0);
     }
 }
 
@@ -702,7 +702,7 @@
                                of_octets_t *value, int cur_len)
 {
     // FIXME need to adjust length of octets member in buffer
-    ASSERT(cur_len == 0 || cur_len == value->bytes);
+    LOCI_ASSERT(cur_len == 0 || cur_len == value->bytes);
 
     OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + OF_OCTETS_BYTES_GET(value));
     buf_octets_set(OF_WIRE_BUFFER_INDEX(wbuf, offset),
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 875a34e..ee452fc 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -584,6 +584,20 @@
 }
 
 # Set to empty dict if no extension instructions defined
+extension_instruction_id_subtype = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(
+        bsn = {   # of_instruction_bsn_
+            },
+        nicira = {   # of_instruction_nicira_
+            }
+        ),
+}
+
+# Set to empty dict if no extension instructions defined
 extension_queue_prop_subtype = {}
 
 # Set to empty dict if no extension instructions defined
@@ -594,6 +608,7 @@
     extension_action_subtype,
     extension_action_id_subtype,
     extension_instruction_subtype,
+    extension_instruction_id_subtype,
     extension_queue_prop_subtype,
     extension_table_feature_prop_subtype
 ]
@@ -768,6 +783,17 @@
     return cls_is_ext_obj(cls, version, extension_instruction_subtype)
 
 ################################################################
+# These are extension instruction specific
+################################################################
+
+def instruction_id_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an instruction ID extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version, extension_instruction_id_subtype)
+
+################################################################
 # These are extension queue_prop specific
 ################################################################
 
diff --git a/generic_utils.py b/generic_utils.py
index 1cfba86..5683aa1 100644
--- a/generic_utils.py
+++ b/generic_utils.py
@@ -214,3 +214,11 @@
         if func(i):
             c +=1
     return c
+
+def chunks(l, n):
+    """
+    Yield successive n-sized chunks from l.
+    From http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
+    """
+    for i in xrange(0, len(l), n):
+        yield l[i:i+n]
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 a9da637..43a7a17 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
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import java.util.Arrays;
+
 import org.jboss.netty.buffer.ChannelBuffer;
 
 import com.google.common.hash.PrimitiveSink;
@@ -119,7 +121,7 @@
         return rawValue;
     }
 
-    volatile byte[] bytesCache = null;
+    private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
         if (bytesCache == null) {
@@ -133,7 +135,7 @@
                 }
             }
         }
-        return bytesCache;
+        return Arrays.copyOf(bytesCache, bytesCache.length);
     }
 
     @Override
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 4e7b856..c9dea13 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
@@ -1,9 +1,11 @@
 package org.projectfloodlight.openflow.types;
 
+import java.util.Arrays;
 import java.util.regex.Pattern;
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
+
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
@@ -201,7 +203,7 @@
         return new IPv6Address(raw1, raw2);
     }
 
-    volatile byte[] bytesCache = null;
+    private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
         if (bytesCache == null) {
@@ -228,7 +230,7 @@
                 }
             }
         }
-        return bytesCache;
+        return Arrays.copyOf(bytesCache, bytesCache.length);
     }
 
     @Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
index 27d5b66..f592ea8 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import java.util.Arrays;
+
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.util.HexString;
@@ -79,7 +81,7 @@
         return MacAddress.of(raw);
     }
 
-    volatile byte[] bytesCache = null;
+    private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
         if (bytesCache == null) {
@@ -95,7 +97,7 @@
                 }
             }
         }
-        return bytesCache;
+        return Arrays.copyOf(bytesCache, bytesCache.length);
     }
 
     /**
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
index fddaa5d..0fae3e6 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFVlanVidMatch.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import java.util.Arrays;
+
 import javax.annotation.Nullable;
 
 import org.jboss.netty.buffer.ChannelBuffer;
@@ -143,7 +145,7 @@
     }
 
 
-    volatile byte[] bytesCache = null;
+    private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
         if (bytesCache == null) {
@@ -155,7 +157,7 @@
                 }
             }
         }
-        return bytesCache;
+        return Arrays.copyOf(bytesCache, bytesCache.length);
     }
 
     public void write2Bytes(ChannelBuffer c) {
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
index 8337eb6..2e675d4 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import java.util.Arrays;
+
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
@@ -67,7 +69,7 @@
         return LENGTH;
     }
 
-    volatile byte[] bytesCache = null;
+    private volatile byte[] bytesCache = null;
 
     public byte[] getBytes() {
         if (bytesCache == null) {
@@ -79,7 +81,7 @@
                 }
             }
         }
-        return bytesCache;
+        return Arrays.copyOf(bytesCache, bytesCache.length);
     }
 
     public void write2Bytes(ChannelBuffer c) {
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
index ddf0f25..bcc46f7 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/HexString.java
@@ -17,8 +17,6 @@
 
 package org.projectfloodlight.openflow.util;
 
-import java.math.BigInteger;
-
 import org.projectfloodlight.openflow.types.U8;
 
 public class HexString {
@@ -86,13 +84,17 @@
         return ret;
     }
 
-    public static long toLong(final String values) throws NumberFormatException {
-        // Long.parseLong() can't handle HexStrings with MSB set. Sigh.
-        BigInteger bi = new BigInteger(values.replaceAll(":", ""), 16);
-        if (bi.bitLength() > 64)
-            throw new NumberFormatException("Input string too big to fit in long: "
-                    + values);
-        return bi.longValue();
+    public static long toLong(String value) throws NumberFormatException {
+        String[] octets = value.split(":");
+        if (octets.length > 8)
+            throw new NumberFormatException("Input string is too big to fit in long: " + value);
+        long l = 0;
+        for (String octet: octets) {
+            if (octet.length() > 2)
+                throw new NumberFormatException("Each colon-separated byte component must consist of 1 or 2 hex digits: " + value);
+            short s = Short.parseShort(octet, 16);
+            l = (l << 8) + s;
+        }
+        return l;
     }
-
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
new file mode 100644
index 0000000..360cb5a
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/HexStringTest.java
@@ -0,0 +1,103 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    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
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.projectfloodlight.openflow.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Does hexstring conversion work?
+ *
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
+ */
+public class HexStringTest {
+
+    @Test
+    public void testMarshalling() throws Exception {
+        String dpidStr = "00:00:00:23:20:2d:16:71";
+        long dpid = HexString.toLong(dpidStr);
+        String testStr = HexString.toHexString(dpid);
+        assertEquals(dpidStr, testStr);
+    }
+
+    @Test
+    public void testToLong() {
+        String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+        long valid = 0x3e1f01fc728c6331L;
+        long testLong = HexString.toLong(dpidStr);
+        assertEquals(valid, testLong);
+    }
+
+    @Test
+    public void testToLong2() {
+        String dpidStr = "1f:1:fc:72:3:f:31";
+        long valid = 0x1f01fc72030f31L;
+        long testLong = HexString.toLong(dpidStr);
+        assertEquals(valid, testLong);
+    }
+
+    @Test
+    public void testToLongMSB() {
+        String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+        long valid = -3856102927509056101L;
+        long testLong = HexString.toLong(dpidStr);
+        assertEquals(valid, testLong);
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testToLongErrorTooManyBytes() {
+        HexString.toLong("09:08:07:06:05:04:03:02:01");
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testToLongErrorByteValueTooLong() {
+        HexString.toLong("234:01");
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testToLongErrorEmptyByte() {
+        HexString.toLong("03::01");
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testToLongErrorInvalidHexDigit() {
+        HexString.toLong("ss:01");
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testToLongErrorEmptyString() {
+        HexString.toLong("");
+    }
+
+
+    @Test
+    public void testToStringBytes() {
+        byte[] dpid = { 0, 0, 0, 0, 0, 0, 0, -1 };
+        String valid = "00:00:00:00:00:00:00:ff";
+        String testString = HexString.toHexString(dpid);
+        assertEquals(valid, testString);
+    }
+
+    @Test(expected=NumberFormatException.class)
+    public void testFromHexStringError() {
+        String invalidStr = "00:00:00:00:00:00:ffff";
+        HexString.fromHexString(invalidStr);
+    }
+}
+
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index 6a053c6..c8ca04d 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -440,10 +440,15 @@
             superclass_name = None
             superclass = None
 
+        ofc_members = []
+        for m in orig_fe.members:
+            if not isinstance(m, frontend_ir.OFDataMember) and not isinstance(m, frontend_ir.OFPadMember):
+                ofc_members.append(m)
+
         fe = frontend_ir.OFClass(
             name=name,
             superclass=superclass_name,
-            members=[m for m in orig_fe.members if not isinstance(m, frontend_ir.OFDataMember)],
+            members=ofc_members,
             virtual=orig_fe.virtual,
             params={})
 
diff --git a/openflow_input/bsn_acl b/openflow_input/bsn_acl
new file mode 100644
index 0000000..4035904
--- /dev/null
+++ b/openflow_input/bsn_acl
@@ -0,0 +1,50 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+//
+// 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
+
+// Instructions to express control flow in ACL tables
+
+struct of_instruction_bsn_permit : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 4;
+    pad(4);
+};
+
+struct of_instruction_bsn_deny : of_instruction_bsn {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 5;
+    pad(4);
+};
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index af7e501..6010880 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -292,6 +292,7 @@
     OFPR_BSN_FRAGMENTATION_REQUIRED = 137,
     OFPR_BSN_ARP = 139,
     OFPR_BSN_DHCP = 140,
+    OFPR_BSN_DEBUG = 141,
 };
 
 enum ofp_flow_removed_reason(wire_type=uint8_t) {
@@ -757,7 +758,6 @@
 struct of_action_id {
     uint16_t type;
     uint16_t len;
-    pad(4);
 };
 
 struct of_action_output : of_action {
@@ -877,6 +877,11 @@
     pad(4);
 };
 
+struct of_instruction_id {
+    uint16_t type;
+    uint16_t len;
+};
+
 struct of_instruction {
     uint16_t type == ?;
     uint16_t len;
@@ -1610,13 +1615,13 @@
     uint16_t         type == 0;
     uint16_t         length;
     // FIXME Check if instruction_t is right for ids here
-    list(of_instruction_t)   instruction_ids;
+    list(of_instruction_id_t)   instruction_ids;
 };
 
 struct of_table_feature_prop_instructions_miss : of_table_feature_prop {
     uint16_t         type == 1;
     uint16_t         length;
-    list(of_instruction_t)   instruction_ids;
+    list(of_instruction_id_t)   instruction_ids;
 };
 
 struct of_table_feature_prop_next_tables : of_table_feature_prop {
@@ -1692,21 +1697,20 @@
 };
 
 struct of_table_feature_prop_experimenter : of_table_feature_prop {
-    uint16_t         type == 65535;
+    uint16_t         type == 65534;
     uint16_t         length;
     uint32_t         experimenter;
     uint32_t         subtype;
     of_octets_t      experimenter_data;
 };
 
-// Not yet supported
-// struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
-//     uint16_t         type;
-//     uint16_t         length;
-//     uint32_t         experimenter;
-//     uint32_t         subtype;
-//     of_octets_t      experimenter_data;
-// };
+struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
+    uint16_t         type == 65535;
+    uint16_t         length;
+    uint32_t         experimenter;
+    uint32_t         subtype;
+    of_octets_t      experimenter_data;
+};
 
 struct of_table_features {
     uint16_t length;
diff --git a/test_data/of13/action_id_output.data b/test_data/of13/action_id_output.data
new file mode 100644
index 0000000..7712203
--- /dev/null
+++ b/test_data/of13/action_id_output.data
@@ -0,0 +1,8 @@
+-- binary
+00 00 # type
+00 04 # length
+-- python
+ofp.action_id.output()
+-- c
+obj = of_action_id_output_new(OF_VERSION_1_3);
+-- java
diff --git a/test_data/of13/instruction_id_goto_table.data b/test_data/of13/instruction_id_goto_table.data
new file mode 100644
index 0000000..e52d9c9
--- /dev/null
+++ b/test_data/of13/instruction_id_goto_table.data
@@ -0,0 +1,8 @@
+-- binary
+00 01 # type
+00 04 # length
+-- python
+ofp.instruction_id.goto_table()
+-- c
+obj = of_instruction_id_goto_table_new(OF_VERSION_1_3);
+-- java