Merge remote-tracking branch 'origin/master' into pyloxi-ir

Conflicts:
	py_gen/oftype.py
diff --git a/openflow_input/bsn_l2_table b/openflow_input/bsn_l2_table
index e3938a8..8075d7f 100644
--- a/openflow_input/bsn_l2_table
+++ b/openflow_input/bsn_l2_table
@@ -36,9 +36,9 @@
     uint32_t experimenter == 0x5c16c7;
     uint32_t subtype == 12;
     uint8_t l2_table_enable;    // 1 == enabled, 0 == disabled
-    uint8_t pad;
+    pad(1);
     uint16_t l2_table_priority;  // priority of all flows in L2 table
-    uint8_t[4] pad;
+    pad(4);
 };
 
 struct of_bsn_set_l2_table_reply {
@@ -49,7 +49,7 @@
     uint32_t experimenter == 0x5c16c7;
     uint32_t subtype == 24;
     uint8_t l2_table_enable;    // Resulting state: 1 == enabled, 0 == disabled
-    uint8_t pad;
+    pad(1);
     uint16_t l2_table_priority;  // priority used, must match request if ok
     uint32_t status; // 0 means success
 };
@@ -71,7 +71,7 @@
     uint32_t experimenter == 0x5c16c7;
     uint32_t subtype == 14;
     uint8_t l2_table_enable;    // 1 == enabled, 0 == disabled
-    uint8_t pad;
+    pad(1);
     uint16_t l2_table_priority;  // priority of all flows in L2 table
-    uint8_t[4] pad;
+    pad(4);
 };
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index d6d8b32..fb2e48c 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -32,135 +32,77 @@
 import loxi_utils.loxi_utils as utils
 import util
 import oftype
+from loxi_ir import *
 
-OFClass = namedtuple('OFClass', ['name', 'pyname', 'members', 'type_members',
-                                 'min_length', 'is_fixed_length'])
-Member = namedtuple('Member', ['name', 'oftype'])
-LengthMember = namedtuple('LengthMember', ['name', 'oftype'])
-FieldLengthMember = namedtuple('FieldLengthMember', ['name', 'oftype', 'field_name'])
-TypeMember = namedtuple('TypeMember', ['name', 'oftype', 'value'])
-PadMember = namedtuple('PadMember', ['length'])
+PyOFClass = namedtuple('PyOFClass', ['name', 'pyname', 'members', 'type_members',
+                                     'min_length', 'is_fixed_length'])
 
-# XXX move to frontend
-field_length_members = {
-    ('of_packet_out', 1, 'actions_len') : 'actions',
-    ('of_packet_out', 2, 'actions_len') : 'actions',
-    ('of_packet_out', 3, 'actions_len') : 'actions',
-    ('of_packet_out', 4, 'actions_len') : 'actions',
-}
-
-def get_type_values(cls, version):
-    """
-    Returns a map from the name of the type member to its value.
-    """
-    type_values = {}
-
-    # Primary wire type
-    if utils.class_is_message(cls):
-        type_values['version'] = 'const.OFP_VERSION'
-        type_values['type'] = util.constant_for_value(version, "ofp_type", util.primary_wire_type(cls, version))
-        if cls in type_maps.flow_mod_list:
-            type_values['_command'] = util.constant_for_value(version, "ofp_flow_mod_command",
-                                                              type_maps.flow_mod_types[version][cls[8:]])
-        if cls in type_maps.stats_request_list:
-            type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
-                                                                type_maps.stats_types[version][cls[3:-14]])
-        if cls in type_maps.stats_reply_list:
-            type_values['stats_type'] = util.constant_for_value(version, "ofp_stats_types",
-                                                                type_maps.stats_types[version][cls[3:-12]])
-        if type_maps.message_is_extension(cls, version):
-            type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
-            type_values['subtype'] = type_maps.extension_message_to_subtype(cls, version)
-    elif utils.class_is_action(cls):
-        type_values['type'] = util.constant_for_value(version, "ofp_action_type", util.primary_wire_type(cls, version))
-        if type_maps.action_is_extension(cls, version):
-            type_values['experimenter'] = '%#x' % type_maps.extension_to_experimenter_id(cls)
-            type_values['subtype'] = type_maps.extension_action_to_subtype(cls, version)
-    elif utils.class_is_queue_prop(cls):
-        type_values['type'] = util.constant_for_value(version, "ofp_queue_properties", util.primary_wire_type(cls, version))
-    elif utils.class_is_hello_elem(cls):
-        type_values['type'] = util.constant_for_value(version, "ofp_hello_elem_type", util.primary_wire_type(cls, version))
+# Return the name for the generated Python class
+def generate_pyname(cls):
+    if utils.class_is_action(cls):
+        return cls[10:]
     elif utils.class_is_oxm(cls):
-        oxm_class = 0x8000
-        oxm_type = util.primary_wire_type(cls, version)
-        oxm_masked = cls.find('masked') != -1 and 1 or 0
-        oxm_len = of_g.base_length[(cls, version)] - 4
-        type_values['type_len'] = '%#x' % (oxm_class << 16 | oxm_type << 8 | \
-                                           oxm_masked << 8 | oxm_len)
-    elif cls == "of_match_v2":
-        type_values['type'] = 0
-    elif cls == "of_match_v3":
-        type_values['type'] = 1
+        return cls[7:]
     elif utils.class_is_meter_band(cls):
-        type_values['type'] = util.constant_for_value(version, "ofp_meter_band_type", util.primary_wire_type(cls, version))
+        return cls[14:]
     elif utils.class_is_instruction(cls):
-        type_values['type'] = util.constant_for_value(version, "ofp_instruction_type", util.primary_wire_type(cls, version))
+        return cls[15:]
+    else:
+        return cls[3:]
 
-    return type_values
-
-# Create intermediate representation
+# Create intermediate representation, extended from the LOXI IR
+# HACK the oftype member attribute is replaced with an OFType instance
 def build_ofclasses(version):
-    blacklist = ["of_action", "of_action_header", "of_header", "of_queue_prop",
-                 "of_queue_prop_header", "of_experimenter", "of_action_experimenter",
-                 "of_oxm", "of_oxm_header", "of_oxm_experimenter_header",
-                 "of_hello_elem", "of_hello_elem_header"]
+    blacklist = ["of_experimenter", "of_action_experimenter"]
     ofclasses = []
-    for cls in of_g.standard_class_order:
+    for ofclass in of_g.ir[version].classes:
+        cls = ofclass.name
         if type_maps.class_is_virtual(cls):
             continue
-        if version not in of_g.unified[cls] or cls in blacklist:
+        if cls in blacklist:
             continue
-        unified_class = util.lookup_unified_class(cls, version)
 
-        # Name for the generated Python class
-        if utils.class_is_action(cls):
-            pyname = cls[10:]
-        elif utils.class_is_oxm(cls):
-            pyname = cls[7:]
-        elif utils.class_is_meter_band(cls):
-            pyname = cls[14:]
-        elif utils.class_is_instruction(cls):
-            pyname = cls[15:]
-        else:
-            pyname = cls[3:]
-
-        type_values = get_type_values(cls, version)
         members = []
         type_members = []
 
-        pad_count = 0
-
-        for member in unified_class['members']:
-            if member['name'] in ['length', 'len']:
-                members.append(LengthMember(name=member['name'],
-                                            oftype=oftype.OFType(member['m_type'], version)))
-            elif (cls, version, member['name']) in field_length_members:
-                field_name = field_length_members[(cls, version, member['name'])]
-                members.append(FieldLengthMember(name=member['name'],
-                                                 oftype=oftype.OFType(member['m_type'], version),
-                                                 field_name=field_name))
-            elif member['name'] in type_values:
-                members.append(TypeMember(name=member['name'],
-                                          oftype=oftype.OFType(member['m_type'], version),
-                                          value=type_values[member['name']]))
+        for m in ofclass.members:
+            if type(m) == OFTypeMember:
+                members.append(OFTypeMember(
+                    name=m.name,
+                    oftype=oftype.OFType(m.oftype, version),
+                    value=m.value))
                 type_members.append(members[-1])
-            elif member['name'].startswith("pad"):
-                # HACK this should be moved to the frontend
-                pad_oftype = oftype.OFType(member['m_type'], version)
-                length = struct.calcsize("!" + pad_oftype._pack_fmt())
-                if pad_oftype.is_array: length *= pad_oftype.array_length
-                members.append(PadMember(length=length))
-            else:
-                members.append(Member(name=member['name'],
-                                      oftype=oftype.OFType(member['m_type'], version)))
+            elif type(m) == OFLengthMember:
+                members.append(OFLengthMember(
+                    name=m.name,
+                    oftype=oftype.OFType(m.oftype, version)))
+            elif type(m) == OFFieldLengthMember:
+                members.append(OFFieldLengthMember(
+                    name=m.name,
+                    oftype=oftype.OFType(m.oftype, version),
+                    field_name=m.field_name))
+            elif type(m) == OFPadMember:
+                members.append(m)
+            elif type(m) == OFDataMember:
+                if utils.class_is_message(ofclass.name) and m.name == 'version':
+                    # HACK move to frontend
+                    members.append(OFTypeMember(
+                        name=m.name,
+                        oftype=oftype.OFType(m.oftype, version),
+                        value=version))
+                    type_members.append(members[-1])
+                else:
+                    members.append(OFDataMember(
+                        name=m.name,
+                        oftype=oftype.OFType(m.oftype, version)))
 
         ofclasses.append(
-            OFClass(name=cls,
-                    pyname=pyname,
-                    members=members,
-                    type_members=type_members,
-                    min_length=of_g.base_length[(cls, version)],
-                    is_fixed_length=(cls, version) in of_g.is_fixed_length))
+            PyOFClass(name=cls,
+                      pyname=generate_pyname(cls),
+                      members=members,
+                      type_members=type_members,
+                      min_length=of_g.base_length[(cls, version)],
+                      is_fixed_length=(cls, version) in of_g.is_fixed_length))
     return ofclasses
 
 def generate_init(out, name, version):
@@ -187,16 +129,8 @@
     util.render_template(out, 'common.py', ofclasses=ofclasses, version=version)
 
 def generate_const(out, name, version):
-    groups = {}
-    for (group, idents) in of_g.identifiers_by_group.items():
-        items = []
-        for ident in idents:
-            info = of_g.identifiers[ident]
-            if version in info["values_by_version"]:
-                items.append((info["ofp_name"], info["values_by_version"][version]))
-        if items:
-            groups[group] = items
-    util.render_template(out, 'const.py', version=version, groups=groups)
+    util.render_template(out, 'const.py', version=version,
+                         enums=of_g.ir[version].enums)
 
 def generate_instruction(out, name, version):
     ofclasses = [x for x in build_ofclasses(version)
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index f90cff5..2a8fdd0 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -46,7 +46,7 @@
         self.is_array = self.array_length != 1
 
     def gen_init_expr(self):
-        if utils.class_is_list(self.base):
+        if self.base.startswith('list('):
             v = "[]"
         elif self.base.find("uint") == 0 or self.base in ["char", "of_port_no_t"]:
             v = "0"
@@ -91,7 +91,7 @@
             return 'struct.pack("!%s%s", *%s)' % (self.array_length, pack_fmt, expr_expr)
         elif self.base == 'of_octets_t':
             return expr_expr
-        elif utils.class_is_list(self.base):
+        elif self.base.startswith('list('):
             return '"".join([x.pack() for x in %s])' % expr_expr
         elif self.base == 'of_mac_addr_t':
             return 'struct.pack("!6B", *%s)' % expr_expr
@@ -116,7 +116,7 @@
         if pack_fmt and not self.is_array:
             return "%s.read('!%s')[0]" % (reader_expr, pack_fmt)
         elif pack_fmt and self.is_array:
-            return "list(%s.read('!%d%s'))" % (self.array_length, pack_fmt)
+            return "list(%s.read('!%d%s'))" % (reader_expr, self.array_length, pack_fmt)
         elif self.base == 'of_octets_t':
             return "str(%s.read_all())" % (reader_expr)
         elif self.base == 'of_mac_addr_t':
@@ -127,28 +127,28 @@
             return 'common.match.unpack(%s)' % (reader_expr)
         elif self.base == 'of_port_desc_t':
             return 'common.port_desc.unpack(%s)' % (reader_expr)
-        elif self.base == 'of_list_action_t':
+        elif self.base == 'list(of_action_t)':
             return 'action.unpack_list(%s)' % (reader_expr)
-        elif self.base == 'of_list_flow_stats_entry_t':
+        elif self.base == 'list(of_flow_stats_entry_t)':
             return 'common.unpack_list_flow_stats_entry(%s)' % (reader_expr)
-        elif self.base == 'of_list_queue_prop_t':
+        elif self.base == 'list(of_queue_prop_t)':
             return 'common.unpack_list_queue_prop(%s)' % (reader_expr)
-        elif self.base == 'of_list_packet_queue_t':
+        elif self.base == 'list(of_packet_queue_t)':
             return 'common.unpack_list_packet_queue(%s)' % (reader_expr)
-        elif self.base == 'of_list_hello_elem_t':
+        elif self.base == 'list(of_hello_elem_t)':
             return 'common.unpack_list_hello_elem(%s)' % (reader_expr)
-        elif self.base == 'of_list_oxm_t':
+        elif self.base == 'list(of_oxm_t)':
             # HACK need the match_v3 length field
             return 'oxm.unpack_list(%s.slice(_length-4))' % (reader_expr)
-        elif self.base == 'of_list_bucket_t':
+        elif self.base == 'list(of_bucket_t)':
             return 'common.unpack_list_bucket(%s)' % (reader_expr)
-        elif self.base == 'of_list_group_desc_stats_entry_t':
+        elif self.base == 'list(of_group_desc_stats_entry_t)':
             return 'common.unpack_list_group_desc_stats_entry(%s)' % (reader_expr)
-        elif self.base == 'of_list_group_stats_entry_t':
+        elif self.base == 'list(of_group_stats_entry_t)':
             return 'common.unpack_list_group_stats_entry(%s)' % (reader_expr)
-        elif self.base == 'of_list_meter_band_t':
+        elif self.base == 'list(of_meter_band_t)':
             return 'meter_band.unpack_list(%s)' % (reader_expr)
-        elif self.base == 'of_list_meter_stats_t':
+        elif self.base == 'list(of_meter_stats_t)':
             return 'common.unpack_list_meter_stats(%s)' % (reader_expr)
         elif self.base == 'of_port_name_t':
             return self._gen_string_unpack_expr(reader_expr, 16)
@@ -160,13 +160,13 @@
             return 'common.meter_features.unpack(%s)' % (reader_expr)
         elif self.base == 'of_bsn_vport_q_in_q_t':
             return 'common.bsn_vport_q_in_q.unpack(%s)' % (reader_expr)
-        elif self.base == 'of_list_instruction_t':
+        elif self.base == 'list(of_instruction_t)':
             return 'instruction.unpack_list(%s)' % (reader_expr)
-        elif utils.class_is_list(self.base):
-            element_cls = utils.list_to_entry_type(self.base)[:-2]
+        elif self.base.startswith('list('):
+            element_cls = self.base[5:-3]
             if ((element_cls, self.version) in of_g.is_fixed_length) \
                and not element_cls in loxi_front_end.type_maps.inheritance_map:
-                klass_name = self.base[8:-2]
+                klass_name = self.base[8:-3]
                 element_size, = of_g.base_length[(element_cls, self.version)],
                 return 'loxi.generic_util.unpack_list(%s, common.%s.unpack)' % (reader_expr, klass_name)
             else:
@@ -208,7 +208,7 @@
 class TestOFType(unittest.TestCase):
     def test_init(self):
         from oftype import OFType
-        self.assertEquals("None", OFType("of_list_action_t", 1).gen_init_expr())
+        self.assertEquals("None", OFType("list(of_action_t)", 1).gen_init_expr())
         self.assertEquals("[0,0,0]", OFType("uint32_t[3]", 1).gen_init_expr())
 
     def test_pack(self):
diff --git a/py_gen/templates/_ofclass.py b/py_gen/templates/_ofclass.py
index 8c21bb3..4c5358e 100644
--- a/py_gen/templates/_ofclass.py
+++ b/py_gen/templates/_ofclass.py
@@ -1,5 +1,5 @@
-:: from py_gen.codegen import Member, LengthMember, TypeMember
-:: normal_members = [m for m in ofclass.members if type(m) == Member]
+:: from loxi_ir import *
+:: normal_members = [m for m in ofclass.members if type(m) == OFDataMember]
 class ${ofclass.pyname}(${superclass}):
 :: for m in ofclass.type_members:
     ${m.name} = ${m.value}
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
index 0c208f7..9a481b2 100644
--- a/py_gen/templates/_pack.py
+++ b/py_gen/templates/_pack.py
@@ -26,22 +26,22 @@
 :: # under the EPL.
 ::
 :: # TODO coalesce format strings
-:: from py_gen.codegen import Member, LengthMember, FieldLengthMember, TypeMember, PadMember
+:: from loxi_ir import *
 :: length_member = None
 :: length_member_index = None
 :: field_length_members = {}
 :: field_length_indexes = {}
 :: index = 0
 :: for m in ofclass.members:
-::     if type(m) == LengthMember:
+::     if type(m) == OFLengthMember:
 ::         length_member = m
 ::         length_member_index = index
         packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${index}
-::     elif type(m) == FieldLengthMember:
+::     elif type(m) == OFFieldLengthMember:
 ::         field_length_members[m.field_name] = m
 ::         field_length_indexes[m.field_name] = index
         packed.append(${m.oftype.gen_pack_expr('0')}) # placeholder for ${m.name} at index ${index}
-::     elif type(m) == PadMember:
+::     elif type(m) == OFPadMember:
         packed.append('\x00' * ${m.length})
 ::     else:
         packed.append(${m.oftype.gen_pack_expr('self.' + m.name)})
diff --git a/py_gen/templates/_pretty_print.py b/py_gen/templates/_pretty_print.py
index 86cb237..0a3a61c 100644
--- a/py_gen/templates/_pretty_print.py
+++ b/py_gen/templates/_pretty_print.py
@@ -29,8 +29,8 @@
         with q.group():
             with q.indent(2):
                 q.breakable()
-:: from py_gen.codegen import Member, LengthMember, TypeMember
-:: normal_members = [m for m in ofclass.members if type(m) == Member]
+:: from loxi_ir import *
+:: normal_members = [m for m in ofclass.members if type(m) == OFDataMember]
 :: first = True
 :: for m in normal_members:
 :: if not first:
diff --git a/py_gen/templates/_unpack.py b/py_gen/templates/_unpack.py
index 7f3ce2a..211043e 100644
--- a/py_gen/templates/_unpack.py
+++ b/py_gen/templates/_unpack.py
@@ -26,24 +26,24 @@
 :: # under the EPL.
 ::
 :: # TODO coalesce format strings
-:: from py_gen.codegen import Member, LengthMember, FieldLengthMember, TypeMember, PadMember
+:: from loxi_ir import *
         if type(buf) == loxi.generic_util.OFReader:
             reader = buf
         else:
             reader = loxi.generic_util.OFReader(buf)
 :: field_length_members = {}
 :: for m in ofclass.members:
-::     if type(m) == PadMember:
+::     if type(m) == OFPadMember:
         reader.skip(${m.length})
-::     elif type(m) == LengthMember:
+::     elif type(m) == OFLengthMember:
         _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
-::     elif type(m) == FieldLengthMember:
+::     elif type(m) == OFFieldLengthMember:
 ::         field_length_members[m.field_name] = m
         _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
-::     elif type(m) == TypeMember:
+::     elif type(m) == OFTypeMember:
         _${m.name} = ${m.oftype.gen_unpack_expr('reader')}
         assert(_${m.name} == ${m.value})
-::     elif type(m) == Member:
+::     elif type(m) == OFDataMember:
 ::         if m.name in field_length_members:
 ::             reader_expr = 'reader.slice(_%s)' % field_length_members[m.name].name
 ::         else:
diff --git a/py_gen/templates/action.py b/py_gen/templates/action.py
index d8f7c80..dccb46e 100644
--- a/py_gen/templates/action.py
+++ b/py_gen/templates/action.py
@@ -27,6 +27,7 @@
 ::
 :: import itertools
 :: import of_g
+:: import py_gen.util as util
 :: include('_copyright.py')
 
 :: include('_autogen.py')
@@ -76,6 +77,7 @@
 :: sort_key = lambda x: x.type_members[0].value
 :: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
 :: for (k, v) in msgtype_groups:
+:: k = util.constant_for_value(version, "ofp_action_type", k)
 :: v = list(v)
 :: if len(v) == 1:
     ${k} : ${v[0].pyname}.unpack,
@@ -85,7 +87,7 @@
 :: #endfor
 }
 
-:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[0].value == 'const.OFPAT_VENDOR']
+:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[0].value == 0xffff]
 :: sort_key = lambda x: x.type_members[1].value
 :: experimenter_ofclasses.sort(key=sort_key)
 :: grouped = itertools.groupby(experimenter_ofclasses, sort_key)
diff --git a/py_gen/templates/const.py b/py_gen/templates/const.py
index ef09585..4567d56 100644
--- a/py_gen/templates/const.py
+++ b/py_gen/templates/const.py
@@ -36,10 +36,9 @@
 
 OFP_VERSION = ${version}
 
-:: for (group, idents) in sorted(groups.items()):
-::    idents.sort(key=lambda (ident, value): value)
-# Identifiers from group ${group}
-::    for (ident, value) in idents:
+:: for enum in sorted(enums, key=lambda enum: enum.name):
+# Identifiers from group ${enum.name}
+::    for (ident, value) in enum.values:
 ::        if version == 1 and ident.startswith('OFPP_'):
 ::        # HACK loxi converts these to 32-bit
 ${ident} = ${"%#x" % (value & 0xffff)}
@@ -48,9 +47,9 @@
 ::        #endif
 ::    #endfor
 
-::    if group not in blacklisted_map_groups:
-${group}_map = {
-::        for (ident, value) in idents:
+::    if enum.name not in blacklisted_map_groups:
+${enum.name}_map = {
+::        for (ident, value) in enum.values:
 ::            if ident in blacklisted_map_idents:
 ::                pass
 ::            elif version == 1 and ident.startswith('OFPP_'):
diff --git a/py_gen/templates/instruction.py b/py_gen/templates/instruction.py
index bfa0628..88b0f89 100644
--- a/py_gen/templates/instruction.py
+++ b/py_gen/templates/instruction.py
@@ -27,6 +27,7 @@
 ::
 :: import itertools
 :: import of_g
+:: import py_gen.util as util
 :: include('_copyright.py')
 
 :: include('_autogen.py')
@@ -58,6 +59,7 @@
 :: sort_key = lambda x: x.type_members[0].value
 :: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
 :: for (k, v) in msgtype_groups:
+:: k = util.constant_for_value(version, "ofp_instruction_type", k)
 :: v = list(v)
 :: if len(v) == 1:
     ${k} : ${v[0].pyname}.unpack,
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index 8e2f861..ffad6cf 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -27,6 +27,7 @@
 ::
 :: import itertools
 :: import of_g
+:: import py_gen.util as util
 :: include('_copyright.py')
 
 :: include('_autogen.py')
@@ -51,9 +52,9 @@
     xid = None
 
 :: for ofclass in ofclasses:
-:: from py_gen.codegen import Member, LengthMember, TypeMember
-:: normal_members = [m for m in ofclass.members if type(m) == Member]
-:: type_members = [m for m in ofclass.members if type(m) == TypeMember]
+:: from loxi_ir import *
+:: normal_members = [m for m in ofclass.members if type(m) == OFDataMember]
+:: type_members = [m for m in ofclass.members if type(m) == OFTypeMember]
 class ${ofclass.pyname}(Message):
 :: for m in type_members:
     ${m.name} = ${m.value}
@@ -193,6 +194,7 @@
 :: sort_key = lambda x: x.type_members[1].value
 :: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
 :: for (k, v) in msgtype_groups:
+:: k = util.constant_for_value(version, "ofp_type", k)
 :: v = list(v)
 :: if len(v) == 1:
     ${k} : ${v[0].pyname}.unpack,
@@ -256,7 +258,7 @@
 # TODO OF 1.3 multipart messages
 :: #endif
 
-:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[1].value == 'const.OFPT_VENDOR']
+:: experimenter_ofclasses = [x for x in ofclasses if x.type_members[1].value == 4]
 :: sort_key = lambda x: x.type_members[2].value
 :: experimenter_ofclasses.sort(key=sort_key)
 :: grouped = itertools.groupby(experimenter_ofclasses, sort_key)
diff --git a/py_gen/templates/meter_band.py b/py_gen/templates/meter_band.py
index ca111d5..eeb9ff2 100644
--- a/py_gen/templates/meter_band.py
+++ b/py_gen/templates/meter_band.py
@@ -27,6 +27,7 @@
 ::
 :: import itertools
 :: import of_g
+:: import py_gen.util as util
 :: include('_copyright.py')
 
 :: include('_autogen.py')
@@ -57,6 +58,7 @@
 :: sort_key = lambda x: x.type_members[0].value
 :: msgtype_groups = itertools.groupby(sorted(ofclasses, key=sort_key), sort_key)
 :: for (k, v) in msgtype_groups:
+:: k = util.constant_for_value(version, "ofp_meter_band_type", k)
 :: v = list(v)
 :: if len(v) == 1:
     ${k} : ${v[0].pyname}.unpack,
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index e11a0a4..2a10a5f 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -52,9 +52,9 @@
     pass
 
 :: for ofclass in ofclasses:
-:: from py_gen.codegen import Member, LengthMember, TypeMember
-:: normal_members = [m for m in ofclass.members if type(m) == Member]
-:: type_members = [m for m in ofclass.members if type(m) == TypeMember]
+:: from loxi_ir import *
+:: normal_members = [m for m in ofclass.members if type(m) == OFDataMember]
+:: type_members = [m for m in ofclass.members if type(m) == OFTypeMember]
 class ${ofclass.pyname}(OXM):
 :: for m in type_members:
     ${m.name} = ${m.value}
@@ -99,7 +99,7 @@
 :: #endfor
 
 parsers = {
-:: key = lambda x: int(x.type_members[0].value, 16)
+:: key = lambda x: x.type_members[0].value
 :: for ofclass in sorted(ofclasses, key=key):
     ${key(ofclass)} : ${ofclass.pyname}.unpack,
 :: #endfor
diff --git a/py_gen/util.py b/py_gen/util.py
index 30c5d50..f527964 100644
--- a/py_gen/util.py
+++ b/py_gen/util.py
@@ -31,7 +31,6 @@
 
 import os
 import of_g
-import loxi_front_end.type_maps as type_maps
 import loxi_utils.loxi_utils as utils
 
 templates_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
@@ -42,38 +41,10 @@
 def render_static(out, name):
     utils.render_static(out, name, [templates_dir])
 
-def lookup_unified_class(cls, version):
-    unified_class = of_g.unified[cls][version]
-    if "use_version" in unified_class: # deref version ref
-        ref_version = unified_class["use_version"]
-        unified_class = of_g.unified[cls][ref_version]
-    return unified_class
-
-def primary_wire_type(cls, version):
-    if cls in type_maps.stats_reply_list:
-        return type_maps.type_val[("of_stats_reply", version)]
-    elif cls in type_maps.stats_request_list:
-        return type_maps.type_val[("of_stats_request", version)]
-    elif cls in type_maps.flow_mod_list:
-        return type_maps.type_val[("of_flow_mod", version)]
-    elif (cls, version) in type_maps.type_val:
-        return type_maps.type_val[(cls, version)]
-    elif type_maps.message_is_extension(cls, version):
-        return type_maps.type_val[("of_experimenter", version)]
-    elif type_maps.action_is_extension(cls, version):
-        return type_maps.type_val[("of_action_experimenter", version)]
-    elif type_maps.action_id_is_extension(cls, version):
-        return type_maps.type_val[("of_action_id_experimenter", version)]
-    elif type_maps.instruction_is_extension(cls, version):
-        return type_maps.type_val[("of_instruction_experimenter", version)]
-    elif type_maps.queue_prop_is_extension(cls, version):
-        return type_maps.type_val[("of_queue_prop_experimenter", version)]
-    elif type_maps.table_feature_prop_is_extension(cls, version):
-        return type_maps.type_val[("of_table_feature_prop_experimenter", version)]
-    else:
-        raise ValueError("No wiretype for %s in version %d" % (cls, version))
-
 def constant_for_value(version, group, value):
-    return (["const." + v["ofp_name"] for k, v in of_g.identifiers.items()
-             if k in of_g.identifiers_by_group[group] and
-                v["values_by_version"].get(version, None) == value] or [value])[0]
+    enums = of_g.ir[version].enums
+    enum = [x for x in enums if x.name == group][0]
+    for name, value2 in enum.values:
+        if value == value2:
+            return "const." + name
+    return repr(value)