Initial import

LoxiGen is the work of several developers, not just myself.
diff --git a/loxi_front_end/__init__.py b/loxi_front_end/__init__.py
new file mode 100644
index 0000000..5e4e379
--- /dev/null
+++ b/loxi_front_end/__init__.py
@@ -0,0 +1,26 @@
+# 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.
diff --git a/loxi_front_end/c_parse_utils.py b/loxi_front_end/c_parse_utils.py
new file mode 100644
index 0000000..f06904b
--- /dev/null
+++ b/loxi_front_end/c_parse_utils.py
@@ -0,0 +1,166 @@
+# 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.
+
+##
+# @brief Utilities related to parsing C files
+#
+import re
+import sys
+import os
+import of_g
+
+def type_dec_to_count_base(m_type):
+    """
+    Resolve a type declaration like uint8_t[4] to a count (4) and base_type
+    (uint8_t)
+
+    @param m_type The string type declaration to process
+    """
+    count = 1
+    chk_ar = m_type.split('[')
+    if len(chk_ar) > 1:
+        count_str = chk_ar[1].split(']')[0]
+        if count_str in of_g.ofp_constants:
+            count = of_g.ofp_constants[count_str]
+        else:
+            count = int(count_str)
+        base_type = chk_ar[0]
+    else:
+        base_type = m_type
+    return count, base_type
+
+def comment_remover(text):
+    """
+    Remove C and C++ comments from text
+    @param text Possibly multiline string of C code.
+
+    http://stackoverflow.com/questions/241327/python-snippet-to-remove-c-and-c-comments
+    """
+
+    def replacer(match):
+        s = match.group(0)
+        if s.startswith('/'):
+            return ""
+        else:
+            return s
+    pattern = re.compile(
+        r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+        re.DOTALL | re.MULTILINE
+    )
+    return re.sub(pattern, replacer, text)
+
+
+def clean_up_input(text):
+    text = comment_remover(text)
+    text_lines = text.splitlines()
+    all_lines = []
+    for line in text_lines:
+        line = re.sub("\t", " ", line) # get rid of tabs
+        line = re.sub(" +$", "", line) # Strip trailing blanks
+        if len(line):
+            all_lines.append(line)
+    text = "\n".join(all_lines)
+    return text
+
+def extract_structs(contents):
+    """
+    Extract the structures from raw C code input
+    @param contents The text of the original C code
+    """
+    contents = clean_up_input(contents)
+    struct_list = re.findall("struct .* \{[^}]+\};", contents)
+    return struct_list
+
+def extract_enums(contents):
+    """
+    Extract the enums from raw C code input
+    @param contents The text of the original C code
+    @return An array where each entry is an (unparsed) enum instance
+    """
+    contents = clean_up_input(contents)
+    enum_list = re.findall("enum .* \{[^}]+\};", contents)
+    return enum_list
+
+def extract_enum_vals(enum):
+    """
+    From a C enum, return a pair (name, values)
+    @param enum The C syntax enumeration
+    @returns (name, values), see below
+
+    name is the enum name
+    values is a list pairs (<ident>, <value>) where ident is the
+    identifier and value is the associated value.
+
+    The values are integers when possible, otherwise strings
+    """
+
+    rv_list = []
+    name = re.search("enum +(\w+)", enum).group(1)
+    lines = " ".join(enum.split("\n"))
+    body = re.search("\{(.+)\}", lines).group(1)
+    entries = body.split(",")
+    previous_value = -1
+    for m in entries:
+        if re.match(" *$", m): # Empty line
+            continue
+        # Parse with = first
+        search_obj = re.match(" +(\w+) *= *(.*) *", m)
+        if search_obj:  # Okay, had =
+            e_name = search_obj.group(1)
+            e_value = search_obj.group(2)
+        else: # No equals
+            search_obj = re.match(" +(\w+)", m)
+            if not search_obj:
+                sys.stderr.write("\nError extracting enum for %s, member %s\n"
+                                 % (name, m))
+                sys.exit(1)
+            e_name = search_obj.group(1)
+            e_value = previous_value + 1
+        rv_list.append([e_name, e_value])
+
+        if type(e_value) is type(0):
+            previous_value = e_value
+        else:
+            try:
+                previous_value = int(e_value, 0)
+            except ValueError:
+                pass
+    return (name, rv_list)
+
+def extract_defines(contents):
+    """
+    Returns a list of pairs (<identifier>, <value>) where
+    #define <ident> <value> appears in the file
+    """
+    rv_list = []
+    contents = clean_up_input(contents)
+    define_list = re.findall("\#define +[^ ]+ .*\n", contents, re.M)
+    for entry in define_list:
+        match_obj = re.match("#define +([^ ]+) +(.+)$", entry)
+        rv_list.append([match_obj.group(1),match_obj.group(2)])
+    return rv_list
+        
diff --git a/loxi_front_end/flags.py b/loxi_front_end/flags.py
new file mode 100644
index 0000000..3c401f9
--- /dev/null
+++ b/loxi_front_end/flags.py
@@ -0,0 +1,76 @@
+# 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.
+
+"""
+This file needs significant work and normalization.  We need a better
+representation for flags, associating them to variables, and associating
+them to OF versions.
+
+@fixme Most of this will be going away soon
+"""
+
+import sys
+import copy
+import type_maps
+import of_g
+import re
+
+# These mark idents as _not_ flags and have precedence
+non_flag_rules = [
+    "OF_CONFIG_FRAG_NORMAL",
+    "OF_FLOW_MOD_FAILED_BAD_FLAGS",
+    "OF_SWITCH_CONFIG_FAILED_BAD_FLAGS",
+    "OF_PORT_STATE_FLAG_STP_LISTEN",
+    "OF_TABLE_CONFIG_TABLE_MISS_CONTROLLER",
+    ]
+
+# These mark idents as flags
+flag_rules = [
+    "OF_CONFIG_",
+    "OF_TABLE_CONFIG_",
+    ]
+
+def ident_is_flag(ident):
+    """
+    Return True if ident should be treated as a flag
+    """
+
+    # Do negative matches first
+    for entry in non_flag_rules:
+        if re.match(entry, ident):
+            return False
+
+    # General rule, if it says flag it is (unless indicated above)
+    if ident.find("FLAG") >= 0:
+        return True
+
+    for entry in flag_rules:
+        if re.match(entry, ident):
+            return True
+
+    return False
+    
diff --git a/loxi_front_end/identifiers.py b/loxi_front_end/identifiers.py
new file mode 100644
index 0000000..a4122ee
--- /dev/null
+++ b/loxi_front_end/identifiers.py
@@ -0,0 +1,99 @@
+# 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.
+
+##
+# @brief Process identifiers for updating of_g.identifiers
+#
+
+import sys
+import of_h_utils
+from generic_utils import *
+import of_g
+
+##
+# The value to use when an identifier is not defined for a version
+UNDEFINED_IDENT_VALUE = 0
+
+def add_identifiers(all_idents, idents_by_group, version, contents):
+    """
+    Update all_idents with identifiers from an openflow.h header file
+    @param all_idents A dict, usually of_g.identifiers
+    @param idents_by_group A dict for mapping LOXI idents to groups,
+    usually of_g.identifiers_by_group
+    @param version The OF wire version
+    @param contents The contents of an openflow.h file
+    """
+
+    # Get the dictionary of enums from the file text
+    enum_dict = of_h_utils.get_enum_dict(version,
+                                         contents)
+    for name, info in enum_dict.items():
+
+        # info is a DotDict w/ keys ofp_name, ofp_group and value.
+        if name in all_idents:
+            all_idents[name]["values_by_version"][version] = info.value
+            if ((all_idents[name]["ofp_name"] != info.ofp_name or 
+                all_idents[name]["ofp_group"] != info.ofp_group) and
+                info.ofp_name.find("OFPP_") != 0):
+                log("""
+NOTE: Identifier %s has different ofp name or group in version %s
+From ofp name %s, group %s to name %s, group %s.
+This could indicate a name collision in LOXI identifier translation.
+""" % (name, str(version), all_idents[name]["ofp_name"],
+       all_idents[name]["ofp_group"], info.ofp_name, info.ofp_group))
+                # Update stuff assuming newer versions processed later
+                all_idents[name]["ofp_name"] = info.ofp_name
+                all_idents[name]["ofp_group"] = info.ofp_group
+
+        else: # New name
+            all_idents[name] = dict(
+                values_by_version = {version:info.value},
+                common_value = info["value"],
+                ofp_name = info["ofp_name"],
+                ofp_group = info["ofp_group"]
+                )
+            if info["ofp_group"] not in idents_by_group:
+                idents_by_group[info["ofp_group"]] = []
+            if name not in idents_by_group[info["ofp_group"]]:
+                idents_by_group[info["ofp_group"]].append(name)
+
+def all_versions_agree(all_idents, version_list, name):
+    val_list = all_idents[name]["values_by_version"]
+    for version in version_list:
+        if not version in val_list:
+            return False
+        if str(val_list[version]) != str(all_idents[name]["common_value"]):
+            return False
+    return True
+
+def defined_versions_agree(all_idents, version_list, name):
+    val_list = all_idents[name]["values_by_version"]
+    for version in version_list:
+        if version in val_list:
+            if str(val_list[version]) != str(all_idents[name]["common_value"]):
+                return False
+    return True
diff --git a/loxi_front_end/match.py b/loxi_front_end/match.py
new file mode 100644
index 0000000..4ab3126
--- /dev/null
+++ b/loxi_front_end/match.py
@@ -0,0 +1,488 @@
+# 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.
+
+# @brief Match data representation
+#
+# @fixme This still has lots of C specific code that should be moved into c_gen
+
+import sys
+import of_g
+from generic_utils import *
+import oxm
+import loxi_utils.loxi_utils as loxi_utils
+
+#
+# Use 1.2 match semantics for common case
+#
+# Generate maps between generic match and version specific matches
+# Generate dump functions for generic match
+# Generate dump functions for version specific matches
+
+## @var of_match_members
+# The dictionary from unified match members to type and indexing info
+#
+# Keys:
+#   name The unified name used for the member
+#   m_type The data type used for the object in unified structure
+#   print_type The id to use when printing
+#   conditions The condition underwhich the field could occur TBD
+#   takes_mask_in_spec Shown as taking mask in OF 1.2 spec; IGNORED NOW
+#   order Used to define an order for readability
+#   v1_wc_shift The WC shift in OF 1.0
+#   v2_wc_shift The WC shift in OF 1.1
+#
+# Unless noted otherwise, class is 0x8000, OFPXMC_OPENFLOW_BASIC
+# We use the 1.2 names and alias older names
+# Conditions:
+#  is_ipv4(_m):  ((_m)->eth_type == 0x0800)
+#  is_ipv6(_m):  ((_m)->eth_type == 0x86dd)
+#  is_ip(_m):    (is_ipv4(_m) || is_ipv6(_m))
+#  is_arp(_m):   ((_m)->eth_type == 0x0806)
+#  is_tcp(_m):   (is_ip(_m) && ((_m)->ip_proto == 6))
+#  is_udp(_m):   (is_ip(_m) && ((_m)->ip_proto == 17))
+#  is_sctp(_m):  (is_ip(_m) && ((_m)->ip_proto == 132))
+#  is_icmpv4(_m):  (is_ipv4(_m) && ((_m)->ip_proto == 1))
+#  is_icmpv6(_m):  (is_ipv6(_m) && ((_m)->ip_proto == 58))
+#
+
+of_match_members = dict(
+    in_port = dict(
+        name="in_port",
+        m_type="of_port_no_t",
+        print_type="PRIx32",
+        conditions="",
+        v1_wc_shift=0,
+        v2_wc_shift=0,
+        takes_mask_in_spec=False,
+        order=100,
+        ),
+    in_phy_port = dict(
+        name="in_phy_port",
+        m_type="of_port_no_t",
+        print_type="PRIx32",
+        conditions="", # OXM_OF_IN_PORT must be present
+        takes_mask_in_spec=False,
+        order=101,
+        ),
+    metadata = dict(
+        name="metadata",
+        m_type="uint64_t",
+        print_type="PRIx64",
+        conditions="",
+        takes_mask_in_spec=True,
+        order=102,
+        ),
+
+    eth_dst = dict(
+        name="eth_dst",
+        m_type="of_mac_addr_t",
+        v1_wc_shift=3,
+        print_type="\"p\"",
+        conditions="",
+        takes_mask_in_spec=True,
+        order=200,
+        ),
+    eth_src = dict(
+        name="eth_src",
+        m_type="of_mac_addr_t",
+        v1_wc_shift=2,
+        print_type="\"p\"",
+        conditions="",
+        takes_mask_in_spec=True,
+        order=201,
+        ),
+    eth_type = dict(
+        name="eth_type",
+        m_type="uint16_t",
+        v1_wc_shift=4,
+        v2_wc_shift=3,
+        print_type="PRIx16",
+        conditions="",
+        takes_mask_in_spec=False,
+        order=203,
+        ),
+    vlan_vid = dict(  # FIXME: Semantics changed in 1.2
+        # Use CFI bit to indicate tag presence
+        name="vlan_vid",
+        m_type="uint16_t",
+        v1_wc_shift=1,
+        v2_wc_shift=1,
+        print_type="PRIx16",
+        conditions="",
+        takes_mask_in_spec=True,
+        order=210,
+        ),
+    vlan_pcp = dict(
+        name="vlan_pcp",
+        m_type="uint8_t",
+        v1_wc_shift=20,
+        v2_wc_shift=2,
+        print_type="PRIx8",
+        conditions="",
+        takes_mask_in_spec=False,
+        order=211,
+        ),
+    ipv4_src = dict(
+        name="ipv4_src",
+        m_type="uint32_t",
+        v1_wc_shift=8,
+        print_type="PRIx32",
+        conditions="is_ipv4(match)",
+        takes_mask_in_spec=True,
+        order=300,
+        ),
+    ipv4_dst = dict(
+        name="ipv4_dst",
+        m_type="uint32_t",
+        v1_wc_shift=14,
+        print_type="PRIx32",
+        conditions="is_ipv4(match)",
+        takes_mask_in_spec=True,
+        order=301,
+        ),
+    ip_dscp = dict(
+        name="ip_dscp",
+        m_type="uint8_t",
+        v1_wc_shift=21,
+        v2_wc_shift=4,
+        print_type="PRIx8",
+        conditions="is_ip(match)",
+        takes_mask_in_spec=False,
+        order=310,
+        ),
+    ip_ecn = dict(
+        name="ip_ecn",
+        m_type="uint8_t",
+        print_type="PRIx8",
+        conditions="is_ip(match)",
+        takes_mask_in_spec=False,
+        order=311,
+        ),
+    ip_proto = dict(
+        name="ip_proto",
+        m_type="uint8_t",
+        v1_wc_shift=5,
+        v2_wc_shift=5,
+        print_type="PRIx8",
+        conditions="is_ip(match)",
+        takes_mask_in_spec=False,
+        order=320,
+        ),
+
+    tcp_dst = dict(
+        name="tcp_dst",
+        m_type="uint16_t",
+        v1_wc_shift=7,
+        v2_wc_shift=7,
+        print_type="PRIx16",
+        conditions="is_tcp(match)",
+        takes_mask_in_spec=False,
+        order=400,
+        ),
+    tcp_src = dict(
+        name="tcp_src",
+        m_type="uint16_t",
+        v1_wc_shift=6,
+        v2_wc_shift=6,
+        print_type="PRIx16",
+        conditions="is_tcp(match)",
+        takes_mask_in_spec=False,
+        order=401,
+        ),
+
+    udp_dst = dict(
+        name="udp_dst",
+        m_type="uint16_t",
+        print_type="PRIx16",
+        conditions="is_udp(match)",
+        takes_mask_in_spec=False,
+        order=410,
+        ),
+    udp_src = dict(
+        name="udp_src",
+        m_type="uint16_t",
+        print_type="PRIx16",
+        conditions="is_udp(match)",
+        takes_mask_in_spec=False,
+        order=411,
+        ),
+
+    sctp_dst = dict(
+        name="sctp_dst",
+        m_type="uint16_t",
+        print_type="PRIx16",
+        conditions="is_sctp(match)",
+        takes_mask_in_spec=False,
+        order=420,
+        ),
+    sctp_src = dict(
+        name="sctp_src",
+        m_type="uint16_t",
+        print_type="PRIx16",
+        conditions="is_sctp(match)",
+        takes_mask_in_spec=False,
+        order=421,
+        ),
+
+    icmpv4_type = dict(
+        name="icmpv4_type",
+        m_type="uint8_t",
+        print_type="PRIx8",
+        conditions="is_icmp_v4(match)",
+        takes_mask_in_spec=False,
+        order=430,
+        ),
+    icmpv4_code = dict(
+        name="icmpv4_code",
+        m_type="uint8_t",
+        print_type="PRIx8",
+        conditions="is_icmp_v4(match)",
+        takes_mask_in_spec=False,
+        order=431,
+        ),
+
+    arp_op = dict(
+        name="arp_op",
+        m_type="uint16_t",
+        print_type="PRIx16",
+        conditions="is_arp(match)",
+        takes_mask_in_spec=False,
+        order=250,
+        ),
+
+    arp_spa = dict(
+        name="arp_spa",
+        m_type="uint32_t",
+        print_type="PRIx32",
+        conditions="is_arp(match)",
+        takes_mask_in_spec=True,
+        order=251,
+        ),
+    arp_tpa = dict(
+        name="arp_tpa",
+        m_type="uint32_t",
+        print_type="PRIx32",
+        conditions="is_arp(match)",
+        takes_mask_in_spec=True,
+        order=252,
+        ),
+
+    arp_sha = dict(
+        name="arp_sha",
+        m_type="of_mac_addr_t",
+        print_type="\"p\"",
+        conditions="is_arp(match)",
+        takes_mask_in_spec=False,
+        order=253,
+        ),
+    arp_tha = dict(
+        name="arp_tha",
+        m_type="of_mac_addr_t",
+        print_type="\"p\"",
+        conditions="is_arp(match)",
+        takes_mask_in_spec=False,
+        order=254,
+        ),
+
+    ipv6_src = dict(
+        name="ipv6_src",
+        m_type="of_ipv6_t",
+        print_type="\"p\"",
+        conditions="is_ipv6(match)",
+        takes_mask_in_spec=True,
+        order=350,
+        ),
+    ipv6_dst = dict(
+        name="ipv6_dst",
+        m_type="of_ipv6_t",
+        print_type="\"p\"",
+        conditions="is_ipv6(match)",
+        takes_mask_in_spec=True,
+        order=351,
+        ),
+
+    ipv6_flabel = dict(
+        name="ipv6_flabel",
+        m_type="uint32_t",
+        print_type="PRIx32",
+        conditions="is_ipv6(match)",
+        takes_mask_in_spec=False, # Comment in openflow.h says True
+        order=360,
+        ),
+
+    icmpv6_type = dict(
+        name="icmpv6_type",
+        m_type="uint8_t",
+        print_type="PRIx8",
+        conditions="is_icmp_v6(match)",
+        takes_mask_in_spec=False,
+        order=440,
+        ),
+    icmpv6_code = dict(
+        name="icmpv6_code",
+        m_type="uint8_t",
+        print_type="PRIx8",
+        conditions="is_icmp_v6(match)",
+        takes_mask_in_spec=False,
+        order=441,
+        ),
+
+    ipv6_nd_target = dict(
+        name="ipv6_nd_target",
+        m_type="of_ipv6_t",
+        print_type="\"p\"",
+        conditions="", # fixme
+        takes_mask_in_spec=False,
+        order=442,
+        ),
+
+    ipv6_nd_sll = dict(
+        name="ipv6_nd_sll",
+        m_type="of_mac_addr_t",
+        print_type="\"p\"",
+        conditions="", # fixme
+        takes_mask_in_spec=False,
+        order=443,
+        ),
+    ipv6_nd_tll = dict(
+        name="ipv6_nd_tll",
+        m_type="of_mac_addr_t",
+        print_type="\"p\"",
+        conditions="", # fixme
+        takes_mask_in_spec=False,
+        order=444,
+        ),
+
+    mpls_label = dict(
+        name="mpls_label",
+        m_type="uint32_t",
+        v2_wc_shift=8,
+        print_type="PRIx32",
+        conditions="",
+        takes_mask_in_spec=False,
+        order=500,
+        ),
+    mpls_tc = dict(
+        name="mpls_tc",
+        m_type="uint8_t",
+        v2_wc_shift=9,
+        print_type="PRIx8",
+        conditions="",
+        takes_mask_in_spec=False,
+        order=501,
+        ),
+)
+
+match_keys_sorted = of_match_members.keys()
+match_keys_sorted.sort(key=lambda entry:of_match_members[entry]["order"])
+
+of_v1_keys = [
+    "eth_dst",
+    "eth_src",
+    "eth_type",
+    "in_port",
+    "ipv4_dst",
+    "ip_proto",
+    "ipv4_src",
+    "ip_dscp",
+    "tcp_dst",  # Means UDP too for 1.0 and 1.1
+    "tcp_src",  # Means UDP too for 1.0 and 1.1
+    "vlan_pcp",
+    "vlan_vid"
+    ]
+
+of_v2_keys = [
+    "eth_dst",
+    "eth_src",
+    "eth_type",
+    "in_port",
+    "ipv4_dst",
+    "ip_proto",
+    "ipv4_src",
+    "ip_dscp",
+    "tcp_dst",  # Means UDP too for 1.0 and 1.1
+    "tcp_src",  # Means UDP too for 1.0 and 1.1
+    "vlan_pcp",
+    "vlan_vid",
+    "mpls_label",
+    "mpls_tc",
+    "metadata"
+    ]
+
+of_v2_full_mask = [
+    "eth_dst",
+    "eth_src",
+    "ipv4_dst",
+    "ipv4_src",
+    "metadata"
+    ]
+
+def oxm_index(key):
+    """
+    What's the index called for a match key
+    """
+    return "OF_OXM_INDEX_" + key.upper()
+
+##
+# Check that all members in the hash are recognized as match keys
+def match_sanity_check():
+    count = 0
+    for match_v in ["of_match_v1", "of_match_v2"]:
+        count += 1
+        for mm in of_g.unified[match_v][count]["members"]:
+            key = mm["name"]
+            if key.find("_mask") >= 0:
+                continue
+            if loxi_utils.skip_member_name(key):
+                continue
+            if key == "wildcards":
+                continue
+            if not key in of_match_members:
+                print "Key %s not found in match struct, v %s" % (key, match_v)
+                sys.exit(1)
+
+    # Check oxm list and the list above
+    for key in oxm.oxm_types:
+        if not key in of_match_members:
+            if not (key.find("_masked") > 0):
+                debug("Key %s in oxm.oxm_types, not of_match_members" % key)
+                sys.exit(1)
+            if not key[:-7] in of_match_members:
+                debug("Key %s in oxm.oxm_types, but %s not in of_match_members"
+                      % (key, key[:-7]))
+                sys.exit(1)
+
+    for key in of_match_members:
+        if not key in oxm.oxm_types:
+            debug("Key %s in of_match_members, not in oxm.oxm_types" % key)
+            sys.exit(1)
+        if of_match_members[key]["m_type"] != oxm.oxm_types[key]:
+            debug("Type mismatch for key %s in oxm data: %s vs %s" %
+                  (key, of_match_members[key]["m_type"], oxm.oxm_types[key]))
+            sys.exit(1)
+
+
diff --git a/loxi_front_end/of_h_utils.py b/loxi_front_end/of_h_utils.py
new file mode 100644
index 0000000..1259a90
--- /dev/null
+++ b/loxi_front_end/of_h_utils.py
@@ -0,0 +1,154 @@
+# 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.
+
+##
+# @brief Utilities related to processing OF header files
+#
+
+import re
+import sys
+import os
+import c_parse_utils
+import loxi_utils.py_utils as py_utils
+import translation
+from generic_utils import *
+import copy
+
+# Silently ignore idents matching any of these
+ignore_idents = [
+    "OFPXMT_OFB_", "OFPFMF_", "OXM_OF_", "OFPXMT_",
+    "OPENFLOW_OPENFLOW_H", "OFP_ASSERT", "OFP_PACKED", "OFP_VERSION"
+    ]
+
+def warn_unmapped_ident(ident, t_name="enum"):
+    for ignore_ident in ignore_idents:
+        if re.match(ignore_ident, ident):
+            return
+    log("Skipping ident %s. Did not map %s identifier to LOXI" %
+              (ident, t_name))
+
+def fixup_values(ident, value, version, ident_list):
+    """
+    Fix up values for LOXI reasons
+
+    Translate defintions that refer to other identifiers
+    This is really just needed for the special case of OFPFW in 1.0 and 1.1.
+
+    Also, LOXI is aware of the change in type of port numbers, so 
+    translate those here.
+    """
+    value_string = str(value).strip()
+    if ident.find("OFPP_") == 0 and version == of_g.VERSION_1_0:
+        value_string = "0x%x" % (int(value, 0) + 0xffff0000)
+
+    # Otherwise, if no reference to a wildcard value, all done
+    if value_string.find("OFPFW") < 0:
+        return value_string
+    for ident, id_value in ident_list.items():
+        id_value_string = "(" + str(id_value).strip() + ")"
+        # If the identifier has (, etc., ignore it; not handling params
+        if ident.find("(") >= 0:
+            continue
+        value_string = re.sub(ident, id_value_string, value_string)
+    return value_string
+
+def get_enum_dict(version, contents):
+    """
+    Given openflow.h input, create a dict for its enums
+    @param contents The raw contents of the C file
+
+    The dict returned is indexed by LOXI identifier.  Each entry is a
+    DotDict with three keys, value, ofp_name and ofp_group.  The value is an 
+    int value when possible, otherwise a string.  The ofp_name is the original
+    name from the openflow header file.  The ofp_group is the enum type.
+    """
+    rv_list = {}
+
+    version_ref = of_g.short_version_names[version]
+    enum_list = c_parse_utils.extract_enums(contents)
+    defines_list = c_parse_utils.extract_defines(contents)
+
+    # First generate a list of all original idents and values for translation
+    full_ident_list = {}
+
+    for enum in enum_list:
+        (name, values) = c_parse_utils.extract_enum_vals(enum)
+        for (ident, value) in values:
+            full_ident_list[ident] = str(value).strip()
+    for ident, value in defines_list:
+        full_ident_list[ident] = str(value).strip()
+
+    # Process enum idents
+    for enum in enum_list:
+        (name, values) = c_parse_utils.extract_enum_vals(enum)
+        for (ident, value) in values:
+            loxi_name = translation.loxi_name(ident)
+            if not loxi_name:
+                warn_unmapped_ident(ident)
+                continue
+            if loxi_name in rv_list:
+                sys.stderr.write("\nError: %s in ident list already\n" % 
+                                 loxi_name)
+                sys.exit(1)
+
+            value_str = fixup_values(ident, value, version, full_ident_list)
+            log("Adding LOXI identifier %s from name %s" % (loxi_name, ident))
+            rv_list[loxi_name] = py_utils.DotDict(dict(
+                ofp_name = ident,
+                ofp_group = name,
+                value = value_str))
+
+    for ident, value in defines_list:
+        loxi_name = translation.loxi_name(ident)
+        if not loxi_name:
+            warn_unmapped_ident(ident, "macro defn")
+            continue
+
+        value_str = fixup_values(ident, value, version, full_ident_list)
+        if loxi_name in rv_list:
+            if value_str != rv_list[loxi_name].value:
+                sys.stderr.write("""
+ERROR: IDENT COLLISION.  Version %s, LOXI Ident %s.
+New ofp_name %s, value %s.
+Previous ofp_name %s, value %s,
+""" % (version_ref, loxi_name, ident, value_str,
+       rv_list[loxi_name].ofp_name),  rv_list[loxi_name].value)
+                sys.exit(1)
+            else:
+                log("Ignoring redundant entry %s, mapping to %s" %
+                          (ident, loxi_name))
+
+        rv_list[loxi_name] = py_utils.DotDict(dict(
+                ofp_name = ident,
+                ofp_group = "macro_definitions",
+                value = value_str))
+
+    return rv_list
+
+
+
+
diff --git a/loxi_front_end/oxm.py b/loxi_front_end/oxm.py
new file mode 100644
index 0000000..d4cf273
--- /dev/null
+++ b/loxi_front_end/oxm.py
@@ -0,0 +1,228 @@
+# 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.
+
+import of_g
+
+oxm_types = dict(
+    in_port               = "of_port_no_t",
+    in_port_masked        = "of_port_no_t",
+    in_phy_port           = "of_port_no_t",
+    in_phy_port_masked    = "of_port_no_t",
+    metadata              = "uint64_t",
+    metadata_masked       = "uint64_t",
+    eth_dst               = "of_mac_addr_t",
+    eth_dst_masked        = "of_mac_addr_t",
+    eth_src               = "of_mac_addr_t",
+    eth_src_masked        = "of_mac_addr_t",
+    eth_type              = "uint16_t",
+    eth_type_masked       = "uint16_t",
+    vlan_vid              = "uint16_t",
+    vlan_vid_masked       = "uint16_t",
+    vlan_pcp              = "uint8_t",
+    vlan_pcp_masked       = "uint8_t",
+    ip_dscp               = "uint8_t",
+    ip_dscp_masked        = "uint8_t",
+    ip_ecn                = "uint8_t",
+    ip_ecn_masked         = "uint8_t",
+    ip_proto              = "uint8_t",
+    ip_proto_masked       = "uint8_t",
+    ipv4_src              = "uint32_t",
+    ipv4_src_masked       = "uint32_t",
+    ipv4_dst              = "uint32_t",
+    ipv4_dst_masked       = "uint32_t",
+    tcp_src               = "uint16_t",
+    tcp_src_masked        = "uint16_t",
+    tcp_dst               = "uint16_t",
+    tcp_dst_masked        = "uint16_t",
+    udp_src               = "uint16_t",
+    udp_src_masked        = "uint16_t",
+    udp_dst               = "uint16_t",
+    udp_dst_masked        = "uint16_t",
+    sctp_src              = "uint16_t",
+    sctp_src_masked       = "uint16_t",
+    sctp_dst              = "uint16_t",
+    sctp_dst_masked       = "uint16_t",
+    icmpv4_type           = "uint8_t",
+    icmpv4_type_masked    = "uint8_t",
+    icmpv4_code           = "uint8_t",
+    icmpv4_code_masked    = "uint8_t",
+    arp_op                = "uint16_t",
+    arp_op_masked         = "uint16_t",
+    arp_spa               = "uint32_t",
+    arp_spa_masked        = "uint32_t",
+    arp_tpa               = "uint32_t",
+    arp_tpa_masked        = "uint32_t",
+    arp_sha               = "of_mac_addr_t",
+    arp_sha_masked        = "of_mac_addr_t",
+    arp_tha               = "of_mac_addr_t",
+    arp_tha_masked        = "of_mac_addr_t",
+    ipv6_src              = "of_ipv6_t",
+    ipv6_src_masked       = "of_ipv6_t",
+    ipv6_dst              = "of_ipv6_t",
+    ipv6_dst_masked       = "of_ipv6_t",
+    ipv6_flabel           = "uint32_t",
+    ipv6_flabel_masked    = "uint32_t",
+    icmpv6_type           = "uint8_t",
+    icmpv6_type_masked    = "uint8_t",
+    icmpv6_code           = "uint8_t",
+    icmpv6_code_masked    = "uint8_t",
+    ipv6_nd_target        = "of_ipv6_t",
+    ipv6_nd_target_masked = "of_ipv6_t",
+    ipv6_nd_sll           = "of_mac_addr_t",
+    ipv6_nd_sll_masked    = "of_mac_addr_t",
+    ipv6_nd_tll           = "of_mac_addr_t",
+    ipv6_nd_tll_masked    = "of_mac_addr_t",
+    mpls_label            = "uint32_t",
+    mpls_label_masked     = "uint32_t",
+    mpls_tc               = "uint8_t",
+    mpls_tc_masked        = "uint8_t"
+    # FIXME Add 1.3 oxm elts
+    )
+
+oxm_wire_type = dict(
+    in_port               = (0 << 1),
+    in_port_masked        = (0 << 1) + 1,
+    in_phy_port           = (1 << 1),
+    in_phy_port_masked    = (1 << 1) + 1,
+    metadata              = (2 << 1),
+    metadata_masked       = (2 << 1) + 1,
+    eth_dst               = (3 << 1),
+    eth_dst_masked        = (3 << 1) + 1,
+    eth_src               = (4 << 1),
+    eth_src_masked        = (4 << 1) + 1,
+    eth_type              = (5 << 1),
+    eth_type_masked       = (5 << 1) + 1,
+    vlan_vid              = (6 << 1),
+    vlan_vid_masked       = (6 << 1) + 1,
+    vlan_pcp              = (7 << 1),
+    vlan_pcp_masked       = (7 << 1) + 1,
+    ip_dscp               = (8 << 1),
+    ip_dscp_masked        = (8 << 1) + 1,
+    ip_ecn                = (9 << 1),
+    ip_ecn_masked         = (9 << 1) + 1,
+    ip_proto              = (10 << 1),
+    ip_proto_masked       = (10 << 1) + 1,
+    ipv4_src              = (11 << 1),
+    ipv4_src_masked       = (11 << 1) + 1,
+    ipv4_dst              = (12 << 1),
+    ipv4_dst_masked       = (12 << 1) + 1,
+    tcp_src               = (13 << 1),
+    tcp_src_masked        = (13 << 1) + 1,
+    tcp_dst               = (14 << 1),
+    tcp_dst_masked        = (14 << 1) + 1,
+    udp_src               = (15 << 1),
+    udp_src_masked        = (15 << 1) + 1,
+    udp_dst               = (16 << 1),
+    udp_dst_masked        = (16 << 1) + 1,
+    sctp_src              = (17 << 1),
+    sctp_src_masked       = (17 << 1) + 1,
+    sctp_dst              = (18 << 1),
+    sctp_dst_masked       = (18 << 1) + 1,
+    icmpv4_type           = (19 << 1),
+    icmpv4_type_masked    = (19 << 1) + 1,
+    icmpv4_code           = (20 << 1),
+    icmpv4_code_masked    = (20 << 1) + 1,
+    arp_op                = (21 << 1),
+    arp_op_masked         = (21 << 1) + 1,
+    arp_spa               = (22 << 1),
+    arp_spa_masked        = (22 << 1) + 1,
+    arp_tpa               = (23 << 1),
+    arp_tpa_masked        = (23 << 1) + 1,
+    arp_sha               = (24 << 1),
+    arp_sha_masked        = (24 << 1) + 1,
+    arp_tha               = (25 << 1),
+    arp_tha_masked        = (25 << 1) + 1,
+    ipv6_src              = (26 << 1),
+    ipv6_src_masked       = (26 << 1) + 1,
+    ipv6_dst              = (27 << 1),
+    ipv6_dst_masked       = (27 << 1) + 1,
+    ipv6_flabel           = (28 << 1),
+    ipv6_flabel_masked    = (28 << 1) + 1,
+    icmpv6_type           = (29 << 1),
+    icmpv6_type_masked    = (29 << 1) + 1,
+    icmpv6_code           = (30 << 1),
+    icmpv6_code_masked    = (30 << 1) + 1,
+    ipv6_nd_target        = (31 << 1),
+    ipv6_nd_target_masked = (31 << 1) + 1,
+    ipv6_nd_sll           = (32 << 1),
+    ipv6_nd_sll_masked    = (32 << 1) + 1,
+    ipv6_nd_tll           = (33 << 1),
+    ipv6_nd_tll_masked    = (33 << 1) + 1,
+    mpls_label            = (34 << 1),
+    mpls_label_masked     = (34 << 1) + 1,
+    mpls_tc               = (35 << 1),
+    mpls_tc_masked        = (35 << 1) + 1
+    # FIXME Add 1.3 oxm elts
+)
+
+def add_oxm_classes_1_2(classes, version):
+    """
+    Add the OXM classes to object passed.  This is a dictionary
+    indexed by class name whose value is an array of member objects.
+    """
+    # First the parent class:
+    if version not in [of_g.VERSION_1_2, of_g.VERSION_1_3]:
+        return
+
+    members = []
+    classes["of_oxm"] = []
+    of_g.ordered_classes[version].append("of_oxm")
+    members.append(dict(name="type_len", m_type="uint32_t"))
+    classes["of_oxm_header"] = members
+    of_g.ordered_classes[version].append("of_oxm_header")
+
+    for oxm in oxm_types:
+        members = []
+        # Assert oxm_types[oxm] in of_base_types
+        m_type = oxm_types[oxm]
+        if m_type in of_g.of_mixed_types:
+            m_type = of_g.of_mixed_types[m_type][version]
+        # m_name = "value_" + of_g.of_base_types[m_type]["short_name"]
+        members.append(dict(name="type_len", m_type="uint32_t"))
+        # members.append(dict(name=m_name, m_type=oxm_types[oxm]))
+        members.append(dict(name="value", m_type=oxm_types[oxm]))
+        if oxm.find("_masked") > 0:
+            members.append(dict(name="value_mask", m_type=oxm_types[oxm]))
+            
+        name = "of_oxm_" + oxm
+        of_g.ordered_classes[version].append(name)
+        classes[name] = members
+        
+# /* Header for OXM experimenter match fields. */
+# struct ofp_oxm_experimenter_header {
+#     uint32_t oxm_header;        /* oxm_class = OFPXMC_EXPERIMENTER */
+#     uint32_t experimenter;      /* Experimenter ID which takes the same
+#                                    form as in struct ofp_experimenter_header. */
+# };
+
+
+# enum ofp_vlan_id {
+#     OFPVID_PRESENT = 0x1000, 
+#     OFPVID_NONE    = 0x0000, 
+# };
+
+# #define OFP_VLAN_NONE      OFPVID_NONE
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
new file mode 100644
index 0000000..6b0e1eb
--- /dev/null
+++ b/loxi_front_end/parser.py
@@ -0,0 +1,62 @@
+# 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.
+
+import pyparsing as P
+
+kw = P.Keyword
+s = P.Suppress
+lit = P.Literal
+
+# Useful for marking the type of a parse result (matches the empty string, but
+# shows up in the result)
+tag = lambda name: P.Empty().setParseAction(P.replaceWith(name))
+
+word = P.Word(P.alphanums + '_')
+
+identifier = word.copy().setName("identifier")
+
+# Type names
+scalar_type = word
+array_type = P.Combine(word + lit('[') - P.Word(P.alphanums + '_') - lit(']'))
+list_type = P.Combine(kw('list') - lit('(') - identifier - lit(')'))
+any_type = (array_type | list_type | scalar_type).setName("type name")
+
+# Structs
+struct_member = P.Group(any_type - identifier - s(';'))
+struct = kw('struct') - identifier - s('{') + \
+         P.Group(P.ZeroOrMore(struct_member)) + \
+         s('}') - s(';')
+
+# Metadata
+metadata_key = P.Or(kw("version")).setName("metadata key")
+metadata = tag('metadata') + s('#') - metadata_key - word
+
+grammar = P.ZeroOrMore(P.Group(struct) | P.Group(metadata))
+grammar.ignore(P.cppStyleComment)
+
+def parse(src):
+    return grammar.parseString(src, parseAll=True)
diff --git a/loxi_front_end/translation.py b/loxi_front_end/translation.py
new file mode 100644
index 0000000..6c39a3a
--- /dev/null
+++ b/loxi_front_end/translation.py
@@ -0,0 +1,126 @@
+# 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.
+
+##
+# @brief Translation data between openflow.h and LOXI
+#
+
+import re
+import sys
+        
+def loxi_name(ident):
+    """
+    Return the LOXI name of an openflow.h identifier
+    """
+
+    # Order at the outer level matters as super strings are listed first
+    rules = [
+# The following are for #define macros and have highest precedence
+        dict(OFP_MAX_TABLE_NAME_LEN = "OF_MAX_TABLE_NAME_LEN"),
+        dict(OFP_MAX_PORT_NAME_LEN = "OF_MAX_PORT_NAME_LEN"),
+        dict(OFP_TCP_PORT = "OF_TCP_PORT"),
+        dict(OFP_SSL_PORT = "OF_SSL_PORT"),
+        dict(OFP_ETH_ALEN = "OF_ETH_ALEN"),
+        dict(OFP_DEFAULT_MISS_SEND_LEN = "OF_DEFAULT_MISS_SEND_LEN"),
+        dict(OFP_VLAN_NONE = "OF_VLAN_UNTAGGED"),
+        dict(OFP_DL_TYPE_ETH2_CUTOFF = "OF_DL_TYPE_ETH2_CUTOFF"),
+        dict(OFP_DL_TYPE_NOT_ETH_TYPE = "OF_DL_TYPE_NOT_ETH_TYPE"),
+        dict(OFP_FLOW_PERMANENT = "OF_FLOW_PERMANENT"),
+        dict(OFP_DEFAULT_PRIORITY = "OF_DEFAULT_PRIORITY"),
+        dict(DESC_STR_LEN = "OF_DESC_STR_LEN"),
+        dict(SERIAL_NUM_LEN = "OF_SERIAL_NUM_LEN"),
+        dict(OFPQ_ALL = "OF_QUEUE_ALL"),
+        dict(OFPQ_MIN_RATE_UNCFG = "OF_QUEUE_MIN_RATE_UNCFG"),
+        dict(OFPQ_MAX_RATE_UNCFG = "OF_QUEUE_MAX_RATE_UNCFG"),
+        dict(OFP_NO_BUFFER = "OF_BUFFER_ID_NO_BUFFER"),
+
+# These are for enums; they map the prefixes
+        dict(OFPP_MAX = "OF_PORT_NUMBER_MAX"), # Special case
+        dict(OFPP_TABLE = "OF_PORT_DEST_USE_TABLE"), # Special case
+        dict(OFPP_ANY = "OF_PORT_DEST_WILDCARD"), # Special case
+        dict(OFPTC_ = "OF_TABLE_CONFIG_"),
+        dict(OFPIEH_ = "OF_IPV6_EXT_HDR_FLAG_"),
+        dict(OFPMBT_ = "OF_METER_BAND_TYPE_"),
+        dict(OFPMC_ = "OF_METER_MOD_COMMAND_"),
+        dict(OFPMF_ = "OF_METER_FLAG_"),
+        dict(OFPTFFC_ = "OF_TABLE_REQUEST_FAILED_"),
+        dict(OFPMMFC_ = "OF_METER_MOD_FAILED_"),
+        dict(OFPPR_ = "OF_PORT_CHANGE_REASON_"),
+        dict(OFPPMFC_ = "OF_PORT_MOD_FAILED_"),
+        dict(OFPP_ = "OF_PORT_DEST_"),
+        dict(OFPRRFC_ = "OF_ROLE_REQUEST_FAILED_"),
+        dict(OFPRR_ = "OF_FLOW_REMOVED_REASON_"),
+        dict(OFPR_ = "OF_PACKET_IN_REASON_"),
+        dict(OFPC_FRAG_ = "OF_CONFIG_FRAG_"),
+        dict(OFPC_INVALID_ = "OF_CONFIG_INVALID_"),
+        dict(OFPCML_ = "OF_CONTROLLER_PKT_"),
+        dict(OFPCR_ROLE_ = "OF_CONTROLLER_ROLE_"),
+        dict(OFPC_ = "OF_CAPABILITIES_FLAG_"),
+        dict(OFPPC_ = "OF_PORT_CONFIG_FLAG_"),
+        dict(OFPPS_ = "OF_PORT_STATE_FLAG_"),
+        dict(OFPPF_ = "OF_PORT_FEATURE_FLAG_"),
+        dict(OFPTT_ = "OF_TABLE_"),
+        dict(OFPT_ = "OF_OBJ_TYPE_"),
+        dict(OFPMT_ = "OF_MATCH_TYPE_"),
+        dict(OFPM_ = "OF_METER_"),
+        dict(OFPXMC_ = "OF_OXM_CLASS_"),
+        dict(OFPVID_ = "OF_VLAN_TAG_"),
+        dict(OFPGC_ = "OF_GROUP_"),
+        dict(OFPGT_ = "OF_GROUP_TYPE_"),
+        dict(OFPG_ = "OF_GROUP_"),
+        dict(OFPET_ = "OF_ERROR_TYPE_"),
+        dict(OFPFC_ = "OF_FLOW_MOD_COMMAND_"),
+        dict(OFPHFC_ = "OF_HELLO_FAILED_"),
+        dict(OFPBRC_ = "OF_REQUEST_FAILED_"),
+        dict(OFPBAC_ = "OF_ACTION_FAILED_"),
+        dict(OFPBIC_ = "OF_INSTRUCTION_FAILED_"),
+        dict(OFPBMC_ = "OF_MATCH_FAILED_"),
+        dict(OFPGMFC_ = "OF_GROUP_MOD_FAILED_"),
+        dict(OFPTMFC_ = "OF_TABLE_MOD_FAILED_"),
+        dict(OFPFMFC_ = "OF_FLOW_MOD_FAILED_"),
+        dict(OFPQOFC_ = "OF_QUEUE_OP_FAILED_"),
+        dict(OFPSCFC_ = "OF_SWITCH_CONFIG_FAILED_"),
+        dict(OFPQCFC_ = "OF_SWITCH_CONFIG_FAILED_"), # See EXT-208
+        dict(OFPAT_ = "OF_ACTION_TYPE_"),
+        dict(OFPFW_ = "OF_FLOW_WC_V1_"),
+        dict(OFPFF_ = "OF_FLOW_MOD_FLAG_"),
+        dict(OFPST_ = "OF_STATS_TYPE_"),
+        dict(OFPSF_ = "OF_STATS_REPLY_FLAG_"),
+        dict(OFPQT_ = "OF_QUEUE_PROPERTY_"),
+        dict(OFPIT_ = "OF_INSTRUCTION_TYPE_"),
+        dict(OFPGFC_ = "OF_GROUP_CAPABILITIES_"),
+        dict(OFPMP_ = "OF_MULTIPART_"),
+        dict(OFPMPF_ = "OF_MULTIPART_FLAG_"),
+        dict(OFPTFPT_ = "OF_TABLE_FEATURE_"),
+        ]
+
+    for entry in rules:
+        for id_from, id_to in entry.items():
+            if re.match(id_from, ident):
+                return re.sub(id_from, id_to, ident)
+    return None
+
diff --git a/loxi_front_end/type_maps.py b/loxi_front_end/type_maps.py
new file mode 100644
index 0000000..ecfd850
--- /dev/null
+++ b/loxi_front_end/type_maps.py
@@ -0,0 +1,1101 @@
+# 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.
+
+#
+# Miscellaneous type information
+#
+# Define the map between sub-class types and wire values.  In each
+# case, an array indexed by wire version gives a hash from identifier
+# to wire value.
+#
+
+import of_g
+import sys
+from generic_utils import *
+import oxm
+import loxi_utils.loxi_utils as loxi_utils
+
+invalid_type = "invalid_type"
+invalid_value = "0xeeee"  # Note, as a string
+
+################################################################
+#
+# Define type data for inheritance classes:
+#   instructions, actions, queue properties and OXM
+#
+# Messages are not in this group; they're treated specially for now
+#
+# These are indexed by wire protocol number
+#
+################################################################
+
+instruction_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        goto_table = 1,
+        write_metadata = 2,
+        write_actions = 3,
+        apply_actions = 4,
+        clear_actions = 5,
+        experimenter = 0xffff
+        ),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        goto_table = 1,
+        write_metadata = 2,
+        write_actions = 3,
+        apply_actions = 4,
+        clear_actions = 5,
+        experimenter = 0xffff
+        ),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        goto_table = 1,
+        write_metadata = 2,
+        write_actions = 3,
+        apply_actions = 4,
+        clear_actions = 5,
+        meter = 6,
+        experimenter = 0xffff
+        )
+    }
+
+of_1_3_action_types = dict(
+    output       = 0,
+    copy_ttl_out = 11,
+    copy_ttl_in  = 12,
+    set_mpls_ttl = 15,
+    dec_mpls_ttl = 16,
+    push_vlan    = 17,
+    pop_vlan     = 18,
+    push_mpls    = 19,
+    pop_mpls     = 20,
+    set_queue    = 21,
+    group        = 22,
+    set_nw_ttl   = 23,
+    dec_nw_ttl   = 24,
+    set_field    = 25,
+    push_pbb     = 26,
+    pop_pbb      = 27,
+    experimenter = 0xffff,
+    bsn_mirror = 0xffff,
+    bsn_set_tunnel_dst = 0xffff,
+    nicira_dec_ttl = 0xffff
+    )
+
+# Indexed by OF version
+action_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(
+        output = 0,
+        set_vlan_vid = 1,
+        set_vlan_pcp = 2,
+        strip_vlan = 3,
+        set_dl_src = 4,
+        set_dl_dst = 5,
+        set_nw_src = 6,
+        set_nw_dst = 7,
+        set_nw_tos = 8,
+        set_tp_src = 9,
+        set_tp_dst = 10,
+        enqueue = 11,
+        experimenter = 0xffff,
+        bsn_mirror = 0xffff,
+        bsn_set_tunnel_dst = 0xffff,
+        nicira_dec_ttl = 0xffff
+        ),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        output = 0,
+        set_vlan_vid = 1,
+        set_vlan_pcp = 2,
+        set_dl_src = 3,
+        set_dl_dst = 4,
+        set_nw_src = 5,
+        set_nw_dst = 6,
+        set_nw_tos = 7,
+        set_nw_ecn = 8,
+        set_tp_src = 9,
+        set_tp_dst = 10,
+        copy_ttl_out = 11,
+        copy_ttl_in = 12,
+        set_mpls_label = 13,
+        set_mpls_tc = 14,
+        set_mpls_ttl = 15,
+        dec_mpls_ttl = 16,
+        push_vlan = 17,
+        pop_vlan = 18,
+        push_mpls = 19,
+        pop_mpls = 20,
+        set_queue = 21,
+        group = 22,
+        set_nw_ttl = 23,
+        dec_nw_ttl = 24,
+        experimenter = 0xffff,
+        bsn_mirror = 0xffff,
+        bsn_set_tunnel_dst = 0xffff,
+        nicira_dec_ttl = 0xffff
+        ),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        output       = 0,
+        copy_ttl_out = 11,
+        copy_ttl_in  = 12,
+        set_mpls_ttl = 15,
+        dec_mpls_ttl = 16,
+        push_vlan    = 17,
+        pop_vlan     = 18,
+        push_mpls    = 19,
+        pop_mpls     = 20,
+        set_queue    = 21,
+        group        = 22,
+        set_nw_ttl   = 23,
+        dec_nw_ttl   = 24,
+        set_field    = 25,
+        experimenter = 0xffff,
+        bsn_mirror = 0xffff,
+        bsn_set_tunnel_dst = 0xffff,
+        nicira_dec_ttl = 0xffff
+        ),
+
+    # version 1.3
+    of_g.VERSION_1_3:of_1_3_action_types
+
+    }
+
+action_id_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:of_1_3_action_types
+    }
+
+queue_prop_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(
+        min_rate      = 1,
+        # experimenter  = 0xffff
+        ),
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        min_rate      = 1,
+        #  experimenter  = 0xffff
+        ),
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        min_rate      = 1,
+        max_rate      = 2,
+        experimenter  = 0xffff
+        ),
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        min_rate      = 1,
+        max_rate      = 2,
+        experimenter  = 0xffff
+        )
+    }
+
+oxm_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(),
+
+    # version 1.2
+    of_g.VERSION_1_2:oxm.oxm_wire_type,
+
+    # version 1.3
+    of_g.VERSION_1_3:oxm.oxm_wire_type  # FIXME needs update for 1.3?
+    }
+
+hello_elem_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        versionbitmap = 1
+        )
+    }
+
+table_feature_prop_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        instructions           = 0,
+        instructions_miss      = 1,
+        next_tables            = 2,
+        next_tables_miss       = 3,
+        write_actions          = 4,
+        write_actions_miss     = 5,
+        apply_actions          = 6,
+        apply_actions_miss     = 7,
+        match                  = 8,
+        wildcards              = 10,
+        write_setfield         = 12,
+        write_setfield_miss    = 13,
+        apply_setfield         = 14,
+        apply_setfield_miss    = 15,
+#        experimenter           = 0xFFFE,
+#        experimenter_miss      = 0xFFFF,
+        experimenter            = 0xFFFF,  # Wrong: should be experimenter_miss
+        )
+    }
+
+meter_band_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        drop                   = 1,
+        dscp_remark            = 2,
+        experimenter           = 0xFFFF,
+        )
+    }
+
+# All inheritance data for non-messages
+inheritance_data = dict(
+    of_instruction = instruction_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
+    )
+
+################################################################
+# Now generate the maps from parent to list of subclasses
+################################################################
+
+# # These lists have entries which are a fixed type, no inheritance
+# fixed_lists = [
+#     "of_list_bucket",
+#     "of_list_bucket_counter",
+#     "of_list_flow_stats_entry",
+#     "of_list_group_desc_stats_entry",
+#     "of_list_group_stats_entry",
+#     "of_list_packet_queue",
+#     "of_list_port_desc",
+#     "of_list_port_stats_entry",
+#     "of_list_queue_stats_entry",
+#     "of_list_table_stats_entry"
+#     ]
+
+# for cls in fixed_lists:
+#     base_type = list_to_entry_type(cls)
+#     of_g.inheritance_map[base_type] = [base_type]
+
+inheritance_map = dict()
+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 class_is_virtual(cls):
+    """
+    Returns True if cls is a virtual class
+    """
+    if cls in inheritance_map:
+        return True
+    if cls.find("header") > 0:
+        return True
+    if loxi_utils.class_is_list(cls):
+        return True
+    return False
+
+################################################################
+#
+# These are message types
+#
+################################################################
+
+message_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(
+        hello                   = 0,
+        error_msg               = 1,
+        echo_request            = 2,
+        echo_reply              = 3,
+        experimenter            = 4,
+        features_request        = 5,
+        features_reply          = 6,
+        get_config_request      = 7,
+        get_config_reply        = 8,
+        set_config              = 9,
+        packet_in               = 10,
+        flow_removed            = 11,
+        port_status             = 12,
+        packet_out              = 13,
+        flow_mod                = 14,
+        port_mod                = 15,
+        stats_request           = 16,
+        stats_reply             = 17,
+        barrier_request         = 18,
+        barrier_reply           = 19,
+        queue_get_config_request = 20,
+        queue_get_config_reply  = 21,
+        table_mod               = 22    # Unofficial 1.0 extension
+        ),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        hello                   = 0,
+        error_msg               = 1,
+        echo_request            = 2,
+        echo_reply              = 3,
+        experimenter            = 4,
+        features_request        = 5,
+        features_reply          = 6,
+        get_config_request      = 7,
+        get_config_reply        = 8,
+        set_config              = 9,
+        packet_in               = 10,
+        flow_removed            = 11,
+        port_status             = 12,
+        packet_out              = 13,
+        flow_mod                = 14,
+        group_mod               = 15,
+        port_mod                = 16,
+        table_mod               = 17,
+        stats_request           = 18,
+        stats_reply             = 19,
+        barrier_request         = 20,
+        barrier_reply           = 21,
+        queue_get_config_request = 22,
+        queue_get_config_reply  = 23
+        ),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        hello                   = 0,
+        error_msg               = 1,
+        echo_request            = 2,
+        echo_reply              = 3,
+        experimenter            = 4,
+        features_request        = 5,
+        features_reply          = 6,
+        get_config_request      = 7,
+        get_config_reply        = 8,
+        set_config              = 9,
+        packet_in               = 10,
+        flow_removed            = 11,
+        port_status             = 12,
+        packet_out              = 13,
+        flow_mod                = 14,
+        group_mod               = 15,
+        port_mod                = 16,
+        table_mod               = 17,
+        stats_request           = 18,
+        stats_reply             = 19,
+        barrier_request         = 20,
+        barrier_reply           = 21,
+        queue_get_config_request = 22,
+        queue_get_config_reply   = 23,
+        role_request            = 24,
+        role_reply              = 25,
+        ),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        hello                   = 0,
+        error_msg               = 1,
+        echo_request            = 2,
+        echo_reply              = 3,
+        experimenter            = 4,
+        features_request        = 5,
+        features_reply          = 6,
+        get_config_request      = 7,
+        get_config_reply        = 8,
+        set_config              = 9,
+        packet_in               = 10,
+        flow_removed            = 11,
+        port_status             = 12,
+        packet_out              = 13,
+        flow_mod                = 14,
+        group_mod               = 15,
+        port_mod                = 16,
+        table_mod               = 17,
+        stats_request           = 18,  # FIXME Multipart
+        stats_reply             = 19,
+        barrier_request         = 20,
+        barrier_reply           = 21,
+        queue_get_config_request = 22,
+        queue_get_config_reply   = 23,
+        role_request            = 24,
+        role_reply              = 25,
+        async_get_request       = 26,
+        async_get_reply         = 27,
+        async_set               = 28,
+        meter_mod               = 29
+        )
+    }
+
+################################################################
+#
+# These are other objects that have a notion of type but are
+# not (yet) promoted to objects with inheritance
+#
+################################################################
+
+stats_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(
+        desc = 0,
+        flow = 1,
+        aggregate = 2,
+        table = 3,
+        port = 4,
+        queue = 5,
+        experimenter = 0xffff
+        ),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        desc = 0,
+        flow = 1,
+        aggregate = 2,
+        table = 3,
+        port = 4,
+        queue = 5,
+        group = 6,
+        group_desc = 7,
+        experimenter = 0xffff
+        ),
+
+    # version 1.2
+        of_g.VERSION_1_2:dict(
+        desc = 0,
+        flow = 1,
+        aggregate = 2,
+        table = 3,
+        port = 4,
+        queue = 5,
+        group = 6,
+        group_desc = 7,
+        group_features = 8,
+        experimenter = 0xffff
+        ),
+
+    # version 1.3
+        of_g.VERSION_1_3:dict(
+        desc = 0,
+        flow = 1,
+        aggregate = 2,
+        table = 3,
+        port = 4,
+        queue = 5,
+        group = 6,
+        group_desc = 7,
+        group_features = 8,
+        meter = 9,
+        meter_config = 10,
+        meter_features = 11,
+        table_features = 12,
+        port_desc = 13,
+        experimenter = 0xffff
+        )
+    }
+
+common_flow_mod_types = dict(
+    add = 0,
+    modify = 1,
+    modify_strict = 2,
+    delete = 3,
+    delete_strict = 4
+    )
+
+flow_mod_types = {
+    # version 1.0
+    of_g.VERSION_1_0:common_flow_mod_types,
+    of_g.VERSION_1_1:common_flow_mod_types,
+    of_g.VERSION_1_2:common_flow_mod_types,
+    of_g.VERSION_1_3:common_flow_mod_types
+    }
+
+# These do not translate to objects (yet)
+error_types = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(
+        hello_failed        = 0,
+        bad_request         = 1,
+        bad_action          = 2,
+        flow_mod_failed     = 3,
+        port_mod_failed     = 4,
+        queue_op_failed     = 5
+        ),
+
+    # version 1.1
+    of_g.VERSION_1_1:dict(
+        hello_failed         = 0,
+        bad_request          = 1,
+        bad_action           = 2,
+        bad_instruction      = 3,
+        bad_match            = 4,
+        flow_mod_failed      = 5,
+        group_mod_failed     = 6,
+        port_mod_failed      = 7,
+        table_mod_failed     = 8,
+        queue_op_failed      = 9,
+        switch_config_failed = 10
+        ),
+
+    # version 1.2
+    of_g.VERSION_1_2:dict(
+        hello_failed         = 0,
+        bad_request          = 1,
+        bad_action           = 2,
+        bad_instruction      = 3,
+        bad_match            = 4,
+        flow_mod_failed      = 5,
+        group_mod_failed     = 6,
+        port_mod_failed      = 7,
+        table_mod_failed     = 8,
+        queue_op_failed      = 9,
+        switch_config_failed = 10,
+        role_request_failed  = 11,
+        experimenter = 0xffff
+        ),
+
+    # version 1.3
+    of_g.VERSION_1_3:dict(
+        hello_failed         = 0,
+        bad_request          = 1,
+        bad_action           = 2,
+        bad_instruction      = 3,
+        bad_match            = 4,
+        flow_mod_failed      = 5,
+        group_mod_failed     = 6,
+        port_mod_failed      = 7,
+        table_mod_failed     = 8,
+        queue_op_failed      = 9,
+        switch_config_failed = 10,
+        role_request_failed  = 11,
+        meter_mod_failed     = 12,
+        table_features_failed= 13,
+        experimenter = 0xffff
+        )
+    }
+
+##
+# These are the objects whose length is specified by an external
+# reference, specifically another data member in the class.
+# 
+#external_length_spec = {
+#    ("of_packet_out", "actions", OF_VERSION_1_0) : "actions_len",
+#    ("of_packet_out", "actions", OF_VERSION_1_1) : "actions_len",
+#    ("of_packet_out", "actions", OF_VERSION_1_2) : "actions_len",
+#    ("of_packet_out", "actions", OF_VERSION_1_3) : "actions_len"
+#}
+
+
+################################################################
+#
+# type_val is the primary data structure that maps an 
+# (class_name, version) pair to the wire data type value
+#
+################################################################
+
+type_val = dict()
+
+for version, classes in message_types.items():
+    for cls in classes:
+        name = "of_" + cls
+        type_val[(name, version)] = classes[cls]
+
+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
+
+# Special case OF-1.2 match type
+type_val[("of_match_v3", of_g.VERSION_1_2)] = 0x8000
+type_val[("of_match_v3", of_g.VERSION_1_3)] = 0x8000
+
+# Utility function
+def dict_to_array(d, m_val, def_val=-1):
+    """
+    Given a dictionary, d, with each value a small integer,
+    produce an array indexed by the integer whose value is the key.
+    @param d The dictionary
+    @param m_val Ignore values greater than m_val
+    @param def_val The default value (for indices not in range of d)
+    """
+
+    # Get the max value in range for hash
+    max_val = 0
+    for key in d:
+        if (d[key] > max_val) and (d[key] < m_val):
+            max_val = d[key]
+    ar = []
+    for x in range(0, max_val + 1):
+        ar.append(def_val)
+    for key in d:
+        if (d[key] < m_val):
+            ar[d[key]] = key
+    return ar
+
+def type_array_len(version_indexed, max_val):
+    """
+    Given versioned information about a type, calculate how long
+    the unified array should be.
+
+    @param version_indexed A dict indexed by version. Each value is a 
+    dict indexed by a name and whose value is an integer
+    @param max_val Ignore values greater than this for length calcs
+    """
+    # First, find the max length of all arrays
+    arr_len = 0
+    for version, val_dict in version_indexed.items():
+        ar = dict_to_array(val_dict, max_val, invalid_type)
+        if arr_len < len(ar):
+            arr_len = len(ar)
+    return arr_len
+
+# FIXME:  Need to move update for multipart messages
+
+stats_reply_list = [
+    "of_aggregate_stats_reply",
+    "of_desc_stats_reply",
+    "of_experimenter_stats_reply",
+    "of_flow_stats_reply",
+    "of_group_stats_reply",
+    "of_group_desc_stats_reply",
+    "of_group_features_stats_reply",
+    "of_meter_stats_reply",
+    "of_meter_config_stats_reply",
+    "of_meter_features_stats_reply",
+    "of_port_stats_reply",
+    "of_port_desc_stats_reply",
+    "of_queue_stats_reply",
+    "of_table_stats_reply",
+    "of_table_features_stats_reply"
+]
+
+stats_request_list = [
+    "of_aggregate_stats_request",
+    "of_desc_stats_request",
+    "of_experimenter_stats_request",
+    "of_flow_stats_request",
+    "of_group_stats_request",
+    "of_group_desc_stats_request",
+    "of_group_features_stats_request",
+    "of_meter_stats_request",
+    "of_meter_config_stats_request",
+    "of_meter_features_stats_request",
+    "of_port_stats_request",
+    "of_port_desc_stats_request",
+    "of_queue_stats_request",
+    "of_table_stats_request",
+    "of_table_features_stats_request"
+]
+
+flow_mod_list = [
+    "of_flow_add",
+    "of_flow_modify",
+    "of_flow_modify_strict",
+    "of_flow_delete",
+    "of_flow_delete_strict"
+]
+
+def sub_class_map(base_type, version):
+    """
+    Returns an iterable object giving the instance nameys and subclass types
+    for the base_type, version values
+    """
+    rv = []
+    if base_type not in inheritance_map:
+        return rv
+
+    for instance in inheritance_map[base_type]:
+        subcls = loxi_utils.instance_to_class(instance, base_type)
+        if not loxi_utils.class_in_version(subcls, version):
+            continue
+        rv.append((instance, subcls))
+
+    return rv
+
+################################################################
+#
+# Extension related data and functions
+#
+################################################################
+
+# Per OF Version, per experimenter, map exp msg type (subtype) to object IDs
+# @fixme Generate defines for OF_<exp>_SUBTYPE_<msg> for the values below?
+extension_message_subtype = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(  # Version 1.0 extensions
+        bsn = {   # BSN extensions; indexed by class name, value is subtype
+            "of_bsn_set_ip_mask"             : 0,
+            "of_bsn_get_ip_mask_request"     : 1,
+            "of_bsn_get_ip_mask_reply"       : 2,
+            "of_bsn_set_mirroring"           : 3,
+            "of_bsn_get_mirroring_request"   : 4,
+            "of_bsn_get_mirroring_reply"     : 5,
+            "of_bsn_shell_command"           : 6,
+            "of_bsn_shell_output"            : 7,
+            "of_bsn_shell_status"            : 8,
+            "of_bsn_get_interfaces_request"  : 9,
+            "of_bsn_get_interfaces_reply"    : 10,
+            },
+        nicira = {   # Nicira extensions, value is subtype
+            "of_nicira_controller_role_request"      : 10,
+            "of_nicira_controller_role_reply"        : 11,
+            },
+        ),
+    of_g.VERSION_1_1:dict(  # Version 1.0 extensions
+        bsn = {   # BSN extensions; indexed by class name, value is subtype
+            "of_bsn_set_mirroring"           : 3,
+            "of_bsn_get_mirroring_request"   : 4,
+            "of_bsn_get_mirroring_reply"     : 5,
+            "of_bsn_get_interfaces_request"  : 9,
+            "of_bsn_get_interfaces_reply"    : 10,
+            },
+        ),
+    of_g.VERSION_1_2:dict(  # Version 1.0 extensions
+        bsn = {   # BSN extensions; indexed by class name, value is subtype
+            "of_bsn_set_mirroring"           : 3,
+            "of_bsn_get_mirroring_request"   : 4,
+            "of_bsn_get_mirroring_reply"     : 5,
+            "of_bsn_get_interfaces_request"  : 9,
+            "of_bsn_get_interfaces_reply"    : 10,
+            },
+        ),
+    of_g.VERSION_1_3:dict(  # Version 1.0 extensions
+        bsn = {   # BSN extensions; indexed by class name, value is subtype
+            "of_bsn_set_mirroring"           : 3,
+            "of_bsn_get_mirroring_request"   : 4,
+            "of_bsn_get_mirroring_reply"     : 5,
+            "of_bsn_get_interfaces_request"  : 9,
+            "of_bsn_get_interfaces_reply"    : 10,
+            },
+        ),
+}
+
+# Set to empty dict if no extension actions defined
+# Per OF Version, per experimenter, map actions to subtype
+extension_action_subtype = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(  # Version 1.0 extensions
+        bsn = {   # of_action_bsn_
+            "of_action_bsn_mirror"           : 1,
+            "of_action_bsn_set_tunnel_dst"   : 2,
+            },
+        nicira = {   # of_action_nicira_
+            "of_action_nicira_dec_ttl"       : 18,
+            }
+        ),
+    of_g.VERSION_1_1:dict(  # Version 1.0 extensions
+        bsn = {   # of_action_bsn_
+            "of_action_bsn_mirror"           : 1,
+            "of_action_bsn_set_tunnel_dst"   : 2,
+            },
+        nicira = {   # of_action_nicira_
+            "of_action_nicira_dec_ttl"       : 18,
+            }
+        ),
+    of_g.VERSION_1_2:dict(  # Version 1.0 extensions
+        bsn = {   # of_action_bsn_
+            "of_action_bsn_mirror"           : 1,
+            "of_action_bsn_set_tunnel_dst"   : 2,
+            },
+        nicira = {   # of_action_nicira_
+            "of_action_nicira_dec_ttl"       : 18,
+            }
+        ),
+    of_g.VERSION_1_3:dict(  # Version 1.0 extensions
+        bsn = {   # of_action_bsn_
+            "of_action_bsn_mirror"           : 1,
+            "of_action_bsn_set_tunnel_dst"   : 2,
+            },
+        nicira = {   # of_action_nicira_
+            "of_action_nicira_dec_ttl"       : 18,
+            }
+        ),
+}
+
+# Set to empty dict if no extension actions defined
+# Per OF Version, per experimenter, map actions to subtype
+extension_action_id_subtype = {
+    # version 1.0
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(  # Version 1.3 extensions
+        bsn = {   # of_action_bsn_
+            "of_action_id_bsn_mirror"           : 1,
+            "of_action_id_bsn_set_tunnel_dst"   : 2,
+            },
+        nicira = {   # of_action_nicira_
+            "of_action_id_nicira_dec_ttl"       : 18,
+            }
+        ),
+}
+
+# Set to empty dict if no extension instructions defined
+extension_instruction_subtype = {}
+
+# Set to empty dict if no extension instructions defined
+extension_queue_prop_subtype = {}
+
+# Set to empty dict if no extension instructions defined
+extension_table_feature_prop_subtype = {}
+
+extension_objects = [
+    extension_message_subtype,
+    extension_action_subtype,
+    extension_action_id_subtype,
+    extension_instruction_subtype,
+    extension_queue_prop_subtype,
+    extension_table_feature_prop_subtype
+]
+
+################################################################
+# These are extension type generic (for messages, actions...)
+################################################################
+
+def extension_to_experimenter_name(cls):
+    """
+    Return the name of the experimenter if class is an
+    extension, else None
+
+    This is brute force; we search all extension data for a match
+    """
+    
+    for ext_obj in extension_objects:
+        for version, exp_list in ext_obj.items():
+            for exp_name, classes in exp_list.items():
+                if cls in classes:
+                    return exp_name
+    return None
+
+def extension_to_experimenter_id(cls):
+    """
+    Return the ID of the experimenter if class is an
+    extension, else None
+    """
+    exp_name = extension_to_experimenter_name(cls)
+    if exp_name:
+        return of_g.experimenter_name_to_id[exp_name]
+    return None
+
+def extension_to_experimenter_macro_name(cls):
+    """
+    Return the "macro name" of the ID of the experimenter if class is an
+    extension, else None
+    """
+    exp_name = extension_to_experimenter_name(cls)
+    if exp_name:
+        return "OF_EXPERIMENTER_ID_" + exp_name.upper()
+    return None
+
+def extension_to_subtype(cls, version):
+    """
+    Generic across all extension objects, return subtype identifier
+    """
+    for ext_obj in extension_objects:
+        for version, exp_list in ext_obj.items():
+            for exp_name, classes in exp_list.items():
+                if cls in classes:
+                    return classes[cls]
+
+def class_is_extension(cls, version):
+    """
+    Return True if class, version is recognized as an extension
+    of any type (message, action....)
+
+    Accepts of_g.OF_VERSION_ANY
+    """
+
+    for ext_obj in extension_objects:
+        if cls_is_ext_obj(cls, version, ext_obj):
+            return True
+
+    return False
+
+# Internal
+def cls_is_ext_obj(cls, version, ext_obj):
+    """
+    @brief Return True if cls in an extension of type ext_obj
+    @param cls The class to check
+    @param version The version to check
+    @param ext_obj The extension object dictionary (messages, actions...)
+
+    Accepts of_g.VERSION_ANY
+    """
+
+    # Call with each version if "any" is passed
+    if version == of_g.VERSION_ANY:
+        for v in of_g.of_version_range:
+            if cls_is_ext_obj(cls, v, ext_obj):
+                return True
+    else:   # Version specified
+        if version in ext_obj:
+            for exp, subtype_vals in ext_obj[version].items():
+                if cls in subtype_vals:
+                    return True
+
+    return False
+    
+################################################################
+# These are extension message specific
+################################################################
+
+def message_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an  extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version, extension_message_subtype)
+
+def extension_message_to_subtype(cls, version):
+    """
+    Return the subtype of the experimenter message if the class is an
+    extension, else None
+    """
+    if version in extension_message_subtype:
+        for exp, classes in extension_message_subtype[version].items():
+            for ext_class, subtype in classes.items():
+                if cls == ext_class:
+                    return subtype
+    return None
+
+################################################################
+# These are extension action specific
+################################################################
+
+def action_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an action extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version, extension_action_subtype)
+
+def extension_action_to_subtype(cls, version):
+    """
+    Return the ID of the action subtype (for its experimenteer)
+    if class is an action extension, else None
+    """
+    if version in extension_action_subtype:
+        for exp, classes in extension_action_subtype[version].items():
+            if cls in classes:
+                return classes[cls]
+
+    return None
+
+################################################################
+# These are extension action specific
+################################################################
+
+def action_id_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an action ID extension
+    This is brute force, searching records for a match
+    """
+    if version not in [of_g.VERSION_1_3]: # Action IDs only 1.3
+        return False
+    return cls_is_ext_obj(cls, version, extension_action_id_subtype)
+
+def extension_action_id_to_subtype(cls, version):
+    """
+    Return the ID of the action ID subtype (for its experimenteer)
+    if class is an action ID extension, else None
+    """
+    if version in extension_action_id_subtype:
+        for exp, classes in extension_action_id_subtype[version].items():
+            if cls in classes:
+                return classes[cls]
+
+    return None
+
+################################################################
+# These are extension instruction specific
+################################################################
+
+def instruction_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an instruction extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version, extension_instruction_subtype)
+
+################################################################
+# These are extension queue_prop specific
+################################################################
+
+def queue_prop_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an instruction extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version, extension_queue_prop_subtype)
+
+################################################################
+# These are extension table_feature_prop specific
+################################################################
+
+def table_feature_prop_is_extension(cls, version):
+    """
+    Return True if cls, version is recognized as an instruction extension
+    This is brute force, searching records for a match
+    """
+    return cls_is_ext_obj(cls, version,
+                          extension_table_feature_prop_subtype)