Merge into master from pull request #125:
BSN extension LACP stats request (https://github.com/floodlight/loxigen/pull/125)
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index d237cfe..e1b6913 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -128,6 +128,11 @@
             m_name == "experimenter" or
             m_name == "subtype")):
         return True
+
+    if (cls in ["of_bsn_lacp_stats_request", "of_bsn_lacp_stats_reply"] and (
+            m_name == "experimenter" or
+            m_name == "subtype")):
+        return True
     return loxi_utils.skip_member_name(m_name) or m_type not in scalar_types
 
 def gen_fill_string(out):
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 8883193..4fc1652 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -503,6 +503,7 @@
     uint16_t stats_type;
     uint16_t err_type;
     uint8_t flow_mod_cmd;
+    uint32_t experimenter, subtype;
 
     if (length < OF_MESSAGE_MIN_LENGTH) {
         return OF_OBJECT_INVALID;
@@ -541,10 +542,23 @@
             return OF_OBJECT_INVALID;
         }
         stats_type = of_message_stats_type_get(msg);
-        if (obj_id == OF_STATS_REQUEST) {
-            obj_id = of_stats_request_to_object_id(stats_type, ver);
+        if (stats_type == OF_STATS_TYPE_EXPERIMENTER) {
+            if (length < OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH) {
+                return OF_OBJECT_INVALID;
+            }
+            experimenter = of_message_stats_experimenter_id_get(msg);
+            subtype = of_message_stats_experimenter_subtype_get(msg);
+            if (obj_id == OF_STATS_REQUEST) {
+                obj_id = of_experimenter_stats_request_to_object_id(experimenter, subtype, ver);
+            } else {
+                obj_id = of_experimenter_stats_reply_to_object_id(experimenter, subtype, ver);
+            }
         } else {
-            obj_id = of_stats_reply_to_object_id(stats_type, ver);
+            if (obj_id == OF_STATS_REQUEST) {
+                obj_id = of_stats_request_to_object_id(stats_type, ver);
+            } else {
+                obj_id = of_stats_reply_to_object_id(stats_type, ver);
+            }
         }
     }
 
@@ -945,6 +959,9 @@
  * top level message: Action, instruction, error, stats, queue_props, oxm
  */
 #define OF_EXPERIMENTER_TYPE 0xffff
+
+int of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
+int of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver);
 """)
     gen_type_to_obj_map_functions(out)
     gen_obj_to_type_map_functions(out)
@@ -1047,6 +1064,17 @@
     if ((type = of_object_to_stats_type(id, ver)) >= 0) {
         /* It's a stats obj */
         of_message_stats_type_set(msg, type);
+        if (type == OF_STATS_TYPE_EXPERIMENTER) {
+            switch (id) {
+            case OF_BSN_LACP_STATS_REQUEST:
+            case OF_BSN_LACP_STATS_REPLY:
+                of_message_stats_experimenter_id_set(msg, OF_EXPERIMENTER_ID_BSN);
+                of_message_stats_experimenter_subtype_set(msg, 1);
+                break;
+            default:
+                break;
+            }
+        }
     }
     if ((type = of_object_to_error_type(id, ver)) >= 0) {
         /* It's an error obj */
diff --git a/c_gen/templates/of_message.h b/c_gen/templates/of_message.h
index 165fe51..c1b6785 100644
--- a/c_gen/templates/of_message.h
+++ b/c_gen/templates/of_message.h
@@ -58,6 +58,10 @@
 #define OF_MESSAGE_EXPERIMENTER_SUBTYPE_OFFSET 12
 #define OF_MESSAGE_EXPERIMENTER_MIN_LENGTH 16
 
+#define OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET 16
+#define OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET 20
+#define OF_MESSAGE_STATS_EXPERIMENTER_MIN_LENGTH 24
+
 /**
  * The "default" free message function; NULL means use nominal malloc/free
  */
@@ -270,4 +274,42 @@
     }
 }
 
+/**
+ * @brief Get/set stats request/reply experimenter ID of a message
+ * @param msg Pointer to the message buffer of sufficient length
+ * @param experimenter_id Data for set operation
+ * @returns get returns experimenter id in host order
+ */
+
+static inline uint32_t
+of_message_stats_experimenter_id_get(of_message_t msg) {
+    uint32_t val;
+    buf_u32_get(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, &val);
+    return val;
+}
+
+static inline void
+of_message_stats_experimenter_id_set(of_message_t msg, uint32_t experimenter_id) {
+    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_ID_OFFSET, experimenter_id);
+}
+
+/**
+ * @brief Get/set stats request/reply experimenter subtype of a message
+ * @param msg Pointer to the message buffer of sufficient length
+ * @param subtype Data for set operation
+ * @returns get returns experimenter subtype in host order
+ */
+
+static inline uint32_t
+of_message_stats_experimenter_subtype_get(of_message_t msg) {
+    uint32_t val;
+    buf_u32_get(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, &val);
+    return val;
+}
+
+static inline void
+of_message_stats_experimenter_subtype_set(of_message_t msg, uint32_t subtype) {
+    buf_u32_set(msg + OF_MESSAGE_STATS_EXPERIMENTER_SUBTYPE_OFFSET, subtype);
+}
+
 #endif /* _OF_MESSAGE_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index fabd25f..30c73ac 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -840,3 +840,27 @@
 
     return OF_ERROR_NONE;
 }
+
+int
+of_experimenter_stats_request_to_object_id(uint32_t experimenter, uint32_t subtype, int ver)
+{
+    switch (experimenter) {
+    case OF_EXPERIMENTER_ID_BSN:
+        switch (subtype) {
+        case 1: return OF_BSN_LACP_STATS_REQUEST;
+        }
+    }
+    return OF_OBJECT_INVALID;
+}
+
+int
+of_experimenter_stats_reply_to_object_id(uint32_t experimenter, uint32_t subtype, int ver)
+{
+    switch (experimenter) {
+    case OF_EXPERIMENTER_ID_BSN:
+        switch (subtype) {
+        case 1: return OF_BSN_LACP_STATS_REPLY;
+        }
+    }
+    return OF_OBJECT_INVALID;
+}
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 83c89b5..a463d69 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -60,7 +60,11 @@
     interface_blacklist = set( ("OFUint8", "OFUint32",))
     # registry of interface properties that should not be generated
     # map: $java_type -> set(java_name_property)
-    read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
+    read_blacklist = defaultdict(lambda: set(),
+        OFExperimenter=set(('data','subtype')),
+        OFActionExperimenter=set(('data',)),
+        OFExperimenterStatsRequest=set(('data','subtype')),
+        OFExperimenterStatsReply=set(('data','subtype')))
     # map: $java_type -> set(java_name_property)
     write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
     # interfaces that are virtual
@@ -510,6 +514,14 @@
         # inheritance information from the versioned lox_ir classes.
         if re.match(r'OFStatsRequest$', self.name):
             return ("", "OFMessage", "T extends OFStatsReply")
+        elif re.match(r'OFBsnStatsRequest$', self.name):
+            return ("", "OFExperimenterStatsRequest", None)
+        elif re.match(r'OFBsnStatsReply$', self.name):
+            return ("", "OFExperimenterStatsReply", None)
+        elif re.match(r'OFBsn.+StatsRequest$', self.name):
+            return ("", "OFBsnStatsRequest", None)
+        elif re.match(r'OFBsn.+StatsReply$', self.name):
+            return ("", "OFBsnStatsReply", None)
         elif re.match(r'OF.+StatsRequest$', self.name):
             return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
         elif re.match(r'OF.+StatsReply$', self.name):
diff --git a/loxi_front_end/frontend.py b/loxi_front_end/frontend.py
index f4dece5..35c1e44 100644
--- a/loxi_front_end/frontend.py
+++ b/loxi_front_end/frontend.py
@@ -62,7 +62,7 @@
     else:
         raise InputError("Dont know how to create member: %s" % m_ast[0])
 
-def create_ofinput(ast):
+def create_ofinput(name, ast):
 
     """
     Create an OFInput from an AST
@@ -72,7 +72,7 @@
     @returns An OFInput object
     """
     ctx = FrontendCtx(set())
-    ofinput = OFInput(wire_versions=set(), classes=[], enums=[])
+    ofinput = OFInput(name, wire_versions=set(), classes=[], enums=[])
 
     for decl_ast in ast:
         if decl_ast[0] == 'struct':
@@ -115,8 +115,4 @@
     if not ofinput.wire_versions:
         raise InputError("Missing #version metadata")
 
-    for used_enum in ctx.used_enums:
-        if not find(lambda e: e.name == used_enum, ofinput.enums):
-            raise Exception("Undeclared enum used in OFInput: {}".format(used_enum))
-
     return ofinput
diff --git a/loxi_front_end/type_maps.py b/loxi_front_end/type_maps.py
index a3394b2..2f02e93 100644
--- a/loxi_front_end/type_maps.py
+++ b/loxi_front_end/type_maps.py
@@ -155,7 +155,7 @@
     if loxi_utils.class_is_list(cls):
         return True
     # TODO get this from the input file when we have virtual class syntax
-    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira"]:
+    if cls in ["of_flow_mod", "of_stats_request", "of_stats_reply", "of_error_msg", "of_bsn_header", "of_nicira_header", "of_action_bsn", "of_action_nicira", "of_action_id_bsn", "of_action_id_nicira", "of_bsn_stats_request", "of_bsn_stats_reply", "of_experimenter_stats_request", "of_experimenter_stats_reply"]:
         return True
     return False
 
@@ -266,7 +266,8 @@
         meter_features = 11,
         table_features = 12,
         port_desc = 13,
-        experimenter = 0xffff
+        experimenter = 0xffff,
+        bsn_lacp = 0xffff
         )
     }
 
@@ -451,7 +452,9 @@
     "of_port_desc_stats_reply",
     "of_queue_stats_reply",
     "of_table_stats_reply",
-    "of_table_features_stats_reply"
+    "of_table_features_stats_reply",
+    "of_bsn_stats_reply",
+    "of_bsn_lacp_stats_reply",
 ]
 
 stats_request_list = [
@@ -469,7 +472,9 @@
     "of_port_desc_stats_request",
     "of_queue_stats_request",
     "of_table_stats_request",
-    "of_table_features_stats_request"
+    "of_table_features_stats_request",
+    "of_bsn_stats_request",
+    "of_bsn_lacp_stats_request",
 ]
 
 flow_mod_list = [
diff --git a/loxi_ir.py b/loxi_ir.py
index a70f041..0fe5497 100644
--- a/loxi_ir.py
+++ b/loxi_ir.py
@@ -47,11 +47,12 @@
 """
 One input file
 
+@param name Name of the input file
 @param wire_versions Set of integer wire versions this file applies to
 @param classes List of OFClass objects in the same order as in the file
 @param enums List of Enum objects in the same order as in the file
 """
-OFInput = namedtuple('OFInput', ['wire_versions', 'classes', 'enums'])
+OFInput = namedtuple('OFInput', ['name', 'wire_versions', 'classes', 'enums'])
 
 """
 One version of the OpenFlow protocol
diff --git a/loxigen.py b/loxigen.py
index 7b78f63..43ff2a8 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -332,7 +332,7 @@
 
     # Create the OFInput from the AST
     try:
-        ofinput = frontend.create_ofinput(ast)
+        ofinput = frontend.create_ofinput(os.path.basename(filename), ast)
     except frontend.InputError as e:
         print "Error in %s: %s" % (os.path.basename(filename), str(e))
         sys.exit(1)
@@ -417,13 +417,35 @@
     # Ignore emacs backup files
     filenames = [x for x in filenames if not x.endswith('~')]
 
+    # Read input files
+    all_ofinputs = []
     for filename in filenames:
         log("Processing struct file: " + filename)
         ofinput = process_input_file(filename)
-
-        # Populate global state
+        all_ofinputs.append(ofinput)
         for wire_version in ofinput.wire_versions:
             ofinputs_by_version[wire_version].append(ofinput)
+
+    # Merge input files into per-version IR
+    for wire_version, ofinputs in ofinputs_by_version.items():
+        ofprotocol = OFProtocol(wire_version=wire_version, classes=[], enums=[])
+        for ofinput in ofinputs:
+            ofprotocol.classes.extend(ofinput.classes)
+            ofprotocol.enums.extend(ofinput.enums)
+        ofprotocol.classes.sort(key=lambda ofclass: ofclass.name)
+        of_g.ir[wire_version] = ofprotocol
+
+    # Extract enums
+    # An input file can refer to an enum in another file
+    enums_by_version = { ver: {} for ver in ofinputs_by_version }
+    for ofinput in all_ofinputs:
+        for wire_version in ofinput.wire_versions:
+            for enum in ofinput.enums:
+                enums_by_version[wire_version][enum.name] = enum
+
+    # Populate legacy maps
+    for ofinput in all_ofinputs:
+        for wire_version in ofinput.wire_versions:
             version_name = of_g.of_version_wire2name[wire_version]
 
             for ofclass in ofinput.classes:
@@ -442,7 +464,7 @@
                         if m.oftype == 'of_oxm_t':
                             m_type = 'of_octets_t'
                         else:
-                            enum = find(lambda e: e.name == m.oftype, ofinput.enums)
+                            enum = enums_by_version[wire_version].get(m.oftype)
                             if enum and "wire_type" in enum.params:
                                 m_type = enum.params["wire_type"]
                             else:
@@ -457,14 +479,6 @@
                         entry.name, enum.name, entry.value, wire_version,
                         of_g.identifiers, of_g.identifiers_by_group)
 
-        for wire_version, ofinputs in ofinputs_by_version.items():
-            ofprotocol = OFProtocol(wire_version=wire_version, classes=[], enums=[])
-            for ofinput in ofinputs:
-                ofprotocol.classes.extend(ofinput.classes)
-                ofprotocol.enums.extend(ofinput.enums)
-            ofprotocol.classes.sort(key=lambda ofclass: ofclass.name)
-            of_g.ir[wire_version] = ofprotocol
-
 def populate_type_maps():
     """
     Use the type members in the IR to fill out the legacy type_maps.
@@ -535,7 +549,7 @@
 
             # Extensions
             experimenter = find_experimenter('of', cls)
-            if experimenter:
+            if experimenter and ofclass.superclass in ['of_bsn_header', 'of_nicira_header']:
                 val = find_type_value(ofclass, 'subtype')
                 type_maps.extension_message_subtype[wire_version][experimenter][cls] = val
 
diff --git a/openflow_input/bsn b/openflow_input/bsn
index 0aa674b..dfbf981 100644
--- a/openflow_input/bsn
+++ b/openflow_input/bsn
@@ -46,3 +46,26 @@
     pad(4);
 };
 
+struct of_bsn_stats_request : of_experimenter_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == ?;
+};
+
+struct of_bsn_stats_reply : of_experimenter_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == ?;
+};
diff --git a/openflow_input/bsn_lacp b/openflow_input/bsn_lacp
index 8237641..d2e540a 100644
--- a/openflow_input/bsn_lacp
+++ b/openflow_input/bsn_lacp
@@ -88,3 +88,45 @@
     uint16_t partner_port_num;
     uint16_t partner_key;
 };
+
+struct of_bsn_lacp_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 1;
+};
+
+struct of_bsn_lacp_stats_entry {
+    of_port_no_t port_no;
+    uint16_t actor_sys_priority;
+    of_mac_addr_t actor_sys_mac;
+    uint16_t actor_port_priority;
+    uint16_t actor_port_num;
+    uint16_t actor_key;
+    uint8_t convergence_status;
+    pad(1);
+    uint16_t partner_sys_priority;
+    of_mac_addr_t partner_sys_mac;
+    uint16_t partner_port_priority;
+    uint16_t partner_port_num;
+    uint16_t partner_key;
+    pad(2);
+};
+
+struct of_bsn_lacp_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 1;
+    list(of_bsn_lacp_stats_entry_t) entries;
+};
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index db7ff0d..b4c4bee 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -1527,6 +1527,30 @@
     list(of_table_stats_entry_t) entries;
 };
 
+struct of_experimenter_stats_request : of_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == ?;
+    uint32_t subtype;
+};
+
+struct of_experimenter_stats_reply : of_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == ?;
+    uint32_t subtype;
+};
+
 // FIXME: These are padded to 8 byte align beyond the length indicated
 
 struct of_table_feature_prop {
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index c378cea..b8f7de1 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -204,6 +204,7 @@
     'list(of_table_stats_entry_t)': 'common.table_stats_entry.unpack',
     'list(of_uint32_t)': 'common.uint32.unpack',
     'list(of_uint8_t)': 'common.uint8.unpack',
+    'list(of_bsn_lacp_stats_entry_t)': 'common.bsn_lacp_stats_entry.unpack',
 }
 
 for (cls, element_deserializer) in fixed_elem_len_lists.items():
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index c8e31c9..e4c2c7b 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -164,6 +164,30 @@
     else:
         raise loxi.ProtocolError("unexpected stats type %u" % stats_type)
 
+def parse_experimenter_stats_request(buf):
+    if len(buf) < 24:
+        raise loxi.ProtocolError("experimenter stats request message too short")
+
+    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
+
+    if experimenter in experimenter_stats_request_parsers and \
+            exp_type in experimenter_stats_request_parsers[experimenter]:
+        return experimenter_stats_request_parsers[experimenter][exp_type](buf)
+    else:
+        raise loxi.ProtocolError("unexpected stats request experimenter %#x exp_type %#x" % (experimenter, exp_type))
+
+def parse_experimenter_stats_reply(buf):
+    if len(buf) < 24:
+        raise loxi.ProtocolError("experimenter stats reply message too short")
+
+    experimenter, exp_type = struct.unpack_from("!LL", buf, 16)
+
+    if experimenter in experimenter_stats_reply_parsers and \
+            exp_type in experimenter_stats_reply_parsers[experimenter]:
+        return experimenter_stats_reply_parsers[experimenter][exp_type](buf)
+    else:
+        raise loxi.ProtocolError("unexpected stats reply experimenter %#x exp_type %#x" % (experimenter, exp_type))
+
 def parse_experimenter(buf):
     if len(buf) < 16:
         raise loxi.ProtocolError("experimenter message too short")
@@ -234,6 +258,7 @@
     const.OFPST_TABLE : table_stats_reply.unpack,
     const.OFPST_PORT : port_stats_reply.unpack,
     const.OFPST_QUEUE : queue_stats_reply.unpack,
+    const.OFPST_EXPERIMENTER : parse_experimenter_stats_reply,
 :: if version >= of_g.VERSION_1_1:
     const.OFPST_GROUP : group_stats_reply.unpack,
     const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
@@ -257,6 +282,7 @@
     const.OFPST_TABLE : table_stats_request.unpack,
     const.OFPST_PORT : port_stats_request.unpack,
     const.OFPST_QUEUE : queue_stats_request.unpack,
+    const.OFPST_EXPERIMENTER : parse_experimenter_stats_request,
 :: if version >= of_g.VERSION_1_1:
     const.OFPST_GROUP : group_stats_request.unpack,
     const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,
@@ -286,3 +312,19 @@
     },
 :: #endfor
 }
+
+experimenter_stats_request_parsers = {
+    0x005c16c7: {
+:: if version >= of_g.VERSION_1_3:
+        1: bsn_lacp_stats_request.unpack,
+:: #endif
+    },
+}
+
+experimenter_stats_reply_parsers = {
+    0x005c16c7: {
+:: if version >= of_g.VERSION_1_3:
+        1: bsn_lacp_stats_reply.unpack,
+:: #endif
+    },
+}
diff --git a/utest/test_frontend.py b/utest/test_frontend.py
index 8febfde..19cde4e 100755
--- a/utest/test_frontend.py
+++ b/utest/test_frontend.py
@@ -109,7 +109,7 @@
         ]
         self.assertEquals(expected_ast, ast)
 
-        ofinput = frontend.create_ofinput(ast)
+        ofinput = frontend.create_ofinput("test", ast)
         self.assertEquals(set([1, 2]), ofinput.wire_versions)
         expected_classes = [
             OFClass(name='of_echo_reply', superclass=None, members=[
@@ -180,7 +180,7 @@
         ]
         self.assertEquals(expected_ast, ast)
 
-        ofinput = frontend.create_ofinput(ast)
+        ofinput = frontend.create_ofinput("test", ast)
         expected_classes = [
             OFClass(name='of_queue_prop', superclass=None, members=[
                 OFDiscriminatorMember('type', 'uint16_t'),