Merge pull request #40 from yotamhc/master

Changes required to adopt new loxi APIs into legacy OFMatch
diff --git a/Makefile b/Makefile
index dceb3e6..cb60398 100644
--- a/Makefile
+++ b/Makefile
@@ -100,17 +100,9 @@
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of12.py
 	PYTHONPATH=${LOXI_OUTPUT_DIR}/pyloxi:. python py_gen/tests/of13.py
 
-CTEST_EXEC = ${LOXI_OUTPUT_DIR}/locitest/locitest
-CTEST_SOURCE = ${LOXI_OUTPUT_DIR}/locitest/src/*.c
-CTEST_SOURCE += ${LOXI_OUTPUT_DIR}/loci/src/*.c
-CTEST_INC = -I ${LOXI_OUTPUT_DIR}/loci/inc
-CTEST_INC += -I ${LOXI_OUTPUT_DIR}/locitest/inc
-CTEST_INC += -I ${LOXI_OUTPUT_DIR}/loci/src
-CTEST_CFLAGS = -Wall -Werror -g
-
 check-c: c
-	gcc ${CTEST_CFLAGS} -o ${CTEST_EXEC} ${CTEST_SOURCE} ${CTEST_INC}
-	${CTEST_EXEC}
+	make -C ${LOXI_OUTPUT_DIR}/locitest
+	${LOXI_OUTPUT_DIR}/locitest/locitest
 
 pylint:
 	pylint -E ${LOXI_PY_FILES}
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 96614e5..14ab24e 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -66,6 +66,8 @@
 import loxi_front_end.type_maps as type_maps
 import loxi_utils.loxi_utils as loxi_utils
 import loxi_front_end.identifiers as identifiers
+import util
+import test_data
 
 def var_name_map(m_type):
     """
@@ -341,6 +343,7 @@
 extern int run_list_limits_tests(void);
 
 extern int test_ext_objs(void);
+extern int test_datafiles(void);
 
 """)
 
@@ -742,6 +745,7 @@
 """ % dict(cls=cls, base_type=base_type))
 
     sub_classes =  type_maps.sub_class_map(base_type, version)
+    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
     if len(sub_classes) == 0:
@@ -789,6 +793,7 @@
 """ % dict(cls=cls, base_type=base_type))
 
     sub_classes =  type_maps.sub_class_map(base_type, version)
+    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
     if len(sub_classes) == 0:
@@ -1080,6 +1085,8 @@
         for cls in of_g.ordered_messages:
             if not (cls, version) in of_g.base_length:
                 continue
+            if type_maps.class_is_virtual(cls):
+                continue
             bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
             out.write("""
 static int
@@ -1133,6 +1140,8 @@
         for cls in of_g.ordered_messages:
             if not (cls, version) in of_g.base_length:
                 continue
+            if type_maps.class_is_virtual(cls):
+                continue
             test_name = "%s_create_%s" % (cls, loxi_utils.version_to_name(version))
             out.write("    RUN_TEST(%s);\n" % test_name)
 
@@ -1163,6 +1172,7 @@
 """ % dict(cls=cls, base_type=base_type))
 
     sub_classes =  type_maps.sub_class_map(base_type, version)
+    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
     if len(sub_classes) == 0:
@@ -1221,6 +1231,7 @@
 
 
     sub_classes =  type_maps.sub_class_map(base_type, version)
+    sub_classes = [(instance, subcls) for (instance, subcls) in sub_classes if not type_maps.class_is_virtual(subcls)]
     v_name = loxi_utils.version_to_name(version)
 
     if len(sub_classes) == 0:
@@ -1967,3 +1978,16 @@
 }
 """)
 
+def gen_datafiles_tests(out, name):
+    tests = []
+    for filename in test_data.list_files():
+        data = test_data.read(filename)
+        if not 'c' in data:
+            continue
+        name = filename[:-5].replace("/", "_")
+        tests.append(dict(name=name,
+                          filename=filename,
+                          c=data['c'],
+                          binary=data['binary']))
+
+    util.render_template(out, "test_data.c", tests=tests)
diff --git a/c_gen/templates/locitest/Makefile b/c_gen/templates/locitest/Makefile
new file mode 100644
index 0000000..ed4ba13
--- /dev/null
+++ b/c_gen/templates/locitest/Makefile
@@ -0,0 +1,12 @@
+SRCS := $(wildcard src/*.c)
+SRCS += $(wildcard ../loci/src/*.c)
+
+OBJS := $(SRCS:.c=.o)
+
+CFLAGS := -Wall -Werror -g
+CFLAGS += -Iinc -I../loci/inc -I ../loci/src
+
+all: locitest
+
+locitest: $(OBJS)
+	$(CC) $^ -o $@
diff --git a/c_gen/templates/locitest/main.c b/c_gen/templates/locitest/main.c
index 3b24035..86f7ae6 100644
--- a/c_gen/templates/locitest/main.c
+++ b/c_gen/templates/locitest/main.c
@@ -41,5 +41,7 @@
 
     RUN_TEST(ext_objs);
 
+    TEST_ASSERT(test_datafiles() == TEST_PASS);
+
     return global_error;
 }
diff --git a/c_gen/templates/locitest/test_data.c b/c_gen/templates/locitest/test_data.c
new file mode 100644
index 0000000..f4e985f
--- /dev/null
+++ b/c_gen/templates/locitest/test_data.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University */
+/* Copyright (c) 2011, 2012 Open Networking Foundation */
+/* Copyright (c) 2012, 2013 Big Switch Networks, Inc. */
+/* See the file LICENSE.loci which should have been included in the source distribution */
+
+/**
+ *
+ * AUTOMATICALLY GENERATED FILE.  Edits will be lost on regen.
+ *
+ * Data file tests for all versions.
+ */
+
+#include <locitest/test_common.h>
+
+<?py
+def hexarray(data, indent):
+    i = 0
+    text = []
+    text.append(" " * indent)
+    for byte in data:
+        text.append("0x%02x, " % ord(byte))
+        i += 1
+        if i == 8:
+            text.append("\n" + " " * indent)
+            i = 0
+        #endif
+    #endfor
+    return "".join(text)
+#end
+?>
+
+static void
+hexdump(const uint8_t *data, int len)
+{
+    int i = 0, j;
+    while (i < len) {
+	printf("%02x: ", i);
+	for (j = 0; j < 8 && i < len; j++, i++) {
+	    printf("%02x ", data[i]);
+	}
+	printf("\n");
+    }
+}
+
+static void
+show_failure(const uint8_t *a, int a_len, const uint8_t *b, int b_len)
+{
+    printf("\n--- Expected: (len=%d)\n", a_len);
+    hexdump(a, a_len);
+    printf("\n--- Actual: (len=%d)\n", b_len);
+    hexdump(b, b_len);
+}
+
+:: for test in tests:
+/* Generated from ${test['filename']} */
+static int
+test_${test['name']}(void) {
+    uint8_t binary[] = {
+${hexarray(test['binary'], indent=8)}
+    };
+
+    of_object_t *obj;
+
+${'\n'.join([' ' * 4 + x for x in test['c'].split("\n")])}
+
+    if (sizeof(binary) != WBUF_CURRENT_BYTES(OF_OBJECT_TO_WBUF(obj))
+        || memcmp(binary, WBUF_BUF(OF_OBJECT_TO_WBUF(obj)), sizeof(binary))) {
+	show_failure(binary, sizeof(binary),
+		     WBUF_BUF(OF_OBJECT_TO_WBUF(obj)),
+		     WBUF_CURRENT_BYTES(OF_OBJECT_TO_WBUF(obj)));
+	of_object_delete(obj);
+	return TEST_FAIL;
+    }
+
+    of_object_delete(obj);
+    return TEST_PASS;
+}
+
+:: #endfor
+
+int
+test_datafiles(void)
+{
+:: for test in tests:
+    RUN_TEST(${test['name']});
+:: #endfor
+    return TEST_PASS;
+}
diff --git a/c_gen/templates/locitest/test_validator.c b/c_gen/templates/locitest/test_validator.c
index d7947b9..6b9dd87 100644
--- a/c_gen/templates/locitest/test_validator.c
+++ b/c_gen/templates/locitest/test_validator.c
@@ -117,7 +117,7 @@
 ::        for cls in reversed(of_g.standard_class_order):
 ::            if not loxi_utils.class_in_version(cls, version):
 ::                continue
-::            elif cls in type_maps.inheritance_map:
+::            elif type_maps.class_is_virtual(cls):
 ::                continue
 ::            elif not loxi_utils.class_is_message(cls):
 ::                continue
diff --git a/lang_c.py b/lang_c.py
index aae08ea..fc016f2 100644
--- a/lang_c.py
+++ b/lang_c.py
@@ -97,6 +97,7 @@
     'locitest/src/test_msg.c': c_test_gen.gen_msg_test,
     'locitest/src/test_scalar_acc.c': c_test_gen.gen_message_scalar_test,
     'locitest/src/test_uni_acc.c': c_test_gen.gen_unified_accessor_tests,
+    'locitest/src/test_data.c': c_test_gen.gen_datafiles_tests,
 
     # Static locitest code
     'locitest/inc/locitest/unittest.h': static,
@@ -107,4 +108,5 @@
     'locitest/src/test_utils.c': static,
     'locitest/src/test_validator.c': static,
     'locitest/src/main.c': static,
+    'locitest/Makefile': static,
 }
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index ab98c26..d25c2eb 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -60,8 +60,8 @@
 
     for decl_ast in ast:
         if decl_ast[0] == 'struct':
-            members = [create_member(m_ast) for m_ast in decl_ast[2]]
-            ofclass = OFClass(name=decl_ast[1], members=members)
+            members = [create_member(m_ast) for m_ast in decl_ast[3]]
+            ofclass = OFClass(name=decl_ast[1], superclass=decl_ast[2], members=members)
             ofinput.classes.append(ofclass)
         if decl_ast[0] == 'enum':
             enum = OFEnum(name=decl_ast[1], values=[(x[0], x[1]) for x in decl_ast[2]])
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index 503a05a..7893008 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -54,7 +54,8 @@
 type_member = P.Group(tag('type') + any_type + identifier + s('==') + integer)
 data_member = P.Group(tag('data') + any_type - identifier)
 struct_member = pad_member | type_member | data_member;
-struct = kw('struct') - identifier - s('{') + \
+parent = (s(':') - identifier) | tag(None)
+struct = kw('struct') - identifier - parent - s('{') + \
          P.Group(P.ZeroOrMore(struct_member - s(';'))) + \
          s('}') - s(';')
 
diff --git a/loxi_front_end/type_maps.py b/loxi_front_end/type_maps.py
index f9a66f6..b64f1b5 100644
--- a/loxi_front_end/type_maps.py
+++ b/loxi_front_end/type_maps.py
@@ -154,6 +154,9 @@
         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_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira"]:
+        return True
     return False
 
 ################################################################
diff --git a/loxi_ir.py b/loxi_ir.py
index 9a27272..824524b 100644
--- a/loxi_ir.py
+++ b/loxi_ir.py
@@ -72,7 +72,7 @@
 @param name
 @param members List of *Member objects
 """
-OFClass = namedtuple('OFClass', ['name', 'members'])
+OFClass = namedtuple('OFClass', ['name', 'superclass', 'members'])
 
 """
 Normal field
diff --git a/loxi_utils/loxi_utils.py b/loxi_utils/loxi_utils.py
index 648e109..f5f9b63 100644
--- a/loxi_utils/loxi_utils.py
+++ b/loxi_utils/loxi_utils.py
@@ -417,7 +417,7 @@
 # Is class a flow modify of some sort?
 
 def cls_is_flow_mod(cls):
-    return cls in ["of_flow_modify", "of_flow_add", "of_flow_delete",
+    return cls in ["of_flow_mod", "of_flow_modify", "of_flow_add", "of_flow_delete",
                    "of_flow_modify_strict", "of_flow_delete_strict"]
 
 
diff --git a/loxigen.py b/loxigen.py
index 36d6872..9bddf4b 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -359,10 +359,6 @@
         else:
             of_g.ordered_non_messages.append(cls)
 
-    of_g.ordered_pseudo_objects.append("of_stats_request")
-    of_g.ordered_pseudo_objects.append("of_stats_reply")
-    of_g.ordered_pseudo_objects.append("of_flow_mod")
-
     of_g.ordered_messages.sort()
     of_g.ordered_pseudo_objects.sort()
     of_g.ordered_non_messages.sort()
@@ -481,7 +477,7 @@
     def find_experimenter(parent, cls):
         for experimenter in sorted(of_g.experimenter_name_to_id.keys(), reverse=True):
             prefix = parent + '_' + experimenter
-            if cls.startswith(prefix):
+            if cls.startswith(prefix) and cls != prefix:
                 return experimenter
         return None
 
@@ -520,7 +516,7 @@
             # HACK (though this is what loxi_utils.class_is_message() does)
             if not [x for x in ofclass.members if isinstance(x, OFDataMember) and x.name == 'xid']:
                 continue
-            if cls == 'of_header':
+            if type_maps.class_is_virtual(cls):
                 continue
             subcls = cls[3:]
             val = find_type_value(ofclass, 'type')
diff --git a/openflow_input/bsn b/openflow_input/bsn
new file mode 100644
index 0000000..16f3323
--- /dev/null
+++ b/openflow_input/bsn
@@ -0,0 +1,48 @@
+// 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 any
+
+// BSN extension message
+struct of_bsn_header : of_experimenter {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype;
+};
+
+// BSN extension action
+struct of_action_bsn : of_action_experimenter {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype;
+    pad(4);
+};
+
diff --git a/openflow_input/bsn_bw b/openflow_input/bsn_bw
index e0ff3e3..50c9267 100644
--- a/openflow_input/bsn_bw
+++ b/openflow_input/bsn_bw
@@ -30,7 +30,7 @@
 
 #version any
 
-struct of_bsn_bw_enable_set_request {
+struct of_bsn_bw_enable_set_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -40,7 +40,7 @@
     uint32_t enable;        // 0 to disable the extension, 1 to enable it
 };
 
-struct of_bsn_bw_enable_set_reply {
+struct of_bsn_bw_enable_set_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -51,7 +51,7 @@
     uint32_t status;        // Result code: 0 success
 };
 
-struct of_bsn_bw_enable_get_request {
+struct of_bsn_bw_enable_get_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -60,7 +60,7 @@
     uint32_t subtype == 19;
 };
 
-struct of_bsn_bw_enable_get_reply {
+struct of_bsn_bw_enable_get_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -70,7 +70,7 @@
     uint32_t enabled;       // 0 if feature is disabled; 1 if feature enabled
 };
 
-struct of_bsn_bw_clear_data_request {
+struct of_bsn_bw_clear_data_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -79,7 +79,7 @@
     uint32_t subtype == 21;
 };
 
-struct of_bsn_bw_clear_data_reply {
+struct of_bsn_bw_clear_data_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_get_interfaces b/openflow_input/bsn_get_interfaces
index 01902bc..6f316b0 100644
--- a/openflow_input/bsn_get_interfaces
+++ b/openflow_input/bsn_get_interfaces
@@ -27,7 +27,7 @@
 
 #version any
 
-struct of_bsn_get_interfaces_request {
+struct of_bsn_get_interfaces_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -44,7 +44,7 @@
     of_ipv4_t ipv4_netmask;
 };
 
-struct of_bsn_get_interfaces_reply {
+struct of_bsn_get_interfaces_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_ip_mask b/openflow_input/bsn_ip_mask
index b6d517b..615ed40 100644
--- a/openflow_input/bsn_ip_mask
+++ b/openflow_input/bsn_ip_mask
@@ -27,7 +27,7 @@
 
 #version 1
 
-struct of_bsn_set_ip_mask {
+struct of_bsn_set_ip_mask : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -39,7 +39,7 @@
     uint32_t mask;
 };
 
-struct of_bsn_get_ip_mask_request {
+struct of_bsn_get_ip_mask_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -50,7 +50,7 @@
     pad(7);
 };
 
-struct of_bsn_get_ip_mask_reply {
+struct of_bsn_get_ip_mask_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_l2_table b/openflow_input/bsn_l2_table
index 8075d7f..725c805 100644
--- a/openflow_input/bsn_l2_table
+++ b/openflow_input/bsn_l2_table
@@ -28,7 +28,7 @@
 #version 1
 
 // BSN L2 table configuration messages
-struct of_bsn_set_l2_table_request {
+struct of_bsn_set_l2_table_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -41,7 +41,7 @@
     pad(4);
 };
 
-struct of_bsn_set_l2_table_reply {
+struct of_bsn_set_l2_table_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -54,7 +54,7 @@
     uint32_t status; // 0 means success
 };
 
-struct of_bsn_get_l2_table_request {
+struct of_bsn_get_l2_table_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -63,7 +63,7 @@
     uint32_t subtype == 13;
 };
 
-struct of_bsn_get_l2_table_reply {
+struct of_bsn_get_l2_table_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_mirror b/openflow_input/bsn_mirror
index cc9e4c3..e2f473f 100644
--- a/openflow_input/bsn_mirror
+++ b/openflow_input/bsn_mirror
@@ -28,7 +28,7 @@
 #version any
 
 // BSN mirror action
-struct of_action_bsn_mirror {
+struct of_action_bsn_mirror : of_action_bsn {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == 0x5c16c7;
@@ -40,7 +40,7 @@
 };
 
 // BSN mirroring messages
-struct of_bsn_set_mirroring {
+struct of_bsn_set_mirroring : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -51,7 +51,7 @@
     pad(3);
 };
 
-struct of_bsn_get_mirroring_request {
+struct of_bsn_get_mirroring_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -62,7 +62,7 @@
     pad(3);
 };
 
-struct of_bsn_get_mirroring_reply {
+struct of_bsn_get_mirroring_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_pktin_suppression b/openflow_input/bsn_pktin_suppression
index 281d6d4..ab4c2fd 100644
--- a/openflow_input/bsn_pktin_suppression
+++ b/openflow_input/bsn_pktin_suppression
@@ -55,7 +55,7 @@
 // The switch should reject the message if both 'hard_timeout' and 'idle_timeout'
 // are zero, since the suppression flows would never expire.
 
-struct of_bsn_set_pktin_suppression_request {
+struct of_bsn_set_pktin_suppression_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -70,7 +70,7 @@
     uint64_t cookie;
 };
 
-struct of_bsn_set_pktin_suppression_reply {
+struct of_bsn_set_pktin_suppression_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_set_tunnel_dst b/openflow_input/bsn_set_tunnel_dst
index 74757f6..b9be58f 100644
--- a/openflow_input/bsn_set_tunnel_dst
+++ b/openflow_input/bsn_set_tunnel_dst
@@ -28,7 +28,7 @@
 #version any
 
 // BSN set tunnel destination IP action
-struct of_action_bsn_set_tunnel_dst {
+struct of_action_bsn_set_tunnel_dst : of_action_bsn {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == 0x5c16c7;
diff --git a/openflow_input/bsn_shell b/openflow_input/bsn_shell
index 805b7e9..d9c2dc7 100644
--- a/openflow_input/bsn_shell
+++ b/openflow_input/bsn_shell
@@ -27,7 +27,7 @@
 
 #version 1
 
-struct of_bsn_shell_command {
+struct of_bsn_shell_command : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -38,7 +38,7 @@
     of_octets_t data;
 };
 
-struct of_bsn_shell_output {
+struct of_bsn_shell_output : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -48,7 +48,7 @@
     of_octets_t data;
 };
 
-struct of_bsn_shell_status {
+struct of_bsn_shell_status : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/bsn_table_mod b/openflow_input/bsn_table_mod
index cc5e723..5846c53 100644
--- a/openflow_input/bsn_table_mod
+++ b/openflow_input/bsn_table_mod
@@ -29,7 +29,7 @@
 
 // This is the 1.1+ table mod message which we back port to 1.0
 // for use inside components
-struct of_table_mod {
+struct of_table_mod : of_header {
     uint8_t version;
     uint8_t type == 22;
     uint16_t length;
diff --git a/openflow_input/bsn_vport b/openflow_input/bsn_vport
index 0cf30bf..4da4638 100644
--- a/openflow_input/bsn_vport
+++ b/openflow_input/bsn_vport
@@ -53,7 +53,7 @@
 
 // Q-in-Q virtual port specification
 
-struct of_bsn_vport_q_in_q {
+struct of_bsn_vport_q_in_q : of_bsn_vport {
     uint16_t type == 0;
     uint16_t length;  /* 16 */
     uint32_t port_no;     /* OF port number of parent; usually phys port */
@@ -64,7 +64,7 @@
 };
 
 // Request from controller to switch to create vport
-struct of_bsn_virtual_port_create_request {
+struct of_bsn_virtual_port_create_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -78,7 +78,7 @@
 
 // Reply from switch to controller indicating port number created
 // vport_no must be 16 bits to be compatible with 1.0
-struct of_bsn_virtual_port_create_reply {
+struct of_bsn_virtual_port_create_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -90,7 +90,7 @@
 };
 
 // Request from controller to switch to remove a vport
-struct of_bsn_virtual_port_remove_request {
+struct of_bsn_virtual_port_remove_request : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -101,7 +101,7 @@
 };
 
 // Request from controller to switch to remove a vport
-struct of_bsn_virtual_port_remove_reply {
+struct of_bsn_virtual_port_remove_reply : of_bsn_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/nicira b/openflow_input/nicira
new file mode 100644
index 0000000..f76be27
--- /dev/null
+++ b/openflow_input/nicira
@@ -0,0 +1,49 @@
+// 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 any
+
+// Nicira extension message
+struct of_nicira_header : of_experimenter {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x2320;
+    uint32_t subtype;
+};
+
+// Nicira extension action
+struct of_action_nicira: of_action_experimenter {
+    uint16_t type == 65535;
+    uint16_t len;
+    uint32_t experimenter == 0x2320;
+    uint16_t subtype;
+    pad(2);
+    pad(4);
+};
+
diff --git a/openflow_input/nicira_dec_ttl b/openflow_input/nicira_dec_ttl
index 77649af..3b95366 100644
--- a/openflow_input/nicira_dec_ttl
+++ b/openflow_input/nicira_dec_ttl
@@ -27,7 +27,7 @@
 
 #version any
 
-struct of_action_nicira_dec_ttl {
+struct of_action_nicira_dec_ttl : of_action_nicira {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == 0x2320;
diff --git a/openflow_input/nicira_role b/openflow_input/nicira_role
index 5747d45..1ed0b3d 100644
--- a/openflow_input/nicira_role
+++ b/openflow_input/nicira_role
@@ -33,7 +33,7 @@
    NX_ROLE_SLAVE = 2,
 };
 
-struct of_nicira_controller_role_request {
+struct of_nicira_controller_role_request : of_nicira_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -43,7 +43,7 @@
     uint32_t role;         // 0 other, 1 master, 2 slave
 };
 
-struct of_nicira_controller_role_reply {
+struct of_nicira_controller_role_reply : of_nicira_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
diff --git a/openflow_input/oxm-1.2 b/openflow_input/oxm-1.2
index 01af6c6..e75d218 100644
--- a/openflow_input/oxm-1.2
+++ b/openflow_input/oxm-1.2
@@ -32,403 +32,401 @@
 #version 3
 #version 4
 
-/* TODO fix the C backend to not require this */
 struct of_oxm {
     uint32_t type_len;
 };
 
-
-struct of_oxm_arp_op {
+struct of_oxm_arp_op : of_oxm {
     uint32_t type_len == 0x80002a02;
     uint16_t value;
 };
 
-struct of_oxm_arp_op_masked {
+struct of_oxm_arp_op_masked : of_oxm {
     uint32_t type_len == 0x80002b04;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_arp_sha {
+struct of_oxm_arp_sha : of_oxm {
     uint32_t type_len == 0x80003006;
     of_mac_addr_t value;
 };
 
-struct of_oxm_arp_sha_masked {
+struct of_oxm_arp_sha_masked : of_oxm {
     uint32_t type_len == 0x8000310c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_arp_spa {
+struct of_oxm_arp_spa : of_oxm {
     uint32_t type_len == 0x80002c04;
     uint32_t value;
 };
 
-struct of_oxm_arp_spa_masked {
+struct of_oxm_arp_spa_masked : of_oxm {
     uint32_t type_len == 0x80002d08;
     uint32_t value;
     uint32_t value_mask;
 };
 
-struct of_oxm_arp_tha {
+struct of_oxm_arp_tha : of_oxm {
     uint32_t type_len == 0x80003206;
     of_mac_addr_t value;
 };
 
-struct of_oxm_arp_tha_masked {
+struct of_oxm_arp_tha_masked : of_oxm {
     uint32_t type_len == 0x8000330c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_arp_tpa {
+struct of_oxm_arp_tpa : of_oxm {
     uint32_t type_len == 0x80002e04;
     uint32_t value;
 };
 
-struct of_oxm_arp_tpa_masked {
+struct of_oxm_arp_tpa_masked : of_oxm {
     uint32_t type_len == 0x80002f08;
     uint32_t value;
     uint32_t value_mask;
 };
 
-struct of_oxm_eth_dst {
+struct of_oxm_eth_dst : of_oxm {
     uint32_t type_len == 0x80000606;
     of_mac_addr_t value;
 };
 
-struct of_oxm_eth_dst_masked {
+struct of_oxm_eth_dst_masked : of_oxm {
     uint32_t type_len == 0x8000070c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_eth_src {
+struct of_oxm_eth_src : of_oxm {
     uint32_t type_len == 0x80000806;
     of_mac_addr_t value;
 };
 
-struct of_oxm_eth_src_masked {
+struct of_oxm_eth_src_masked : of_oxm {
     uint32_t type_len == 0x8000090c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_eth_type {
+struct of_oxm_eth_type : of_oxm {
     uint32_t type_len == 0x80000a02;
     uint16_t value;
 };
 
-struct of_oxm_eth_type_masked {
+struct of_oxm_eth_type_masked : of_oxm {
     uint32_t type_len == 0x80000b04;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_icmpv4_code {
+struct of_oxm_icmpv4_code : of_oxm {
     uint32_t type_len == 0x80002801;
     uint8_t value;
 };
 
-struct of_oxm_icmpv4_code_masked {
+struct of_oxm_icmpv4_code_masked : of_oxm {
     uint32_t type_len == 0x80002902;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_icmpv4_type {
+struct of_oxm_icmpv4_type : of_oxm {
     uint32_t type_len == 0x80002601;
     uint8_t value;
 };
 
-struct of_oxm_icmpv4_type_masked {
+struct of_oxm_icmpv4_type_masked : of_oxm {
     uint32_t type_len == 0x80002702;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_icmpv6_code {
+struct of_oxm_icmpv6_code : of_oxm {
     uint32_t type_len == 0x80003c01;
     uint8_t value;
 };
 
-struct of_oxm_icmpv6_code_masked {
+struct of_oxm_icmpv6_code_masked : of_oxm {
     uint32_t type_len == 0x80003d02;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_icmpv6_type {
+struct of_oxm_icmpv6_type : of_oxm {
     uint32_t type_len == 0x80003a01;
     uint8_t value;
 };
 
-struct of_oxm_icmpv6_type_masked {
+struct of_oxm_icmpv6_type_masked : of_oxm {
     uint32_t type_len == 0x80003b02;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_in_phy_port {
+struct of_oxm_in_phy_port : of_oxm {
     uint32_t type_len == 0x80000204;
     of_port_no_t value;
 };
 
-struct of_oxm_in_phy_port_masked {
+struct of_oxm_in_phy_port_masked : of_oxm {
     uint32_t type_len == 0x80000308;
     of_port_no_t value;
     of_port_no_t value_mask;
 };
 
-struct of_oxm_in_port {
+struct of_oxm_in_port : of_oxm {
     uint32_t type_len == 0x80000004;
     of_port_no_t value;
 };
 
-struct of_oxm_in_port_masked {
+struct of_oxm_in_port_masked : of_oxm {
     uint32_t type_len == 0x80000108;
     of_port_no_t value;
     of_port_no_t value_mask;
 };
 
-struct of_oxm_ip_dscp {
+struct of_oxm_ip_dscp : of_oxm {
     uint32_t type_len == 0x80001001;
     uint8_t value;
 };
 
-struct of_oxm_ip_dscp_masked {
+struct of_oxm_ip_dscp_masked : of_oxm {
     uint32_t type_len == 0x80001102;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_ip_ecn {
+struct of_oxm_ip_ecn : of_oxm {
     uint32_t type_len == 0x80001201;
     uint8_t value;
 };
 
-struct of_oxm_ip_ecn_masked {
+struct of_oxm_ip_ecn_masked : of_oxm {
     uint32_t type_len == 0x80001302;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_ip_proto {
+struct of_oxm_ip_proto : of_oxm {
     uint32_t type_len == 0x80001401;
     uint8_t value;
 };
 
-struct of_oxm_ip_proto_masked {
+struct of_oxm_ip_proto_masked : of_oxm {
     uint32_t type_len == 0x80001502;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_ipv4_dst {
+struct of_oxm_ipv4_dst : of_oxm {
     uint32_t type_len == 0x80001804;
     of_ipv4_t value;
 };
 
-struct of_oxm_ipv4_dst_masked {
+struct of_oxm_ipv4_dst_masked : of_oxm {
     uint32_t type_len == 0x80001908;
     of_ipv4_t value;
     of_ipv4_t value_mask;
 };
 
-struct of_oxm_ipv4_src {
+struct of_oxm_ipv4_src : of_oxm {
     uint32_t type_len == 0x80001604;
     of_ipv4_t value;
 };
 
-struct of_oxm_ipv4_src_masked {
+struct of_oxm_ipv4_src_masked : of_oxm {
     uint32_t type_len == 0x80001708;
     of_ipv4_t value;
     of_ipv4_t value_mask;
 };
 
-struct of_oxm_ipv6_dst {
+struct of_oxm_ipv6_dst : of_oxm {
     uint32_t type_len == 0x80003610;
     of_ipv6_t value;
 };
 
-struct of_oxm_ipv6_dst_masked {
+struct of_oxm_ipv6_dst_masked : of_oxm {
     uint32_t type_len == 0x80003720;
     of_ipv6_t value;
     of_ipv6_t value_mask;
 };
 
-struct of_oxm_ipv6_flabel {
+struct of_oxm_ipv6_flabel : of_oxm {
     uint32_t type_len == 0x80003804;
     uint32_t value;
 };
 
-struct of_oxm_ipv6_flabel_masked {
+struct of_oxm_ipv6_flabel_masked : of_oxm {
     uint32_t type_len == 0x80003908;
     uint32_t value;
     uint32_t value_mask;
 };
 
-struct of_oxm_ipv6_nd_sll {
+struct of_oxm_ipv6_nd_sll : of_oxm {
     uint32_t type_len == 0x80004006;
     of_mac_addr_t value;
 };
 
-struct of_oxm_ipv6_nd_sll_masked {
+struct of_oxm_ipv6_nd_sll_masked : of_oxm {
     uint32_t type_len == 0x8000410c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_ipv6_nd_target {
+struct of_oxm_ipv6_nd_target : of_oxm {
     uint32_t type_len == 0x80003e10;
     of_ipv6_t value;
 };
 
-struct of_oxm_ipv6_nd_target_masked {
+struct of_oxm_ipv6_nd_target_masked : of_oxm {
     uint32_t type_len == 0x80003f20;
     of_ipv6_t value;
     of_ipv6_t value_mask;
 };
 
-struct of_oxm_ipv6_nd_tll {
+struct of_oxm_ipv6_nd_tll : of_oxm {
     uint32_t type_len == 0x80004206;
     of_mac_addr_t value;
 };
 
-struct of_oxm_ipv6_nd_tll_masked {
+struct of_oxm_ipv6_nd_tll_masked : of_oxm {
     uint32_t type_len == 0x8000430c;
     of_mac_addr_t value;
     of_mac_addr_t value_mask;
 };
 
-struct of_oxm_ipv6_src {
+struct of_oxm_ipv6_src : of_oxm {
     uint32_t type_len == 0x80003410;
     of_ipv6_t value;
 };
 
-struct of_oxm_ipv6_src_masked {
+struct of_oxm_ipv6_src_masked : of_oxm {
     uint32_t type_len == 0x80003520;
     of_ipv6_t value;
     of_ipv6_t value_mask;
 };
 
-struct of_oxm_metadata {
+struct of_oxm_metadata : of_oxm {
     uint32_t type_len == 0x80000408;
     uint64_t value;
 };
 
-struct of_oxm_metadata_masked {
+struct of_oxm_metadata_masked : of_oxm {
     uint32_t type_len == 0x80000510;
     uint64_t value;
     uint64_t value_mask;
 };
 
-struct of_oxm_mpls_label {
+struct of_oxm_mpls_label : of_oxm {
     uint32_t type_len == 0x80004404;
     uint32_t value;
 };
 
-struct of_oxm_mpls_label_masked {
+struct of_oxm_mpls_label_masked : of_oxm {
     uint32_t type_len == 0x80004508;
     uint32_t value;
     uint32_t value_mask;
 };
 
-struct of_oxm_mpls_tc {
+struct of_oxm_mpls_tc : of_oxm {
     uint32_t type_len == 0x80004601;
     uint8_t value;
 };
 
-struct of_oxm_mpls_tc_masked {
+struct of_oxm_mpls_tc_masked : of_oxm {
     uint32_t type_len == 0x80004702;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_sctp_dst {
+struct of_oxm_sctp_dst : of_oxm {
     uint32_t type_len == 0x80002402;
     uint16_t value;
 };
 
-struct of_oxm_sctp_dst_masked {
+struct of_oxm_sctp_dst_masked : of_oxm {
     uint32_t type_len == 0x80002504;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_sctp_src {
+struct of_oxm_sctp_src : of_oxm {
     uint32_t type_len == 0x80002202;
     uint16_t value;
 };
 
-struct of_oxm_sctp_src_masked {
+struct of_oxm_sctp_src_masked : of_oxm {
     uint32_t type_len == 0x80002304;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_tcp_dst {
+struct of_oxm_tcp_dst : of_oxm {
     uint32_t type_len == 0x80001c02;
     uint16_t value;
 };
 
-struct of_oxm_tcp_dst_masked {
+struct of_oxm_tcp_dst_masked : of_oxm {
     uint32_t type_len == 0x80001d04;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_tcp_src {
+struct of_oxm_tcp_src : of_oxm {
     uint32_t type_len == 0x80001a02;
     uint16_t value;
 };
 
-struct of_oxm_tcp_src_masked {
+struct of_oxm_tcp_src_masked : of_oxm {
     uint32_t type_len == 0x80001b04;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_udp_dst {
+struct of_oxm_udp_dst : of_oxm {
     uint32_t type_len == 0x80002002;
     uint16_t value;
 };
 
-struct of_oxm_udp_dst_masked {
+struct of_oxm_udp_dst_masked : of_oxm {
     uint32_t type_len == 0x80002104;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_udp_src {
+struct of_oxm_udp_src : of_oxm {
     uint32_t type_len == 0x80001e02;
     uint16_t value;
 };
 
-struct of_oxm_udp_src_masked {
+struct of_oxm_udp_src_masked : of_oxm {
     uint32_t type_len == 0x80001f04;
     uint16_t value;
     uint16_t value_mask;
 };
 
-struct of_oxm_vlan_pcp {
+struct of_oxm_vlan_pcp : of_oxm {
     uint32_t type_len == 0x80000e01;
     uint8_t value;
 };
 
-struct of_oxm_vlan_pcp_masked {
+struct of_oxm_vlan_pcp_masked : of_oxm {
     uint32_t type_len == 0x80000f02;
     uint8_t value;
     uint8_t value_mask;
 };
 
-struct of_oxm_vlan_vid {
+struct of_oxm_vlan_vid : of_oxm {
     uint32_t type_len == 0x80000c02;
     uint16_t value;
 };
 
-struct of_oxm_vlan_vid_masked {
+struct of_oxm_vlan_vid_masked : of_oxm {
     uint32_t type_len == 0x80000d04;
     uint16_t value;
     uint16_t value_mask;
diff --git a/openflow_input/standard-1.0 b/openflow_input/standard-1.0
index e9cb6f0..64c60d5 100644
--- a/openflow_input/standard-1.0
+++ b/openflow_input/standard-1.0
@@ -296,6 +296,7 @@
     OFPQOFC_EPERM = 2,
 };
 
+/* XXX rename to of_message */
 struct of_header {
     uint8_t version;
     uint8_t type;
@@ -303,14 +304,14 @@
     uint32_t xid;
 };
 
-struct of_hello {
+struct of_hello : of_header {
     uint8_t version;
     uint8_t type == 0;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_echo_request {
+struct of_echo_request : of_header {
     uint8_t version;
     uint8_t type == 2;
     uint16_t length;
@@ -318,7 +319,7 @@
     of_octets_t data;
 };
 
-struct of_echo_reply {
+struct of_echo_reply : of_header {
     uint8_t version;
     uint8_t type == 3;
     uint16_t length;
@@ -326,7 +327,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter {
+struct of_experimenter : of_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -336,28 +337,28 @@
     of_octets_t data;
 };
 
-struct of_barrier_request {
+struct of_barrier_request : of_header {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_barrier_reply {
+struct of_barrier_reply : of_header {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_request {
+struct of_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 7;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_reply {
+struct of_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 8;
     uint16_t length;
@@ -366,7 +367,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_set_config {
+struct of_set_config : of_header {
     uint8_t version;
     uint8_t type == 9;
     uint16_t length;
@@ -387,14 +388,14 @@
     uint32_t peer;
 };
 
-struct of_features_request {
+struct of_features_request : of_header {
     uint8_t version;
     uint8_t type == 5;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_features_reply {
+struct of_features_reply : of_header {
     uint8_t version;
     uint8_t type == 6;
     uint16_t length;
@@ -408,7 +409,7 @@
     list(of_port_desc_t) ports;
 };
 
-struct of_port_status {
+struct of_port_status : of_header {
     uint8_t version;
     uint8_t type == 12;
     uint16_t length;
@@ -418,7 +419,7 @@
     of_port_desc_t desc;
 };
 
-struct of_port_mod {
+struct of_port_mod : of_header {
     uint8_t version;
     uint8_t type == 15;
     uint16_t length;
@@ -431,7 +432,7 @@
     pad(4);
 };
 
-struct of_packet_in {
+struct of_packet_in : of_header {
     uint8_t version;
     uint8_t type == 10;
     uint16_t length;
@@ -444,88 +445,88 @@
     of_octets_t data;
 };
 
-struct of_action_output {
+struct of_action_output : of_action {
     uint16_t type == 0;
     uint16_t len;
     of_port_no_t port;
     uint16_t max_len;
 };
 
-struct of_action_set_vlan_vid {
+struct of_action_set_vlan_vid : of_action {
     uint16_t type == 1;
     uint16_t len;
     uint16_t vlan_vid;
     pad(2);
 };
 
-struct of_action_strip_vlan {
+struct of_action_strip_vlan : of_action {
     uint16_t type == 3;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_vlan_pcp {
+struct of_action_set_vlan_pcp : of_action {
     uint16_t type == 2;
     uint16_t len;
     uint8_t vlan_pcp;
     pad(3);
 };
 
-struct of_action_set_dl_src {
+struct of_action_set_dl_src : of_action {
     uint16_t type == 4;
     uint16_t len;
     of_mac_addr_t dl_addr;
     pad(6);
 };
 
-struct of_action_set_dl_dst {
+struct of_action_set_dl_dst : of_action {
     uint16_t type == 5;
     uint16_t len;
     of_mac_addr_t dl_addr;
     pad(6);
 };
 
-struct of_action_set_nw_src {
+struct of_action_set_nw_src : of_action {
     uint16_t type == 6;
     uint16_t len;
     uint32_t nw_addr;
 };
 
-struct of_action_set_nw_dst {
+struct of_action_set_nw_dst : of_action {
     uint16_t type == 7;
     uint16_t len;
     uint32_t nw_addr;
 };
 
-struct of_action_set_tp_src {
+struct of_action_set_tp_src : of_action {
     uint16_t type == 9;
     uint16_t len;
     uint16_t tp_port;
     pad(2);
 };
 
-struct of_action_set_tp_dst {
+struct of_action_set_tp_dst : of_action {
     uint16_t type == 10;
     uint16_t len;
     uint16_t tp_port;
     pad(2);
 };
 
-struct of_action_set_nw_tos {
+struct of_action_set_nw_tos : of_action {
     uint16_t type == 8;
     uint16_t len;
     uint8_t nw_tos;
     pad(3);
 };
 
-struct of_action_experimenter {
+struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
     of_octets_t data;
 };
 
-struct of_action_enqueue {
+struct of_action_enqueue : of_action {
     uint16_t type == 11;
     uint16_t len;
     of_port_no_t port;
@@ -539,7 +540,7 @@
     pad(4);
 };
 
-struct of_packet_out {
+struct of_packet_out : of_header {
     uint8_t version;
     uint8_t type == 13;
     uint16_t length;
@@ -569,7 +570,24 @@
     uint16_t tcp_dst;
 };
 
-struct of_flow_add {
+struct of_flow_mod : of_header {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    of_match_t match;
+    uint64_t cookie;
+    of_fm_cmd_t _command;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint16_t flags;
+    list(of_action_t) actions;
+};
+
+struct of_flow_add : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -586,7 +604,7 @@
     list(of_action_t) actions;
 };
 
-struct of_flow_modify {
+struct of_flow_modify : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -603,7 +621,7 @@
     list(of_action_t) actions;
 };
 
-struct of_flow_modify_strict {
+struct of_flow_modify_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -620,7 +638,7 @@
     list(of_action_t) actions;
 };
 
-struct of_flow_delete {
+struct of_flow_delete : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -637,7 +655,7 @@
     list(of_action_t) actions;
 };
 
-struct of_flow_delete_strict {
+struct of_flow_delete_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -654,7 +672,7 @@
     list(of_action_t) actions;
 };
 
-struct of_flow_removed {
+struct of_flow_removed : of_header {
     uint8_t version;
     uint8_t type == 11;
     uint16_t length;
@@ -672,7 +690,7 @@
     uint64_t byte_count;
 };
 
-struct of_error_msg {
+struct of_error_msg : of_header {
     uint8_t version;
     uint8_t type == 1;
     uint16_t length;
@@ -739,7 +757,25 @@
 
 // STATS request/reply:  Desc, flow, agg, table, port, queue
 
-struct of_desc_stats_request {
+struct of_stats_request : of_header {
+    uint8_t version;
+    uint8_t type == 16;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+};
+
+struct of_stats_reply : of_header {
+    uint8_t version;
+    uint8_t type == 17;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+};
+
+struct of_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -748,7 +784,7 @@
     uint16_t flags;
 };
 
-struct of_desc_stats_reply {
+struct of_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -762,7 +798,7 @@
     of_desc_str_t dp_desc;
 };
 
-struct of_flow_stats_request {
+struct of_flow_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -775,7 +811,7 @@
     of_port_no_t out_port;
 };
 
-struct of_flow_stats_reply {
+struct of_flow_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -785,7 +821,7 @@
     list(of_flow_stats_entry_t) entries;
 };
 
-struct of_aggregate_stats_request {
+struct of_aggregate_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -798,7 +834,7 @@
     of_port_no_t out_port;
 };
 
-struct of_aggregate_stats_reply {
+struct of_aggregate_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -811,7 +847,7 @@
     pad(4);
 };
 
-struct of_table_stats_request {
+struct of_table_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -820,7 +856,7 @@
     uint16_t flags;
 };
 
-struct of_table_stats_reply {
+struct of_table_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -830,7 +866,7 @@
     list(of_table_stats_entry_t) entries;
 };
 
-struct of_port_stats_request {
+struct of_port_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -841,7 +877,7 @@
     pad(6);
 };
 
-struct of_port_stats_reply {
+struct of_port_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -851,7 +887,7 @@
     list(of_port_stats_entry_t) entries;
 };
 
-struct of_queue_stats_request {
+struct of_queue_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -863,7 +899,7 @@
     uint32_t queue_id;
 };
 
-struct of_queue_stats_reply {
+struct of_queue_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -873,7 +909,7 @@
     list(of_queue_stats_entry_t) entries;
 };
 
-struct of_experimenter_stats_request {
+struct of_experimenter_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -884,7 +920,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter_stats_reply {
+struct of_experimenter_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -903,7 +939,7 @@
     pad(4);
 };
 
-struct of_queue_prop_min_rate {
+struct of_queue_prop_min_rate : of_queue_prop {
     uint16_t type == 1;
     uint16_t len;
     pad(4);
@@ -918,7 +954,7 @@
     list(of_queue_prop_t) properties;
 };
 
-struct of_queue_get_config_request {
+struct of_queue_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 20;
     uint16_t length;
@@ -927,7 +963,7 @@
     pad(2);
 };
 
-struct of_queue_get_config_reply {
+struct of_queue_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 21;
     uint16_t length;
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index 553e665..4366af8 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -407,6 +407,7 @@
     OFPQT_MIN_RATE = 1,
 };
 
+/* XXX rename to of_message */
 struct of_header {
     uint8_t version;
     uint8_t type;
@@ -414,14 +415,14 @@
     uint32_t xid;
 };
 
-struct of_hello {
+struct of_hello : of_header {
     uint8_t version;
     uint8_t type == 0;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_echo_request {
+struct of_echo_request : of_header {
     uint8_t version;
     uint8_t type == 2;
     uint16_t length;
@@ -429,7 +430,7 @@
     of_octets_t data;
 };
 
-struct of_echo_reply {
+struct of_echo_reply : of_header {
     uint8_t version;
     uint8_t type == 3;
     uint16_t length;
@@ -437,7 +438,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter {
+struct of_experimenter : of_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -447,28 +448,28 @@
     of_octets_t data;
 };
 
-struct of_barrier_request {
+struct of_barrier_request : of_header {
     uint8_t version;
     uint8_t type == 20;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_barrier_reply {
+struct of_barrier_reply : of_header {
     uint8_t version;
     uint8_t type == 21;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_request {
+struct of_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 7;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_reply {
+struct of_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 8;
     uint16_t length;
@@ -477,7 +478,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_set_config {
+struct of_set_config : of_header {
     uint8_t version;
     uint8_t type == 9;
     uint16_t length;
@@ -486,7 +487,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_table_mod {
+struct of_table_mod : of_header {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -512,14 +513,14 @@
     uint32_t max_speed;
 };
 
-struct of_features_request {
+struct of_features_request : of_header {
     uint8_t version;
     uint8_t type == 5;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_features_reply {
+struct of_features_reply : of_header {
     uint8_t version;
     uint8_t type == 6;
     uint16_t length;
@@ -533,7 +534,7 @@
     list(of_port_desc_t) ports;
 };
 
-struct of_port_status {
+struct of_port_status : of_header {
     uint8_t version;
     uint8_t type == 12;
     uint16_t length;
@@ -543,7 +544,7 @@
     of_port_desc_t desc;
 };
 
-struct of_port_mod {
+struct of_port_mod : of_header {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -558,7 +559,7 @@
     pad(4);
 };
 
-struct of_packet_in {
+struct of_packet_in : of_header {
     uint8_t version;
     uint8_t type == 10;
     uint16_t length;
@@ -572,7 +573,7 @@
     of_octets_t data;
 };
 
-struct of_action_output {
+struct of_action_output : of_action {
     uint16_t type == 0;
     uint16_t len;
     of_port_no_t port;
@@ -580,165 +581,165 @@
     pad(6);
 };
 
-struct of_action_set_vlan_vid {
+struct of_action_set_vlan_vid : of_action {
     uint16_t type == 1;
     uint16_t len;
     uint16_t vlan_vid;
     pad(2);
 };
 
-struct of_action_set_vlan_pcp {
+struct of_action_set_vlan_pcp : of_action {
     uint16_t type == 2;
     uint16_t len;
     uint8_t vlan_pcp;
     pad(3);
 };
 
-struct of_action_set_dl_src {
+struct of_action_set_dl_src : of_action {
     uint16_t type == 3;
     uint16_t len;
     of_mac_addr_t dl_addr;
     pad(6);
 };
 
-struct of_action_set_dl_dst {
+struct of_action_set_dl_dst : of_action {
     uint16_t type == 4;
     uint16_t len;
     of_mac_addr_t dl_addr;
     pad(6);
 };
 
-struct of_action_set_nw_src {
+struct of_action_set_nw_src : of_action {
     uint16_t type == 5;
     uint16_t len;
     uint32_t nw_addr;
 };
 
-struct of_action_set_nw_dst {
+struct of_action_set_nw_dst : of_action {
     uint16_t type == 6;
     uint16_t len;
     uint32_t nw_addr;
 };
 
-struct of_action_set_nw_tos {
+struct of_action_set_nw_tos : of_action {
     uint16_t type == 7;
     uint16_t len;
     uint8_t nw_tos;
     pad(3);
 };
 
-struct of_action_set_nw_ecn {
+struct of_action_set_nw_ecn : of_action {
     uint16_t type == 8;
     uint16_t len;
     uint8_t nw_ecn;
     pad(3);
 };
 
-struct of_action_set_tp_src {
+struct of_action_set_tp_src : of_action {
     uint16_t type == 9;
     uint16_t len;
     uint16_t tp_port;
     pad(2);
 };
 
-struct of_action_set_tp_dst {
+struct of_action_set_tp_dst : of_action {
     uint16_t type == 10;
     uint16_t len;
     uint16_t tp_port;
     pad(2);
 };
 
-struct of_action_copy_ttl_out {
+struct of_action_copy_ttl_out : of_action {
     uint16_t type == 11;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_copy_ttl_in {
+struct of_action_copy_ttl_in : of_action {
     uint16_t type == 12;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_mpls_label {
+struct of_action_set_mpls_label : of_action {
     uint16_t type == 13;
     uint16_t len;
     uint32_t mpls_label;
 };
 
-struct of_action_set_mpls_tc {
+struct of_action_set_mpls_tc : of_action {
     uint16_t type == 14;
     uint16_t len;
     uint8_t mpls_tc;
     pad(3);
 };
 
-struct of_action_set_mpls_ttl {
+struct of_action_set_mpls_ttl : of_action {
     uint16_t type == 15;
     uint16_t len;
     uint8_t mpls_ttl;
     pad(3);
 };
 
-struct of_action_dec_mpls_ttl {
+struct of_action_dec_mpls_ttl : of_action {
     uint16_t type == 16;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_vlan {
+struct of_action_push_vlan : of_action {
     uint16_t type == 17;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_vlan {
+struct of_action_pop_vlan : of_action {
     uint16_t type == 18;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_mpls {
+struct of_action_push_mpls : of_action {
     uint16_t type == 19;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_mpls {
+struct of_action_pop_mpls : of_action {
     uint16_t type == 20;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_set_queue {
+struct of_action_set_queue : of_action {
     uint16_t type == 21;
     uint16_t len;
     uint32_t queue_id;
 };
 
-struct of_action_group {
+struct of_action_group : of_action {
     uint16_t type == 22;
     uint16_t len;
     uint32_t group_id;
 };
 
-struct of_action_set_nw_ttl {
+struct of_action_set_nw_ttl : of_action {
     uint16_t type == 23;
     uint16_t len;
     uint8_t nw_ttl;
     pad(3);
 };
 
-struct of_action_dec_nw_ttl {
+struct of_action_dec_nw_ttl : of_action {
     uint16_t type == 24;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_experimenter {
+struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
@@ -751,7 +752,7 @@
     pad(4);
 };
 
-struct of_packet_out {
+struct of_packet_out : of_header {
     uint8_t version;
     uint8_t type == 13;
     uint16_t length;
@@ -798,14 +799,14 @@
     pad(4);
 };
 
-struct of_instruction_goto_table {
+struct of_instruction_goto_table : of_instruction {
     uint16_t type == 1;
     uint16_t len;
     uint8_t table_id;
     pad(3);
 };
 
-struct of_instruction_write_metadata {
+struct of_instruction_write_metadata : of_instruction {
     uint16_t type == 2;
     uint16_t len;
     pad(4);
@@ -813,34 +814,55 @@
     uint64_t metadata_mask;
 };
 
-struct of_instruction_write_actions {
+struct of_instruction_write_actions : of_instruction {
     uint16_t type == 3;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_apply_actions {
+struct of_instruction_apply_actions : of_instruction {
     uint16_t type == 4;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_clear_actions {
+struct of_instruction_clear_actions : of_instruction {
     uint16_t type == 5;
     uint16_t len;
     pad(4);
 };
 
-struct of_instruction_experimenter {
+struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
     of_octets_t data;
 };
 
-struct of_flow_add {
+struct of_flow_mod : of_header {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    uint16_t flags;
+    pad(2);
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_add : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -861,7 +883,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify {
+struct of_flow_modify : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -882,7 +904,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify_strict {
+struct of_flow_modify_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -903,7 +925,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete {
+struct of_flow_delete : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -924,7 +946,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete_strict {
+struct of_flow_delete_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -954,7 +976,7 @@
     list(of_action_t) actions;
 };
 
-struct of_group_mod {
+struct of_group_mod : of_header {
     uint8_t version;
     uint8_t type == 15;
     uint16_t length;
@@ -966,7 +988,7 @@
     list(of_bucket_t) buckets;
 };
 
-struct of_flow_removed {
+struct of_flow_removed : of_header {
     uint8_t version;
     uint8_t type == 11;
     uint16_t length;
@@ -984,7 +1006,7 @@
     of_match_t match;
 };
 
-struct of_error_msg {
+struct of_error_msg : of_header {
     uint8_t version;
     uint8_t type == 1;
     uint16_t length;
@@ -1080,7 +1102,27 @@
 
 // STATS:  Desc, flow, agg, table, port, queue, group, group_desc, experi
 
-struct of_desc_stats_request {
+struct of_stats_request : of_header {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_stats_reply : of_header {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1090,7 +1132,7 @@
     pad(4);
 };
 
-struct of_desc_stats_reply {
+struct of_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1105,7 +1147,7 @@
     of_desc_str_t dp_desc;
 };
 
-struct of_flow_stats_request {
+struct of_flow_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1123,7 +1165,7 @@
     of_match_t match;
 };
 
-struct of_flow_stats_reply {
+struct of_flow_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1134,7 +1176,7 @@
     list(of_flow_stats_entry_t) entries;
 };
 
-struct of_aggregate_stats_request {
+struct of_aggregate_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1152,7 +1194,7 @@
     of_match_t match;
 };
 
-struct of_aggregate_stats_reply {
+struct of_aggregate_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1166,7 +1208,7 @@
     pad(4);
 };
 
-struct of_table_stats_request {
+struct of_table_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1176,7 +1218,7 @@
     pad(4);
 };
 
-struct of_table_stats_reply {
+struct of_table_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1187,7 +1229,7 @@
     list(of_table_stats_entry_t) entries;
 };
 
-struct of_port_stats_request {
+struct of_port_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1199,7 +1241,7 @@
     pad(4);
 };
 
-struct of_port_stats_reply {
+struct of_port_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1210,7 +1252,7 @@
     list(of_port_stats_entry_t) entries;
 };
 
-struct of_queue_stats_request {
+struct of_queue_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1222,7 +1264,7 @@
     uint32_t queue_id;
 };
 
-struct of_queue_stats_reply {
+struct of_queue_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1233,7 +1275,7 @@
     list(of_queue_stats_entry_t) entries;
 };
 
-struct of_group_stats_request {
+struct of_group_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1245,7 +1287,7 @@
     pad(4);
 };
 
-struct of_group_stats_reply {
+struct of_group_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1256,7 +1298,7 @@
     list(of_group_stats_entry_t) entries;
 };
 
-struct of_group_desc_stats_request {
+struct of_group_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1266,7 +1308,7 @@
     pad(4);
 };
 
-struct of_group_desc_stats_reply {
+struct of_group_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1277,7 +1319,7 @@
     list(of_group_desc_stats_entry_t) entries;
 };
 
-struct of_experimenter_stats_request {
+struct of_experimenter_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1290,7 +1332,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter_stats_reply {
+struct of_experimenter_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1311,7 +1353,7 @@
     pad(4);
 };
 
-struct of_queue_prop_min_rate {
+struct of_queue_prop_min_rate : of_queue_prop {
     uint16_t type == 1;
     uint16_t len;
     pad(4);
@@ -1326,7 +1368,7 @@
     list(of_queue_prop_t) properties;
 };
 
-struct of_queue_get_config_request {
+struct of_queue_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 22;
     uint16_t length;
@@ -1335,7 +1377,7 @@
     pad(4);
 };
 
-struct of_queue_get_config_reply {
+struct of_queue_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 23;
     uint16_t length;
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index 8b4fa3f..b49c83f 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -447,6 +447,7 @@
     OFPCR_ROLE_SLAVE = 3,
 };
 
+/* XXX rename to of_message */
 struct of_header {
     uint8_t version;
     uint8_t type;
@@ -454,14 +455,14 @@
     uint32_t xid;
 };
 
-struct of_hello {
+struct of_hello : of_header {
     uint8_t version;
     uint8_t type == 0;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_echo_request {
+struct of_echo_request : of_header {
     uint8_t version;
     uint8_t type == 2;
     uint16_t length;
@@ -469,7 +470,7 @@
     of_octets_t data;
 };
 
-struct of_echo_reply {
+struct of_echo_reply : of_header {
     uint8_t version;
     uint8_t type == 3;
     uint16_t length;
@@ -477,7 +478,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter {
+struct of_experimenter : of_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -487,28 +488,28 @@
     of_octets_t data;
 };
 
-struct of_barrier_request {
+struct of_barrier_request : of_header {
     uint8_t version;
     uint8_t type == 20;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_barrier_reply {
+struct of_barrier_reply : of_header {
     uint8_t version;
     uint8_t type == 21;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_request {
+struct of_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 7;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_reply {
+struct of_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 8;
     uint16_t length;
@@ -517,7 +518,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_set_config {
+struct of_set_config : of_header {
     uint8_t version;
     uint8_t type == 9;
     uint16_t length;
@@ -526,7 +527,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_table_mod {
+struct of_table_mod : of_header {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -552,14 +553,14 @@
     uint32_t max_speed;
 };
 
-struct of_features_request {
+struct of_features_request : of_header {
     uint8_t version;
     uint8_t type == 5;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_features_reply {
+struct of_features_reply : of_header {
     uint8_t version;
     uint8_t type == 6;
     uint16_t length;
@@ -573,7 +574,7 @@
     list(of_port_desc_t) ports;
 };
 
-struct of_port_status {
+struct of_port_status : of_header {
     uint8_t version;
     uint8_t type == 12;
     uint16_t length;
@@ -583,7 +584,7 @@
     of_port_desc_t desc;
 };
 
-struct of_port_mod {
+struct of_port_mod : of_header {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -604,7 +605,7 @@
     list(of_oxm_t) oxm_list;
 };
 
-struct of_action_output {
+struct of_action_output : of_action {
     uint16_t type == 0;
     uint16_t len;
     of_port_no_t port;
@@ -612,90 +613,90 @@
     pad(6);
 };
 
-struct of_action_copy_ttl_out {
+struct of_action_copy_ttl_out : of_action {
     uint16_t type == 11;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_copy_ttl_in {
+struct of_action_copy_ttl_in : of_action {
     uint16_t type == 12;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_mpls_ttl {
+struct of_action_set_mpls_ttl : of_action {
     uint16_t type == 15;
     uint16_t len;
     uint8_t mpls_ttl;
     pad(3);
 };
 
-struct of_action_dec_mpls_ttl {
+struct of_action_dec_mpls_ttl : of_action {
     uint16_t type == 16;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_vlan {
+struct of_action_push_vlan : of_action {
     uint16_t type == 17;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_vlan {
+struct of_action_pop_vlan : of_action {
     uint16_t type == 18;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_mpls {
+struct of_action_push_mpls : of_action {
     uint16_t type == 19;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_mpls {
+struct of_action_pop_mpls : of_action {
     uint16_t type == 20;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_set_queue {
+struct of_action_set_queue : of_action {
     uint16_t type == 21;
     uint16_t len;
     uint32_t queue_id;
 };
 
-struct of_action_group {
+struct of_action_group : of_action {
     uint16_t type == 22;
     uint16_t len;
     uint32_t group_id;
 };
 
-struct of_action_set_nw_ttl {
+struct of_action_set_nw_ttl : of_action {
     uint16_t type == 23;
     uint16_t len;
     uint8_t nw_ttl;
     pad(3);
 };
 
-struct of_action_dec_nw_ttl {
+struct of_action_dec_nw_ttl : of_action {
     uint16_t type == 24;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_field {
+struct of_action_set_field : of_action {
     uint16_t type == 25;
     uint16_t len;
     of_oxm_t field;
 };
 
-struct of_action_experimenter {
+struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
@@ -714,14 +715,14 @@
     pad(4);
 };
 
-struct of_instruction_goto_table {
+struct of_instruction_goto_table : of_instruction {
     uint16_t type == 1;
     uint16_t len;
     uint8_t table_id;
     pad(3);
 };
 
-struct of_instruction_write_metadata {
+struct of_instruction_write_metadata : of_instruction {
     uint16_t type == 2;
     uint16_t len;
     pad(4);
@@ -729,34 +730,55 @@
     uint64_t metadata_mask;
 };
 
-struct of_instruction_write_actions {
+struct of_instruction_write_actions : of_instruction {
     uint16_t type == 3;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_apply_actions {
+struct of_instruction_apply_actions : of_instruction {
     uint16_t type == 4;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_clear_actions {
+struct of_instruction_clear_actions : of_instruction {
     uint16_t type == 5;
     uint16_t len;
     pad(4);
 };
 
-struct of_instruction_experimenter {
+struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
     of_octets_t data;
 };
 
-struct of_flow_add {
+struct of_flow_mod : of_header {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    uint16_t flags;
+    pad(2);
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_add : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -777,7 +799,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify {
+struct of_flow_modify : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -798,7 +820,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify_strict {
+struct of_flow_modify_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -819,7 +841,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete {
+struct of_flow_delete : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -840,7 +862,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete_strict {
+struct of_flow_delete_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -870,7 +892,7 @@
     list(of_action_t) actions;
 };
 
-struct of_group_mod {
+struct of_group_mod : of_header {
     uint8_t version;
     uint8_t type == 15;
     uint16_t length;
@@ -882,7 +904,7 @@
     list(of_bucket_t) buckets;
 };
 
-struct of_packet_out {
+struct of_packet_out : of_header {
     uint8_t version;
     uint8_t type == 13;
     uint16_t length;
@@ -895,7 +917,7 @@
     of_octets_t data;
 };
 
-struct of_packet_in {
+struct of_packet_in : of_header {
     uint8_t version;
     uint8_t type == 10;
     uint16_t length;
@@ -909,7 +931,7 @@
     of_octets_t data; /* FIXME: Ensure total_len gets updated */
 };
 
-struct of_flow_removed {
+struct of_flow_removed : of_header {
     uint8_t version;
     uint8_t type == 11;
     uint16_t length;
@@ -927,7 +949,7 @@
     of_match_t match;
 };
 
-struct of_error_msg {
+struct of_error_msg : of_header {
     uint8_t version;
     uint8_t type == 1;
     uint16_t length;
@@ -1040,7 +1062,27 @@
 // STATS: 
 //  Desc, flow, agg, table, port, queue, group, group_desc, group_feat, experi
 
-struct of_desc_stats_request {
+struct of_stats_request : of_header {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_stats_reply : of_header {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1050,7 +1092,7 @@
     pad(4);
 };
 
-struct of_desc_stats_reply {
+struct of_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1065,7 +1107,7 @@
     of_desc_str_t dp_desc;
 };
 
-struct of_flow_stats_request {
+struct of_flow_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1083,7 +1125,7 @@
     of_match_t match;
 };
 
-struct of_flow_stats_reply {
+struct of_flow_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1094,7 +1136,7 @@
     list(of_flow_stats_entry_t) entries;
 };
 
-struct of_aggregate_stats_request {
+struct of_aggregate_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1112,7 +1154,7 @@
     of_match_t match;
 };
 
-struct of_aggregate_stats_reply {
+struct of_aggregate_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1126,7 +1168,7 @@
     pad(4);
 };
 
-struct of_table_stats_request {
+struct of_table_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1136,7 +1178,7 @@
     pad(4);
 };
 
-struct of_table_stats_reply {
+struct of_table_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1147,7 +1189,7 @@
     list(of_table_stats_entry_t) entries;
 };
 
-struct of_port_stats_request {
+struct of_port_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1159,7 +1201,7 @@
     pad(4);
 };
 
-struct of_port_stats_reply {
+struct of_port_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1170,7 +1212,7 @@
     list(of_port_stats_entry_t) entries;
 };
 
-struct of_queue_stats_request {
+struct of_queue_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1182,7 +1224,7 @@
     uint32_t queue_id;
 };
 
-struct of_queue_stats_reply {
+struct of_queue_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1193,7 +1235,7 @@
     list(of_queue_stats_entry_t) entries;
 };
 
-struct of_group_stats_request {
+struct of_group_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1205,7 +1247,7 @@
     pad(4);
 };
 
-struct of_group_stats_reply {
+struct of_group_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1216,7 +1258,7 @@
     list(of_group_stats_entry_t) entries;
 };
 
-struct of_group_desc_stats_request {
+struct of_group_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1226,7 +1268,7 @@
     pad(4);
 };
 
-struct of_group_desc_stats_reply {
+struct of_group_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1237,7 +1279,7 @@
     list(of_group_desc_stats_entry_t) entries;
 };
 
-struct of_group_features_stats_request {
+struct of_group_features_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1247,7 +1289,7 @@
     pad(4);
 };
 
-struct of_group_features_stats_reply {
+struct of_group_features_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1267,7 +1309,7 @@
     uint32_t actions_ff;
 };
 
-struct of_experimenter_stats_request {
+struct of_experimenter_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1280,7 +1322,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter_stats_reply {
+struct of_experimenter_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1301,7 +1343,7 @@
     pad(4);
 };
 
-struct of_queue_prop_min_rate {
+struct of_queue_prop_min_rate : of_queue_prop {
     uint16_t type == 1;
     uint16_t len;
     pad(4);
@@ -1309,7 +1351,7 @@
     pad(6);
 };
 
-struct of_queue_prop_max_rate {
+struct of_queue_prop_max_rate : of_queue_prop {
     uint16_t type == 2;
     uint16_t len;
     pad(4);
@@ -1317,7 +1359,7 @@
     pad(6);
 };
 
-struct of_queue_prop_experimenter {
+struct of_queue_prop_experimenter : of_queue_prop {
     uint16_t type == 65535;
     uint16_t len;
     pad(4);
@@ -1334,7 +1376,7 @@
     list(of_queue_prop_t) properties;
 };
 
-struct of_queue_get_config_request {
+struct of_queue_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 22;
     uint16_t length;
@@ -1343,7 +1385,7 @@
     pad(4);
 };
 
-struct of_queue_get_config_reply {
+struct of_queue_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 23;
     uint16_t length;
@@ -1353,7 +1395,7 @@
     list(of_packet_queue_t) queues;
 };
 
-struct of_role_request {
+struct of_role_request : of_header {
     uint8_t version;
     uint8_t type == 24;
     uint16_t length;
@@ -1363,7 +1405,7 @@
     uint64_t generation_id;
 };
 
-struct of_role_reply {
+struct of_role_reply : of_header {
     uint8_t version;
     uint8_t type == 25;
     uint16_t length;
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index 0d5cec3..ab32abe 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -548,6 +548,7 @@
     OFPHET_VERSIONBITMAP = 1,
 };
 
+/* XXX rename to of_message */
 struct of_header {
     uint8_t version;
     uint8_t type;
@@ -570,13 +571,13 @@
     uint16_t length;
 };
 
-struct of_hello_elem_versionbitmap {
+struct of_hello_elem_versionbitmap : of_hello_elem {
     uint16_t type == 1;
     uint16_t length;
     list(of_uint32_t) bitmaps;
 };
 
-struct of_hello {
+struct of_hello : of_header {
     uint8_t version;
     uint8_t type == 0;
     uint16_t length;
@@ -584,7 +585,7 @@
     list(of_hello_elem_t) elements;
 };
 
-struct of_echo_request {
+struct of_echo_request : of_header {
     uint8_t version;
     uint8_t type == 2;
     uint16_t length;
@@ -592,7 +593,7 @@
     of_octets_t data;
 };
 
-struct of_echo_reply {
+struct of_echo_reply : of_header {
     uint8_t version;
     uint8_t type == 3;
     uint16_t length;
@@ -600,7 +601,7 @@
     of_octets_t data;
 };
 
-struct of_experimenter {
+struct of_experimenter : of_header {
     uint8_t version;
     uint8_t type == 4;
     uint16_t length;
@@ -610,28 +611,28 @@
     of_octets_t data;
 };
 
-struct of_barrier_request {
+struct of_barrier_request : of_header {
     uint8_t version;
     uint8_t type == 20;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_barrier_reply {
+struct of_barrier_reply : of_header {
     uint8_t version;
     uint8_t type == 21;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_request {
+struct of_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 7;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_get_config_reply {
+struct of_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 8;
     uint16_t length;
@@ -640,7 +641,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_set_config {
+struct of_set_config : of_header {
     uint8_t version;
     uint8_t type == 9;
     uint16_t length;
@@ -649,7 +650,7 @@
     uint16_t miss_send_len;
 };
 
-struct of_table_mod {
+struct of_table_mod : of_header {
     uint8_t version;
     uint8_t type == 17;
     uint16_t length;
@@ -675,14 +676,14 @@
     uint32_t max_speed;
 };
 
-struct of_features_request {
+struct of_features_request : of_header {
     uint8_t version;
     uint8_t type == 5;
     uint16_t length;
     uint32_t xid;
 };
 
-struct of_features_reply {
+struct of_features_reply : of_header {
     uint8_t version;
     uint8_t type == 6;
     uint16_t length;
@@ -696,7 +697,7 @@
     uint32_t reserved;
 };
 
-struct of_port_status {
+struct of_port_status : of_header {
     uint8_t version;
     uint8_t type == 12;
     uint16_t length;
@@ -706,7 +707,7 @@
     of_port_desc_t desc;
 };
 
-struct of_port_mod {
+struct of_port_mod : of_header {
     uint8_t version;
     uint8_t type == 16;
     uint16_t length;
@@ -736,7 +737,7 @@
     pad(4);
 };
 
-struct of_action_output {
+struct of_action_output : of_action {
     uint16_t type == 0;
     uint16_t len;
     of_port_no_t port;
@@ -744,103 +745,103 @@
     pad(6);
 };
 
-struct of_action_copy_ttl_out {
+struct of_action_copy_ttl_out : of_action {
     uint16_t type == 11;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_copy_ttl_in {
+struct of_action_copy_ttl_in : of_action {
     uint16_t type == 12;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_mpls_ttl {
+struct of_action_set_mpls_ttl : of_action {
     uint16_t type == 15;
     uint16_t len;
     uint8_t mpls_ttl;
     pad(3);
 };
 
-struct of_action_dec_mpls_ttl {
+struct of_action_dec_mpls_ttl : of_action {
     uint16_t type == 16;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_vlan {
+struct of_action_push_vlan : of_action {
     uint16_t type == 17;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_vlan {
+struct of_action_pop_vlan : of_action {
     uint16_t type == 18;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_mpls {
+struct of_action_push_mpls : of_action {
     uint16_t type == 19;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_pop_mpls {
+struct of_action_pop_mpls : of_action {
     uint16_t type == 20;
     uint16_t len;
     uint16_t ethertype;
     pad(2);
 };
 
-struct of_action_set_queue {
+struct of_action_set_queue : of_action {
     uint16_t type == 21;
     uint16_t len;
     uint32_t queue_id;
 };
 
-struct of_action_group {
+struct of_action_group : of_action {
     uint16_t type == 22;
     uint16_t len;
     uint32_t group_id;
 };
 
-struct of_action_set_nw_ttl {
+struct of_action_set_nw_ttl : of_action {
     uint16_t type == 23;
     uint16_t len;
     uint8_t nw_ttl;
     pad(3);
 };
 
-struct of_action_dec_nw_ttl {
+struct of_action_dec_nw_ttl : of_action {
     uint16_t type == 24;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_set_field {
+struct of_action_set_field : of_action {
     uint16_t type == 25;
     uint16_t len;
     of_oxm_t field;
 };
 
-struct of_action_experimenter {
+struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
     of_octets_t data;
 };
 
-struct of_action_pop_pbb {
+struct of_action_pop_pbb : of_action {
     uint16_t type == 27;
     uint16_t len;
     pad(4);
 };
 
-struct of_action_push_pbb {
+struct of_action_push_pbb : of_action {
     uint16_t type == 26;
     uint16_t len;
     uint16_t ethertype;
@@ -858,14 +859,14 @@
     uint16_t len;
 };
 
-struct of_instruction_goto_table {
+struct of_instruction_goto_table : of_instruction {
     uint16_t type == 1;
     uint16_t len;
     uint8_t table_id;
     pad(3);
 };
 
-struct of_instruction_write_metadata {
+struct of_instruction_write_metadata : of_instruction {
     uint16_t type == 2;
     uint16_t len;
     pad(4);
@@ -873,40 +874,61 @@
     uint64_t metadata_mask;
 };
 
-struct of_instruction_write_actions {
+struct of_instruction_write_actions : of_instruction {
     uint16_t type == 3;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_apply_actions {
+struct of_instruction_apply_actions : of_instruction {
     uint16_t type == 4;
     uint16_t len;
     pad(4);
     list(of_action_t) actions;
 };
 
-struct of_instruction_clear_actions {
+struct of_instruction_clear_actions : of_instruction {
     uint16_t type == 5;
     uint16_t len;
     pad(4);
 };
 
-struct of_instruction_meter {
+struct of_instruction_meter : of_instruction {
     uint16_t type == 6;
     uint16_t len;
     uint32_t meter_id;
 };
 
-struct of_instruction_experimenter {
+struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter;
     of_octets_t data;
 };
 
-struct of_flow_add {
+struct of_flow_mod : of_header {
+    uint8_t version;
+    uint8_t type == 14;
+    uint16_t length;
+    uint32_t xid;
+    uint64_t cookie;
+    uint64_t cookie_mask;
+    uint8_t table_id;
+    of_fm_cmd_t _command;
+    uint16_t idle_timeout;
+    uint16_t hard_timeout;
+    uint16_t priority;
+    uint32_t buffer_id;
+    of_port_no_t out_port;
+    uint32_t out_group;
+    uint16_t flags;
+    pad(2);
+    of_match_t match;
+    list(of_instruction_t) instructions;
+};
+
+struct of_flow_add : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -927,7 +949,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify {
+struct of_flow_modify : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -948,7 +970,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_modify_strict {
+struct of_flow_modify_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -969,7 +991,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete {
+struct of_flow_delete : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -990,7 +1012,7 @@
     list(of_instruction_t) instructions;
 };
 
-struct of_flow_delete_strict {
+struct of_flow_delete_strict : of_flow_mod {
     uint8_t version;
     uint8_t type == 14;
     uint16_t length;
@@ -1020,7 +1042,7 @@
     list(of_action_t) actions;
 };
 
-struct of_group_mod {
+struct of_group_mod : of_header {
     uint8_t version;
     uint8_t type == 15;
     uint16_t length;
@@ -1032,7 +1054,7 @@
     list(of_bucket_t) buckets;
 };
 
-struct of_packet_out {
+struct of_packet_out : of_header {
     uint8_t version;
     uint8_t type == 13;
     uint16_t length;
@@ -1045,7 +1067,7 @@
     of_octets_t data;
 };
 
-struct of_packet_in {
+struct of_packet_in : of_header {
     uint8_t version;
     uint8_t type == 10;
     uint16_t length;
@@ -1060,7 +1082,7 @@
     of_octets_t data; /* FIXME: Ensure total_len gets updated */
 };
 
-struct of_flow_removed {
+struct of_flow_removed : of_header {
     uint8_t version;
     uint8_t type == 11;
     uint16_t length;
@@ -1085,7 +1107,7 @@
 //    uint32_t        burst_size;  // These are excluded b/c this is the header
 };
 
-struct of_meter_band_drop {
+struct of_meter_band_drop : of_meter_band {
     uint16_t        type == 1;
     uint16_t        len;
     uint32_t        rate;
@@ -1093,7 +1115,7 @@
     pad(4);
 };
 
-struct of_meter_band_dscp_remark {
+struct of_meter_band_dscp_remark : of_meter_band {
     uint16_t        type == 2;
     uint16_t        len;
     uint32_t        rate;
@@ -1102,7 +1124,7 @@
     pad(3);
 };
 
-struct of_meter_band_experimenter {
+struct of_meter_band_experimenter : of_meter_band {
     uint16_t        type == 65535;
     uint16_t        len;
     uint32_t        rate;
@@ -1110,7 +1132,7 @@
     uint32_t        experimenter;
 };
 
-struct of_meter_mod {
+struct of_meter_mod : of_header {
     uint8_t version;
     uint8_t type == 29;
     uint16_t length;
@@ -1121,7 +1143,7 @@
     list(of_meter_band_t) meters;
 };
 
-struct of_error_msg {
+struct of_error_msg : of_header {
     uint8_t version;
     uint8_t type == 1;
     uint16_t length;
@@ -1228,7 +1250,27 @@
 // STATS: 
 //  Desc, flow, agg, table, port, queue, group, group_desc, group_feat, experi
 
-struct of_desc_stats_request {
+struct of_stats_request : of_header {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_stats_reply : of_header {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type;
+    uint16_t flags;
+    pad(4);
+};
+
+struct of_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1238,7 +1280,7 @@
     pad(4);
 };
 
-struct of_desc_stats_reply {
+struct of_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1253,7 +1295,7 @@
     of_desc_str_t dp_desc;
 };
 
-struct of_flow_stats_request {
+struct of_flow_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1271,7 +1313,7 @@
     of_match_t match;
 };
 
-struct of_flow_stats_reply {
+struct of_flow_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1282,7 +1324,7 @@
     list(of_flow_stats_entry_t) entries;
 };
 
-struct of_aggregate_stats_request {
+struct of_aggregate_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1300,7 +1342,7 @@
     of_match_t match;
 };
 
-struct of_aggregate_stats_reply {
+struct of_aggregate_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1314,7 +1356,7 @@
     pad(4);
 };
 
-struct of_table_stats_request {
+struct of_table_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1324,7 +1366,7 @@
     pad(4);
 };
 
-struct of_table_stats_reply {
+struct of_table_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1342,92 +1384,92 @@
     uint16_t         length;
 };
 
-struct of_table_feature_prop_instructions {
+struct of_table_feature_prop_instructions : of_table_feature_prop {
     uint16_t         type == 0;
     uint16_t         length;
     // FIXME Check if instruction_t is right for ids here
     list(of_instruction_t)   instruction_ids;
 };
 
-struct of_table_feature_prop_instructions_miss {
+struct of_table_feature_prop_instructions_miss : of_table_feature_prop {
     uint16_t         type == 1;
     uint16_t         length;
     list(of_instruction_t)   instruction_ids;
 };
 
-struct of_table_feature_prop_next_tables {
+struct of_table_feature_prop_next_tables : of_table_feature_prop {
     uint16_t         type == 2;
     uint16_t         length;
     list(of_uint8_t) next_table_ids;
 };
 
-struct of_table_feature_prop_next_tables_miss {
+struct of_table_feature_prop_next_tables_miss : of_table_feature_prop {
     uint16_t         type == 3;
     uint16_t         length;
     list(of_uint8_t) next_table_ids;
 };
 
-struct of_table_feature_prop_write_actions {
+struct of_table_feature_prop_write_actions : of_table_feature_prop {
     uint16_t         type == 4;
     uint16_t         length;
     list(of_action_id_t) action_ids;
 };
 
-struct of_table_feature_prop_write_actions_miss {
+struct of_table_feature_prop_write_actions_miss : of_table_feature_prop {
     uint16_t         type == 5;
     uint16_t         length;
     list(of_action_id_t) action_ids;
 };
 
-struct of_table_feature_prop_apply_actions {
+struct of_table_feature_prop_apply_actions : of_table_feature_prop {
     uint16_t         type == 6;
     uint16_t         length;
     list(of_action_id_t) action_ids;
 };
 
-struct of_table_feature_prop_apply_actions_miss {
+struct of_table_feature_prop_apply_actions_miss : of_table_feature_prop {
     uint16_t         type == 7;
     uint16_t         length;
     list(of_action_id_t) action_ids;
 };
 
-struct of_table_feature_prop_match {
+struct of_table_feature_prop_match : of_table_feature_prop {
     uint16_t         type == 8;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_wildcards {
+struct of_table_feature_prop_wildcards : of_table_feature_prop {
     uint16_t         type == 10;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_write_setfield {
+struct of_table_feature_prop_write_setfield : of_table_feature_prop {
     uint16_t         type == 12;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_write_setfield_miss {
+struct of_table_feature_prop_write_setfield_miss : of_table_feature_prop {
     uint16_t         type == 13;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_apply_setfield {
+struct of_table_feature_prop_apply_setfield : of_table_feature_prop {
     uint16_t         type == 14;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_apply_setfield_miss {
+struct of_table_feature_prop_apply_setfield_miss : of_table_feature_prop {
     uint16_t         type == 15;
     uint16_t         length;
     list(of_uint32_t) oxm_ids;
 };
 
-struct of_table_feature_prop_experimenter {
+struct of_table_feature_prop_experimenter : of_table_feature_prop {
     uint16_t         type == 65535;
     uint16_t         length;
     uint32_t         experimenter;
@@ -1436,7 +1478,7 @@
 };
 
 // Not yet supported
-// struct of_table_feature_prop_experimenter_miss {
+// struct of_table_feature_prop_experimenter_miss : of_table_feature_prop {
 //     uint16_t         type;
 //     uint16_t         length;
 //     uint32_t         experimenter;
@@ -1465,7 +1507,7 @@
     pad(2);
 };
 
-struct of_port_stats_request {
+struct of_port_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1477,7 +1519,7 @@
     pad(4);
 };
 
-struct of_port_stats_reply {
+struct of_port_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1488,7 +1530,7 @@
     list(of_port_stats_entry_t) entries;
 };
 
-struct of_queue_stats_request {
+struct of_queue_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1500,7 +1542,7 @@
     uint32_t queue_id;
 };
 
-struct of_queue_stats_reply {
+struct of_queue_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1511,7 +1553,7 @@
     list(of_queue_stats_entry_t) entries;
 };
 
-struct of_group_stats_request {
+struct of_group_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1523,7 +1565,7 @@
     pad(4);
 };
 
-struct of_group_stats_reply {
+struct of_group_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1534,7 +1576,7 @@
     list(of_group_stats_entry_t) entries;
 };
 
-struct of_group_desc_stats_request {
+struct of_group_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1544,7 +1586,7 @@
     pad(4);
 };
 
-struct of_group_desc_stats_reply {
+struct of_group_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1555,7 +1597,7 @@
     list(of_group_desc_stats_entry_t) entries;
 };
 
-struct of_group_features_stats_request {
+struct of_group_features_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1565,7 +1607,7 @@
     pad(4);
 };
 
-struct of_group_features_stats_reply {
+struct of_group_features_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1585,7 +1627,7 @@
     uint32_t actions_ff;
 };
 
-struct of_meter_stats_request {
+struct of_meter_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1597,7 +1639,7 @@
     pad(4);
 };
 
-struct of_meter_stats_reply {
+struct of_meter_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1608,7 +1650,7 @@
     list(of_meter_stats_t) entries;
 };
 
-struct of_meter_config_stats_request {
+struct of_meter_config_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1620,7 +1662,7 @@
     pad(4);
 };
 
-struct of_meter_config_stats_reply {
+struct of_meter_config_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1632,7 +1674,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_meter_features_stats_request {
+struct of_meter_features_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1643,7 +1685,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_meter_features_stats_reply {
+struct of_meter_features_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1655,7 +1697,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_table_features_stats_request {
+struct of_table_features_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1667,7 +1709,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_table_features_stats_reply {
+struct of_table_features_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1679,7 +1721,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_port_desc_stats_request {
+struct of_port_desc_stats_request : of_stats_request {
     uint8_t version;
     uint8_t type == 18;
     uint16_t length;
@@ -1690,7 +1732,7 @@
 };
 
 // FIXME stats added to get things working
-struct of_port_desc_stats_reply {
+struct of_port_desc_stats_reply : of_stats_reply {
     uint8_t version;
     uint8_t type == 19;
     uint16_t length;
@@ -1738,7 +1780,7 @@
     pad(4);
 };
 
-struct of_queue_prop_min_rate {
+struct of_queue_prop_min_rate : of_queue_prop {
     uint16_t type == 1;
     uint16_t len;
     pad(4);
@@ -1746,7 +1788,7 @@
     pad(6);
 };
 
-struct of_queue_prop_max_rate {
+struct of_queue_prop_max_rate : of_queue_prop {
     uint16_t type == 2;
     uint16_t len;
     pad(4);
@@ -1754,7 +1796,7 @@
     pad(6);
 };
 
-struct of_queue_prop_experimenter {
+struct of_queue_prop_experimenter : of_queue_prop {
     uint16_t type == 65535;
     uint16_t len;
     pad(4);
@@ -1771,7 +1813,7 @@
     list(of_queue_prop_t) properties;
 };
 
-struct of_queue_get_config_request {
+struct of_queue_get_config_request : of_header {
     uint8_t version;
     uint8_t type == 22;
     uint16_t length;
@@ -1780,7 +1822,7 @@
     pad(4);
 };
 
-struct of_queue_get_config_reply {
+struct of_queue_get_config_reply : of_header {
     uint8_t version;
     uint8_t type == 23;
     uint16_t length;
@@ -1790,7 +1832,7 @@
     list(of_packet_queue_t) queues;
 };
 
-struct of_role_request {
+struct of_role_request : of_header {
     uint8_t version;
     uint8_t type == 24;
     uint16_t length;
@@ -1800,7 +1842,7 @@
     uint64_t generation_id;
 };
 
-struct of_role_reply {
+struct of_role_reply : of_header {
     uint8_t version;
     uint8_t type == 25;
     uint16_t length;
@@ -1815,7 +1857,7 @@
 //   while uint32_t[1] is interest for slave
 ////////////////////////////////////////////////////////////////
 
-struct of_async_get_request {
+struct of_async_get_request : of_header {
     uint8_t version;
     uint8_t type == 26;
     uint16_t length;
@@ -1828,7 +1870,7 @@
     uint32_t flow_removed_mask_slave;
 };
 
-struct of_async_get_reply {
+struct of_async_get_reply : of_header {
     uint8_t version;
     uint8_t type == 27;
     uint16_t length;
@@ -1841,7 +1883,7 @@
     uint32_t flow_removed_mask_slave;
 };
 
-struct of_async_set {
+struct of_async_set : of_header {
     uint8_t version;
     uint8_t type == 28;
     uint16_t length;
diff --git a/test_data/of10/action_bsn_set_tunnel_dst.data b/test_data/of10/action_bsn_set_tunnel_dst.data
index 7e1f43d..7a5747c 100644
--- a/test_data/of10/action_bsn_set_tunnel_dst.data
+++ b/test_data/of10/action_bsn_set_tunnel_dst.data
@@ -8,3 +8,6 @@
 ofp.action.bsn_set_tunnel_dst(dst=0x12345678)
 -- python pretty-printer
 bsn_set_tunnel_dst { dst = 0x12345678 }
+-- c
+obj = of_action_bsn_set_tunnel_dst_new(OF_VERSION_1_0);
+of_action_bsn_set_tunnel_dst_dst_set(obj, 0x12345678);
diff --git a/test_data/of10/desc_stats_reply.data b/test_data/of10/desc_stats_reply.data
index b4b3eb1..c000bb0 100644
--- a/test_data/of10/desc_stats_reply.data
+++ b/test_data/of10/desc_stats_reply.data
@@ -145,3 +145,27 @@
     sw_desc="Indigo-2 LRI pre-release",
     serial_num="11235813213455",
     dp_desc="Indigo-2 LRI forwarding module")
+-- c
+obj = of_desc_stats_reply_new(OF_VERSION_1_0);
+of_desc_stats_reply_xid_set(obj, 3);
+of_desc_stats_reply_flags_set(obj, OF_STATS_REPLY_FLAG_REPLY_MORE);
+{
+    of_desc_str_t mfr_desc = "The Indigo-2 Community";
+    of_desc_stats_reply_mfr_desc_set(obj, mfr_desc);
+}
+{
+    of_desc_str_t hw_desc = "Unknown server";
+    of_desc_stats_reply_hw_desc_set(obj, hw_desc);
+}
+{
+    of_desc_str_t sw_desc = "Indigo-2 LRI pre-release";
+    of_desc_stats_reply_sw_desc_set(obj, sw_desc);
+}
+{
+    of_desc_str_t dp_desc = "Indigo-2 LRI forwarding module";
+    of_desc_stats_reply_dp_desc_set(obj, dp_desc);
+}
+{
+    of_serial_num_t serial_num = "11235813213455";
+    of_desc_stats_reply_serial_num_set(obj, serial_num);
+}
diff --git a/test_data/of10/echo_request.data b/test_data/of10/echo_request.data
index abe06fc..701376e 100644
--- a/test_data/of10/echo_request.data
+++ b/test_data/of10/echo_request.data
@@ -7,3 +7,10 @@
 ofp.message.echo_request(xid=0x12345678, data="ab\x01")
 -- python pretty-printer
 echo_request { xid = 0x12345678, data = 'ab\x01' }
+-- c
+obj = of_echo_request_new(OF_VERSION_1_0);
+of_echo_request_xid_set(obj, 0x12345678);
+{
+    of_octets_t data = { .data=(uint8_t *)"ab\x01", .bytes=3 };
+    of_echo_request_data_set(obj, &data);
+}
diff --git a/test_data/of10/flow_add.data b/test_data/of10/flow_add.data
index 9801a36..fc09a23 100644
--- a/test_data/of10/flow_add.data
+++ b/test_data/of10/flow_add.data
@@ -1,6 +1,6 @@
 -- binary
 01 0e 00 70 12 34 56 78
-00 00 00 0c 00 03 01 23
+00 10 00 02 00 03 01 23
 45 67 89 ab cd ef 01 23
 45 67 00 00 00 00 00 00
 00 00 00 00 c0 a8 03 7f
@@ -17,7 +17,7 @@
 ofp.message.flow_add(
     xid=0x12345678,
     match=ofp.match(
-        wildcards=ofp.OFPFW_DL_SRC|ofp.OFPFW_DL_DST,
+        wildcards=ofp.OFPFW_DL_VLAN|ofp.OFPFW_DL_VLAN_PCP,
         in_port=3,
         ipv4_src=0xc0a8037f,
         ipv4_dst=0xffffffff,
@@ -33,7 +33,7 @@
 flow_add {
   xid = 0x12345678,
   match = match_v1 {
-    wildcards = OFPFW_DL_SRC|OFPFW_DL_DST,
+    wildcards = OFPFW_DL_VLAN|OFPFW_DL_VLAN_PCP,
     in_port = 3,
     eth_src = 01:23:45:67:89:ab,
     eth_dst = cd:ef:01:23:45:67,
@@ -60,3 +60,49 @@
     bsn_set_tunnel_dst { dst = 0x0 }
   ]
 }
+-- c
+obj = of_flow_add_new(OF_VERSION_1_0);
+of_flow_add_xid_set(obj, 0x12345678);
+of_flow_add_idle_timeout_set(obj, 5);
+of_flow_add_flags_set(obj, 2);
+{
+    of_match_t match = { OF_VERSION_1_0 };
+    match.fields.in_port = 3;
+    match.fields.eth_src = (of_mac_addr_t) { { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } };
+    match.fields.eth_dst = (of_mac_addr_t) { { 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 } };
+    match.fields.ipv4_src = 0xc0a8037f;
+    match.fields.ipv4_dst = 0xffffffff;
+    OF_MATCH_MASK_IN_PORT_EXACT_SET(&match);
+    OF_MATCH_MASK_ETH_SRC_EXACT_SET(&match);
+    OF_MATCH_MASK_ETH_DST_EXACT_SET(&match);
+    //OF_MATCH_MASK_VLAN_VID_EXACT_SET(&match);
+    //OF_MATCH_MASK_VLAN_PCP_EXACT_SET(&match);
+    OF_MATCH_MASK_ETH_TYPE_EXACT_SET(&match);
+    OF_MATCH_MASK_IP_DSCP_EXACT_SET(&match);
+    OF_MATCH_MASK_IP_PROTO_EXACT_SET(&match);
+    OF_MATCH_MASK_IPV4_SRC_EXACT_SET(&match);
+    OF_MATCH_MASK_IPV4_DST_EXACT_SET(&match);
+    OF_MATCH_MASK_TCP_SRC_EXACT_SET(&match);
+    OF_MATCH_MASK_TCP_DST_EXACT_SET(&match);
+    of_flow_add_match_set(obj, &match);
+}
+{
+    of_list_action_t actions;
+    of_flow_add_actions_bind(obj, &actions);
+    {
+        of_action_t action;
+        of_action_output_init(&action.output, OF_VERSION_1_0, -1, 1);
+        of_list_action_append_bind(&actions, &action);
+        of_action_output_port_set(&action.output, OF_PORT_DEST_FLOOD);
+    }
+    {
+        of_action_t action;
+        of_action_nicira_dec_ttl_init(&action.nicira_dec_ttl, OF_VERSION_1_0, -1, 1);
+        of_list_action_append_bind(&actions, &action);
+    }
+    {
+        of_action_t action;
+        of_action_bsn_set_tunnel_dst_init(&action.bsn_set_tunnel_dst, OF_VERSION_1_0, -1, 1);
+        of_list_action_append_bind(&actions, &action);
+    }
+}
diff --git a/test_data/of10/flow_stats_entry.data b/test_data/of10/flow_stats_entry.data
index 45c6569..2f9df64 100644
--- a/test_data/of10/flow_stats_entry.data
+++ b/test_data/of10/flow_stats_entry.data
@@ -40,3 +40,36 @@
     actions=[
         ofp.action.output(port=1),
         ofp.action.output(port=2)])
+-- c
+obj = of_flow_stats_entry_new(OF_VERSION_1_0);
+{
+    of_object_t list;
+    of_flow_stats_entry_actions_bind(obj, &list);
+    {
+        of_object_t *obj = of_action_output_new(OF_VERSION_1_0);
+        of_action_output_max_len_set(obj, 0);
+        of_action_output_port_set(obj, 1);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+    {
+        of_object_t *obj = of_action_output_new(OF_VERSION_1_0);
+        of_action_output_max_len_set(obj, 0);
+        of_action_output_port_set(obj, 2);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+}
+of_flow_stats_entry_byte_count_set(obj, 1000);
+of_flow_stats_entry_cookie_set(obj, 81985529216486895);
+of_flow_stats_entry_duration_nsec_set(obj, 2);
+of_flow_stats_entry_duration_sec_set(obj, 1);
+of_flow_stats_entry_hard_timeout_set(obj, 10);
+of_flow_stats_entry_idle_timeout_set(obj, 5);
+{
+    of_match_t match = { OF_VERSION_1_0 };
+    of_flow_stats_entry_match_set(obj, &match);
+}
+of_flow_stats_entry_packet_count_set(obj, 10);
+of_flow_stats_entry_priority_set(obj, 100);
+of_flow_stats_entry_table_id_set(obj, 3);
diff --git a/test_data/of10/flow_stats_reply.data b/test_data/of10/flow_stats_reply.data
index 38db4d5..185235b 100644
--- a/test_data/of10/flow_stats_reply.data
+++ b/test_data/of10/flow_stats_reply.data
@@ -90,3 +90,93 @@
             actions=[ofp.action.output(port=1),
             ofp.action.output(port=2),
             ofp.action.output(port=3)])])
+-- c
+obj = of_flow_stats_reply_new(OF_VERSION_1_0);
+of_flow_stats_reply_flags_set(obj, 0);
+of_flow_stats_reply_xid_set(obj, 6);
+{
+    of_object_t *entries = of_list_flow_stats_entry_new(OF_VERSION_1_0);
+    {
+        of_object_t *elem = of_flow_stats_entry_new(OF_VERSION_1_0);
+        of_flow_stats_entry_byte_count_set(elem, 1000);
+        of_flow_stats_entry_cookie_set(elem, 81985529216486895);
+        of_flow_stats_entry_duration_nsec_set(elem, 2);
+        of_flow_stats_entry_duration_sec_set(elem, 1);
+        of_flow_stats_entry_hard_timeout_set(elem, 10);
+        of_flow_stats_entry_idle_timeout_set(elem, 5);
+        of_flow_stats_entry_packet_count_set(elem, 10);
+        of_flow_stats_entry_priority_set(elem, 100);
+        of_flow_stats_entry_table_id_set(elem, 3);
+        {
+            of_match_t match = { OF_VERSION_1_0 };
+            of_flow_stats_entry_match_set(elem, &match);
+        }
+        {
+            of_object_t *actions = of_list_action_new(OF_VERSION_1_0);
+            {
+                of_object_t *elem = of_action_output_new(OF_VERSION_1_0);
+                of_action_output_max_len_set(elem, 0);
+                of_action_output_port_set(elem, 1);
+                of_list_append(actions, elem);
+                of_object_delete(elem);
+            }
+            {
+                of_object_t *elem = of_action_output_new(OF_VERSION_1_0);
+                of_action_output_max_len_set(elem, 0);
+                of_action_output_port_set(elem, 2);
+                of_list_append(actions, elem);
+                of_object_delete(elem);
+            }
+            of_flow_stats_entry_actions_set(elem, actions);
+            of_object_delete(actions);
+        }
+        of_list_append(entries, elem);
+        of_object_delete(elem);
+    }
+    {
+        of_object_t *elem = of_flow_stats_entry_new(OF_VERSION_1_0);
+        of_flow_stats_entry_byte_count_set(elem, 1000);
+        of_flow_stats_entry_cookie_set(elem, 81985529216486895);
+        of_flow_stats_entry_duration_nsec_set(elem, 2);
+        of_flow_stats_entry_duration_sec_set(elem, 1);
+        of_flow_stats_entry_hard_timeout_set(elem, 10);
+        of_flow_stats_entry_idle_timeout_set(elem, 5);
+        of_flow_stats_entry_packet_count_set(elem, 10);
+        of_flow_stats_entry_priority_set(elem, 100);
+        of_flow_stats_entry_table_id_set(elem, 4);
+        {
+            of_match_t match = { OF_VERSION_1_0 };
+            of_flow_stats_entry_match_set(elem, &match);
+        }
+        {
+            of_object_t *actions = of_list_action_new(OF_VERSION_1_0);
+            {
+                of_object_t *elem = of_action_output_new(OF_VERSION_1_0);
+                of_action_output_max_len_set(elem, 0);
+                of_action_output_port_set(elem, 1);
+                of_list_append(actions, elem);
+                of_object_delete(elem);
+            }
+            {
+                of_object_t *elem = of_action_output_new(OF_VERSION_1_0);
+                of_action_output_max_len_set(elem, 0);
+                of_action_output_port_set(elem, 2);
+                of_list_append(actions, elem);
+                of_object_delete(elem);
+            }
+            {
+                of_object_t *elem = of_action_output_new(OF_VERSION_1_0);
+                of_action_output_max_len_set(elem, 0);
+                of_action_output_port_set(elem, 3);
+                of_list_append(actions, elem);
+                of_object_delete(elem);
+            }
+            of_flow_stats_entry_actions_set(elem, actions);
+            of_object_delete(actions);
+        }
+        of_list_append(entries, elem);
+        of_object_delete(elem);
+    }
+    of_flow_stats_reply_entries_set(obj, entries);
+    of_object_delete(entries);
+}
diff --git a/test_data/of10/hello.data b/test_data/of10/hello.data
index 2603365..3dc2b44 100644
--- a/test_data/of10/hello.data
+++ b/test_data/of10/hello.data
@@ -4,3 +4,6 @@
 12 34 56 78 # xid
 -- python
 ofp.message.hello(xid=0x12345678)
+-- c
+obj = of_hello_new(OF_VERSION_1_0);
+of_hello_xid_set(obj, 305419896);
diff --git a/test_data/of10/packet_in.data b/test_data/of10/packet_in.data
index f8d026b..8168e3b 100644
--- a/test_data/of10/packet_in.data
+++ b/test_data/of10/packet_in.data
@@ -16,3 +16,14 @@
     in_port=ofp.OFPP_LOCAL,
     reason=ofp.OFPR_ACTION,
     data='abc')
+-- c
+obj = of_packet_in_new(OF_VERSION_1_0);
+of_packet_in_buffer_id_set(obj, 2882400001);
+{
+    of_octets_t data = { .bytes=3, .data=(uint8_t *)"\x61\x62\x63" };
+    of_packet_in_data_set(obj, &data);
+}
+of_packet_in_in_port_set(obj, 65534);
+of_packet_in_reason_set(obj, 1);
+of_packet_in_total_len_set(obj, 9);
+of_packet_in_xid_set(obj, 305419896);
diff --git a/test_data/of10/packet_out.data b/test_data/of10/packet_out.data
index a3892f6..fdd1c3d 100644
--- a/test_data/of10/packet_out.data
+++ b/test_data/of10/packet_out.data
@@ -23,3 +23,31 @@
         ofp.action.output(port=1),
         ofp.action.output(port=2)],
     data='abc')
+-- c
+obj = of_packet_out_new(OF_VERSION_1_0);
+of_packet_out_buffer_id_set(obj, 2882400001);
+of_packet_out_in_port_set(obj, 65534);
+of_packet_out_xid_set(obj, 305419896);
+{
+    of_object_t *list = of_list_action_new(OF_VERSION_1_0);
+    {
+        of_object_t *obj = of_action_output_new(OF_VERSION_1_0);
+        of_action_output_max_len_set(obj, 0);
+        of_action_output_port_set(obj, 1);
+        of_list_append(list, obj);
+        of_object_delete(obj);
+    }
+    {
+        of_object_t *obj = of_action_output_new(OF_VERSION_1_0);
+        of_action_output_max_len_set(obj, 0);
+        of_action_output_port_set(obj, 2);
+        of_list_append(list, obj);
+        of_object_delete(obj);
+    }
+    of_packet_out_actions_set(obj, list);
+    of_object_delete(list);
+}
+{
+    of_octets_t data = { .bytes=3, .data=(uint8_t *)"\x61\x62\x63" };
+    of_packet_out_data_set(obj, &data);
+}
diff --git a/test_data/of10/port_desc.data b/test_data/of10/port_desc.data
index c3c2e38..56242cc 100644
--- a/test_data/of10/port_desc.data
+++ b/test_data/of10/port_desc.data
@@ -19,3 +19,20 @@
     advertised=ofp.OFPPF_1GB_FD,
     supported=ofp.OFPPF_AUTONEG,
     peer=ofp.OFPPF_PAUSE_ASYM)
+-- c
+obj = of_port_desc_new(OF_VERSION_1_0);
+of_port_desc_advertised_set(obj, 32);
+of_port_desc_config_set(obj, 16);
+of_port_desc_curr_set(obj, 1);
+{
+    of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
+    of_port_desc_hw_addr_set(obj, hw_addr);
+}
+{
+    of_port_name_t name = "foo";
+    of_port_desc_name_set(obj, name);
+}
+of_port_desc_peer_set(obj, 2048);
+of_port_desc_port_no_set(obj, 65533);
+of_port_desc_state_set(obj, 512);
+of_port_desc_supported_set(obj, 512);
diff --git a/test_data/of10/port_mod.data b/test_data/of10/port_mod.data
index 972a4e8..53e09ce 100644
--- a/test_data/of10/port_mod.data
+++ b/test_data/of10/port_mod.data
@@ -16,3 +16,14 @@
     config=0x90ABCDEF,
     mask=0xFF11FF11,
     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_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_port_no_set(obj, 65533);
+of_port_mod_xid_set(obj, 2);
diff --git a/test_data/of10/port_stats_reply.data b/test_data/of10/port_stats_reply.data
index 45a3532..4378387 100644
--- a/test_data/of10/port_stats_reply.data
+++ b/test_data/of10/port_stats_reply.data
@@ -37,3 +37,47 @@
     xid=5, flags=0, entries=[
         ofp.port_stats_entry(port_no=1, rx_packets=56, collisions=5),
         ofp.port_stats_entry(port_no=ofp.OFPP_LOCAL, rx_packets=1, collisions=1)])
+-- c
+obj = of_port_stats_reply_new(OF_VERSION_1_0);
+{
+    of_object_t list;
+    of_port_stats_reply_entries_bind(obj, &list);
+    {
+        of_object_t *obj = of_port_stats_entry_new(OF_VERSION_1_0);
+        of_port_stats_entry_collisions_set(obj, 5);
+        of_port_stats_entry_port_no_set(obj, 1);
+        of_port_stats_entry_rx_bytes_set(obj, 0);
+        of_port_stats_entry_rx_crc_err_set(obj, 0);
+        of_port_stats_entry_rx_dropped_set(obj, 0);
+        of_port_stats_entry_rx_errors_set(obj, 0);
+        of_port_stats_entry_rx_frame_err_set(obj, 0);
+        of_port_stats_entry_rx_over_err_set(obj, 0);
+        of_port_stats_entry_rx_packets_set(obj, 56);
+        of_port_stats_entry_tx_bytes_set(obj, 0);
+        of_port_stats_entry_tx_dropped_set(obj, 0);
+        of_port_stats_entry_tx_errors_set(obj, 0);
+        of_port_stats_entry_tx_packets_set(obj, 0);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+    {
+        of_object_t *obj = of_port_stats_entry_new(OF_VERSION_1_0);
+        of_port_stats_entry_collisions_set(obj, 1);
+        of_port_stats_entry_port_no_set(obj, 65534);
+        of_port_stats_entry_rx_bytes_set(obj, 0);
+        of_port_stats_entry_rx_crc_err_set(obj, 0);
+        of_port_stats_entry_rx_dropped_set(obj, 0);
+        of_port_stats_entry_rx_errors_set(obj, 0);
+        of_port_stats_entry_rx_frame_err_set(obj, 0);
+        of_port_stats_entry_rx_over_err_set(obj, 0);
+        of_port_stats_entry_rx_packets_set(obj, 1);
+        of_port_stats_entry_tx_bytes_set(obj, 0);
+        of_port_stats_entry_tx_dropped_set(obj, 0);
+        of_port_stats_entry_tx_errors_set(obj, 0);
+        of_port_stats_entry_tx_packets_set(obj, 0);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+}
+of_port_stats_reply_flags_set(obj, 0);
+of_port_stats_reply_xid_set(obj, 5);
diff --git a/test_data/of10/port_status.data b/test_data/of10/port_status.data
index 04da9fd..7589eae 100644
--- a/test_data/of10/port_status.data
+++ b/test_data/of10/port_status.data
@@ -28,3 +28,27 @@
         advertised=ofp.OFPPF_1GB_FD,
         supported=ofp.OFPPF_AUTONEG,
         peer=ofp.OFPPF_PAUSE_ASYM))
+-- c
+obj = of_port_status_new(OF_VERSION_1_0);
+{
+    of_object_t *desc = of_port_desc_new(OF_VERSION_1_0);
+    of_port_desc_advertised_set(desc, 32);
+    of_port_desc_config_set(desc, 16);
+    of_port_desc_curr_set(desc, 1);
+    {
+	of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
+	of_port_desc_hw_addr_set(desc, hw_addr);
+    }
+    {
+	of_port_name_t name = "foo";
+	of_port_desc_name_set(desc, name);
+    }
+    of_port_desc_peer_set(desc, 2048);
+    of_port_desc_port_no_set(desc, 65533);
+    of_port_desc_state_set(desc, 512);
+    of_port_desc_supported_set(desc, 512);
+    of_port_status_desc_set(obj, desc);
+    of_object_delete(desc);
+}
+of_port_status_reason_set(obj, 1);
+of_port_status_xid_set(obj, 4);
diff --git a/test_data/of10/queue_get_config_reply.data b/test_data/of10/queue_get_config_reply.data
index 5e3453d..1016cad 100644
--- a/test_data/of10/queue_get_config_reply.data
+++ b/test_data/of10/queue_get_config_reply.data
@@ -35,3 +35,49 @@
         ofp.packet_queue(queue_id=2, properties=[
             ofp.queue_prop_min_rate(rate=6),
             ofp.queue_prop_min_rate(rate=7)])])
+-- c
+obj = of_queue_get_config_reply_new(OF_VERSION_1_0);
+of_queue_get_config_reply_port_set(obj, 65534);
+{
+    of_object_t list;
+    of_queue_get_config_reply_queues_bind(obj, &list);
+    {
+        of_object_t *obj = of_packet_queue_new(OF_VERSION_1_0);
+        {
+            of_object_t list;
+            of_packet_queue_properties_bind(obj, &list);
+            {
+                of_object_t *obj = of_queue_prop_min_rate_new(OF_VERSION_1_0);
+                of_queue_prop_min_rate_rate_set(obj, 5);
+                of_list_append(&list, obj);
+                of_object_delete(obj);
+            }
+        }
+        of_packet_queue_queue_id_set(obj, 1);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+    {
+        of_object_t *obj = of_packet_queue_new(OF_VERSION_1_0);
+        {
+            of_object_t list;
+            of_packet_queue_properties_bind(obj, &list);
+            {
+                of_object_t *obj = of_queue_prop_min_rate_new(OF_VERSION_1_0);
+                of_queue_prop_min_rate_rate_set(obj, 6);
+                of_list_append(&list, obj);
+                of_object_delete(obj);
+            }
+            {
+                of_object_t *obj = of_queue_prop_min_rate_new(OF_VERSION_1_0);
+                of_queue_prop_min_rate_rate_set(obj, 7);
+                of_list_append(&list, obj);
+                of_object_delete(obj);
+            }
+        }
+        of_packet_queue_queue_id_set(obj, 2);
+        of_list_append(&list, obj);
+        of_object_delete(obj);
+    }
+}
+of_queue_get_config_reply_xid_set(obj, 305419896);
diff --git a/test_data/of10/table_stats_entry.data b/test_data/of10/table_stats_entry.data
index 1a99237..017e8ba 100644
--- a/test_data/of10/table_stats_entry.data
+++ b/test_data/of10/table_stats_entry.data
@@ -19,3 +19,15 @@
     active_count=2,
     lookup_count=1099511627775,
     matched_count=9300233470495232273L)
+-- c
+obj = of_table_stats_entry_new(OF_VERSION_1_0);
+of_table_stats_entry_active_count_set(obj, 2);
+of_table_stats_entry_lookup_count_set(obj, 1099511627775ULL);
+of_table_stats_entry_matched_count_set(obj, 9300233470495232273ULL);
+of_table_stats_entry_max_entries_set(obj, 5);
+{
+    of_table_name_t name = "foo";
+    of_table_stats_entry_name_set(obj, name);
+}
+of_table_stats_entry_table_id_set(obj, 3);
+of_table_stats_entry_wildcards_set(obj, 4194303);
diff --git a/utest/test_frontend.py b/utest/test_frontend.py
index 01b8270..609a262 100755
--- a/utest/test_frontend.py
+++ b/utest/test_frontend.py
@@ -90,7 +90,7 @@
                 ['OFPPC_NO_FWD', 32],
                 ['OFPPC_NO_PACKET_IN', 64]]],
             ['metadata', 'version', '2'],
-            ['struct', 'of_echo_reply', [
+            ['struct', 'of_echo_reply', None, [
                 ['data', 'uint8_t', 'version'],
                 ['type', 'uint8_t', 'type', 3],
                 ['data', 'uint16_t', 'length'],
@@ -100,7 +100,7 @@
                 ['OFPQOFC_BAD_PORT', 0],
                 ['OFPQOFC_BAD_QUEUE', 1],
                 ['OFPQOFC_EPERM', 2]]],
-            ['struct', 'of_packet_queue', [
+            ['struct', 'of_packet_queue', None, [
                 ['data', 'uint32_t', 'queue_id'],
                 ['data', 'uint16_t', 'len'],
                 ['pad', 2],
@@ -111,13 +111,13 @@
         ofinput = frontend.create_ofinput(ast)
         self.assertEquals(set([1, 2]), ofinput.wire_versions)
         expected_classes = [
-            OFClass('of_echo_reply', [
+            OFClass('of_echo_reply', None, [
                 OFDataMember('version', 'uint8_t'), # XXX
                 OFTypeMember('type', 'uint8_t', 3),
                 OFLengthMember('length', 'uint16_t'),
                 OFDataMember('xid', 'uint32_t'),
                 OFDataMember('data', 'of_octets_t')]),
-            OFClass('of_packet_queue', [
+            OFClass('of_packet_queue', None, [
                 OFDataMember('queue_id', 'uint32_t'),
                 OFLengthMember('len', 'uint16_t'),
                 OFPadMember(2),
@@ -140,5 +140,57 @@
         ]
         self.assertEquals(expected_enums, ofinput.enums)
 
+    def test_inheritance(self):
+        ast = parser.parse("""
+#version 1
+
+struct of_queue_prop {
+    uint16_t type;
+    uint16_t len;
+    pad(4);
+};
+
+struct of_queue_prop_min_rate : of_queue_prop {
+    uint16_t type == 1;
+    uint16_t len;
+    pad(4);
+    uint16_t rate;
+    pad(6);
+};
+""")
+
+        # Not testing the parser, just making sure the AST is what we expect
+        expected_ast = [
+            ['metadata', 'version', '1'],
+
+            ['struct', 'of_queue_prop', None, [
+                ['data', 'uint16_t', 'type'],
+                ['data', 'uint16_t', 'len'],
+                ['pad', 4]]],
+
+            ['struct', 'of_queue_prop_min_rate', 'of_queue_prop', [
+                ['type', 'uint16_t', 'type', 1],
+                ['data', 'uint16_t', 'len'],
+                ['pad', 4],
+                ['data', 'uint16_t', 'rate'],
+                ['pad', 6]]],
+        ]
+        self.assertEquals(expected_ast, ast)
+
+        ofinput = frontend.create_ofinput(ast)
+        expected_classes = [
+            OFClass('of_queue_prop', None, [
+                OFDataMember('type', 'uint16_t'),
+                OFLengthMember('len', 'uint16_t'),
+                OFPadMember(4)]),
+            OFClass('of_queue_prop_min_rate', 'of_queue_prop', [
+                OFTypeMember('type', 'uint16_t', 1),
+                OFLengthMember('len', 'uint16_t'),
+                OFPadMember(4),
+                OFDataMember('rate', 'uint16_t'),
+                OFPadMember(6)]),
+        ]
+        self.assertEquals(expected_classes, ofinput.classes)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/utest/test_parser.py b/utest/test_parser.py
index 40d2913..c24665c 100755
--- a/utest/test_parser.py
+++ b/utest/test_parser.py
@@ -42,7 +42,7 @@
 struct foo { };
 """
         ast = parser.parse(src)
-        self.assertEquals(ast, [['struct', 'foo', []]])
+        self.assertEquals(ast, [['struct', 'foo', None, []]])
 
     def test_one_field(self):
         src = """\
@@ -52,7 +52,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['data', 'uint32_t', 'bar']]]])
+            [['struct', 'foo', None, [['data', 'uint32_t', 'bar']]]])
 
     def test_multiple_fields(self):
         src = """\
@@ -64,7 +64,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo',
+            [['struct', 'foo', None,
                 [['data', 'uint32_t', 'bar'],
                  ['data', 'uint8_t', 'baz'],
                  ['data', 'uint64_t', 'abc']]]])
@@ -77,7 +77,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['data', 'uint32_t[4]', 'bar']]]])
+            [['struct', 'foo', None, [['data', 'uint32_t[4]', 'bar']]]])
 
     def test_list_type(self):
         src = """\
@@ -87,7 +87,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['data', 'list(of_action_t)', 'bar']]]])
+            [['struct', 'foo', None, [['data', 'list(of_action_t)', 'bar']]]])
 
     def test_pad_member(self):
         src = """\
@@ -97,7 +97,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['pad', 1]]]])
+            [['struct', 'foo', None, [['pad', 1]]]])
 
     def test_type_member(self):
         src = """\
@@ -107,7 +107,17 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['type', 'uint16_t', 'foo', 0x10]]]])
+            [['struct', 'foo', None, [['type', 'uint16_t', 'foo', 0x10]]]])
+
+    def test_inheritance(self):
+        src = """\
+struct foo : bar {
+    uint16_t foo == 0x10;
+};
+"""
+        ast = parser.parse(src)
+        self.assertEquals(ast,
+            [['struct', 'foo', 'bar', [['type', 'uint16_t', 'foo', 0x10]]]])
 
 class EnumTests(unittest.TestCase):
     def test_empty(self):
@@ -165,7 +175,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', []], ['struct', 'bar', []]])
+            [['struct', 'foo', None, []], ['struct', 'bar', None, []]])
 
     def test_comments(self):
         src = """\
@@ -179,7 +189,7 @@
 """
         ast = parser.parse(src)
         self.assertEquals(ast,
-            [['struct', 'foo', [['data', 'uint32_t', 'a']]]])
+            [['struct', 'foo', None, [['data', 'uint32_t', 'a']]]])
 
     def test_mixed(self):
         src = """\
@@ -191,9 +201,9 @@
         ast = parser.parse(src)
         self.assertEquals(ast,
             [['metadata', 'version', '1'],
-             ['struct', 'foo', []],
+             ['struct', 'foo', None, []],
              ['metadata', 'version', '2'],
-             ['struct', 'bar', []]])
+             ['struct', 'bar', None, []]])
 
 class TestErrors(unittest.TestCase):
     def syntax_error(self, src, regex):