loci: clean up generating remaining type_maps
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 784dcea..d919e42 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -361,48 +361,6 @@
     """
     Use the type members in the IR to fill out the legacy type_maps.
     """
-
-    def split_inherited_cls(cls):
-        if cls == 'of_meter_band_stats': # HACK not a subtype of of_meter_band
-            return None, None
-        for parent in sorted(type_maps.inheritance_data.keys(), reverse=True):
-            if cls.startswith(parent):
-                return (parent, cls[len(parent)+1:])
-        return None, None
-
-    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) and cls != prefix:
-                return experimenter
-        return None
-
-    def find_type_value(ofclass, m_name):
-        for m in ofclass.members:
-            if isinstance(m, OFTypeMember) and m.name == m_name:
-                return m.value
-        raise KeyError("ver=%d, cls=%s, m_name=%s" % (wire_version, cls, m_name))
-
-    # Most inheritance classes: actions, instructions, etc
-    for version, protocol in loxi_globals.ir.items():
-        wire_version = version.wire_version
-        for ofclass in protocol.classes:
-            cls = ofclass.name
-            parent, subcls = split_inherited_cls(cls)
-            if not (parent and subcls):
-                continue
-            if parent == 'of_oxm':
-                type_len = find_type_value(ofclass, 'type_len')
-                oxm_class = (type_len >> 16) & 0xffff
-                if oxm_class != 0x8000:
-                    # Do not include experimenter OXMs in the main table
-                    val = type_maps.invalid_type
-                else:
-                    val = (type_len >> 8) & 0xff
-            else:
-                val = find_type_value(ofclass, 'type')
-            type_maps.inheritance_data[parent][wire_version][subcls] = val
-
     type_maps.generate_maps()
 
 def analyze_input():
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index 03e1c2a..221adbe 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -53,98 +53,19 @@
 #
 ################################################################
 
-instruction_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-instruction_id_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-action_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-action_id_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-queue_prop_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict()
-    }
-
-bsn_vport_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-oxm_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-hello_elem_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-table_feature_prop_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-meter_band_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-bsn_tlv_types = {
-    of_g.VERSION_1_0:dict(),
-    of_g.VERSION_1_1:dict(),
-    of_g.VERSION_1_2:dict(),
-    of_g.VERSION_1_3:dict(),
-    }
-
-# All inheritance data for non-messages
-inheritance_data = dict(
-    of_instruction = instruction_types,
-    of_instruction_id = instruction_id_types,
-    of_action = action_types,
-    of_action_id = action_id_types,
-    of_oxm = oxm_types,
-    of_queue_prop = queue_prop_types,
-    of_hello_elem = hello_elem_types,
-    of_table_feature_prop = table_feature_prop_types,
-    of_meter_band = meter_band_types,
-    # BSN specific inheritance extensions
-    of_bsn_vport = bsn_vport_types,
-    of_bsn_tlv = bsn_tlv_types,
-    )
+inheritance_roots = [
+    'of_instruction',
+    'of_instruction_id',
+    'of_action',
+    'of_action_id',
+    'of_oxm',
+    'of_queue_prop',
+    'of_hello_elem',
+    'of_table_feature_prop',
+    'of_meter_band',
+    'of_bsn_vport',
+    'of_bsn_tlv',
+]
 
 def class_is_virtual(cls):
     """
@@ -156,32 +77,41 @@
         return True
     return loxi_globals.unified.class_by_name(cls).virtual
 
-################################################################
-#
-# type_val is the primary data structure that maps an
-# (class_name, version) pair to the wire data type value
-#
-################################################################
+# map from root class name to (map from wire version to set of subclass names)
+inheritance_data = {}
 
-type_val = dict()
+# map from parent class name to set of subclass names
 inheritance_map = dict()
 
 def generate_maps():
-    for parent, versioned in inheritance_data.items():
-        inheritance_map[parent] = set()
-        for ver, subclasses in versioned.items():
-            for subcls in subclasses:
-                inheritance_map[parent].add(subcls)
+    def inheritance_root(ofclass):
+        if not ofclass.superclass:
+            if ofclass.name in inheritance_roots:
+                return ofclass
+            else:
+                return None
+        else:
+            return inheritance_root(ofclass.superclass)
 
-    for parent, versioned in inheritance_data.items():
-        for version, subclasses in versioned.items():
-            for subcls, value in subclasses.items():
-                name = parent + "_" + subcls
-                type_val[(name, version)] = value
+    for version, protocol in loxi_globals.ir.items():
+        wire_version = version.wire_version
+        for ofclass in protocol.classes:
+            root = inheritance_root(ofclass)
+            if not root or root == ofclass:
+                continue
 
-    # Special case OF-1.2 match type
-    type_val[("of_match_v3", of_g.VERSION_1_2)] = 1
-    type_val[("of_match_v3", of_g.VERSION_1_3)] = 1
+            assert ofclass.name.startswith(root.name + '_')
+            subcls = ofclass.name[len(root.name)+1:]
+
+            if root.name not in inheritance_data:
+                inheritance_data[root.name] = {}
+            if wire_version not in inheritance_data[root.name]:
+                inheritance_data[root.name][wire_version] = set()
+            inheritance_data[root.name][wire_version].add(subcls)
+
+            if root.name not in inheritance_map:
+                inheritance_map[root.name] = set()
+            inheritance_map[root.name].add(subcls)
 
 def sub_class_map(base_type, version):
     """