Merge branch 'master' of github.com:floodlight/loxigen
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index 3dff5a5..270a6ba 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -288,6 +288,7 @@
     OF_OXM_INDEX_MPLS_TC        = 35, /* MPLS TC. */
 
     OF_OXM_INDEX_BSN_IN_PORTS_128 = 36,
+    OF_OXM_INDEX_BSN_LAG_ID = 37,
 };
 
 #define OF_OXM_BIT(index) (((uint64_t) 1) << (index))
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 9644fdb..ab4b3e0 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -75,7 +75,8 @@
                 out.write("    %d%s /* %s */\n" %
                           (type_maps.type_val[("of_flow_mod", version)],
                            comma, cls))
-            elif (cls, version) in type_maps.type_val:
+            elif (cls, version) in type_maps.type_val and \
+                    type_maps.type_val[(cls, version)] != type_maps.invalid_type:
                 out.write("    %d%s /* %s */\n" %
                           (type_maps.type_val[(cls, version)], comma, cls))
             elif type_maps.message_is_extension(cls, version):
@@ -597,6 +598,8 @@
         switch (masked_type) {
         case 0x00: return OF_OXM_BSN_IN_PORTS_128;
         case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
+        case 0x02: return OF_OXM_BSN_LAG_ID;
+        case 0x03: return OF_OXM_BSN_LAG_ID_MASKED;
         default: return OF_OBJECT_INVALID;
         }
     } else {
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index 215e65a..de96a4b 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -345,5 +345,6 @@
 #define LOCI_SHOW_u32_timeout_ms(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 #define LOCI_SHOW_u32_tx_interval_ms(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 #define LOCI_SHOW_u8_slot_num(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u32_bsn_lag_id(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 67c3535..df49492 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -590,6 +590,12 @@
     case OF_OXM_BSN_IN_PORTS_128_MASKED:
         type_len = 0x00030100 | (type_len & 0xff);
         break;
+    case OF_OXM_BSN_LAG_ID:
+        type_len = 0x00030200 | (type_len & 0xff);
+        break;
+    case OF_OXM_BSN_LAG_ID_MASKED:
+        type_len = 0x00030300 | (type_len & 0xff);
+        break;
     default:
         wire_type = of_object_to_wire_type(id, obj->version);
         ASSERT(wire_type >= 0);
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 4971d02..2ffec92 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -140,7 +140,9 @@
                 "OFOxmMplsTc":              OxmMapEntry("U8", "MPLS_TC", False),
                 "OFOxmMplsTcMasked":        OxmMapEntry("U8", "MPLS_TC", True),
                 "OFOxmBsnInPorts128":       OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
-                "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True)
+                "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
+                "OFOxmBsnLagId":            OxmMapEntry("LagId", "BSN_LAG_ID", False),
+                "OFOxmBsnLagIdMasked":      OxmMapEntry("LagId", "BSN_LAG_ID", True),
                 }
 
     # Registry of nullable properties:
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 331aeea..0bae34a 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -462,6 +462,8 @@
          .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ANY")
 buffer_id = JType("OFBufferId") \
          .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
+lag_id = JType("LagId") \
+         .op(version=ANY, read="LagId.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="LagId.NONE")
 
 generic_t = JType("T")
 
@@ -552,6 +554,9 @@
         'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
         'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
 
+        'of_oxm_bsn_lag_id' : { 'value' : lag_id },
+        'of_oxm_bsn_lag_id_masked' : { 'value' : lag_id, 'value_mask' : lag_id },
+
         'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
         'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
                 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
index 34d6946..574cb55 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
@@ -10,6 +10,7 @@
 import org.projectfloodlight.openflow.types.IpDscp;
 import org.projectfloodlight.openflow.types.IpEcn;
 import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.LagId;
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFBitMask128;
 import org.projectfloodlight.openflow.types.OFMetadata;
@@ -174,6 +175,9 @@
     public final static MatchField<OFBitMask128> BSN_IN_PORTS_128 =
             new MatchField<OFBitMask128>("bsn_in_port_masked_128", MatchFields.BSN_IN_PORTS_128);
 
+    public final static MatchField<LagId> BSN_LAG_ID =
+            new MatchField<LagId>("bsn_lag_id", MatchFields.BSN_LAG_ID);
+
     public String getName() {
         return name;
     }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
index 0de5caf..e41f786 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
@@ -38,5 +38,6 @@
     IPV6_ND_TLL,
     MPLS_LABEL,
     MPLS_TC,
-    BSN_IN_PORTS_128
+    BSN_IN_PORTS_128,
+    BSN_LAG_ID,
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
index 2046d71..6d9421a 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
@@ -12,6 +12,9 @@
     static final int LENGTH = 4;
     private final int rawValue;
 
+    private final static int NONE_VAL = 0;
+    public final static LagId NONE = new LagId(NONE_VAL);
+
     private LagId(final int rawValue) {
         this.rawValue = rawValue;
     }
diff --git a/loxi_front_end/match.py b/loxi_front_end/match.py
index f580354..c0e5188 100644
--- a/loxi_front_end/match.py
+++ b/loxi_front_end/match.py
@@ -405,6 +405,15 @@
         takes_mask_in_spec=True,
         order=1000,
         ),
+
+    bsn_lag_id = dict(
+        name="bsn_lag_id",
+        m_type="uint32_t",
+        print_type="PRIu32",
+        conditions="",
+        takes_mask_in_spec=False,
+        order=1001,
+        ),
 )
 
 match_keys_sorted = of_match_members.keys()
diff --git a/loxigen.py b/loxigen.py
index f756dc0..05dd6b5 100755
--- a/loxigen.py
+++ b/loxigen.py
@@ -499,7 +499,13 @@
             if not (parent and subcls):
                 continue
             if parent == 'of_oxm':
-                val = (find_type_value(ofclass, 'type_len') >> 8) & 0xff
+                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
diff --git a/openflow_input/bsn_lag_id b/openflow_input/bsn_lag_id
new file mode 100644
index 0000000..c96c1d6
--- /dev/null
+++ b/openflow_input/bsn_lag_id
@@ -0,0 +1,47 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 3
+#version 4
+
+/*
+ * Ingress LAG ID for SwitchLight
+ */
+
+struct of_oxm_bsn_lag_id : of_oxm {
+    uint32_t type_len == 0x00030204;
+    uint32_t value;
+};
+
+struct of_oxm_bsn_lag_id_masked : of_oxm {
+    uint32_t type_len == 0x00030304;
+    uint32_t value;
+    uint32_t value_mask;
+};
diff --git a/test_data/of13/action_set_field__bsn_lag_id.data b/test_data/of13/action_set_field__bsn_lag_id.data
new file mode 100644
index 0000000..f1a8aa1
--- /dev/null
+++ b/test_data/of13/action_set_field__bsn_lag_id.data
@@ -0,0 +1,11 @@
+-- binary
+00 19 # type
+00 10 # length
+00 03 02 04 # OXM header
+12 34 56 78 # OXM value
+00 00 00 00 # pad
+-- python
+ofp.action.set_field(field=ofp.oxm.bsn_lag_id(0x12345678))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.bsnLagId(LagId.of(0x12345678)))
diff --git a/test_data/of13/oxm_bsn_lag_id.data b/test_data/of13/oxm_bsn_lag_id.data
new file mode 100644
index 0000000..e8b2fcd
--- /dev/null
+++ b/test_data/of13/oxm_bsn_lag_id.data
@@ -0,0 +1,12 @@
+-- binary
+00 03 # class
+02 # type/masked
+04 # length
+12 34 56 78 # value
+-- python
+ofp.oxm.bsn_lag_id(0x12345678)
+-- c
+obj = of_oxm_bsn_lag_id_new(OF_VERSION_1_3);
+of_oxm_bsn_lag_id_value_set(obj, 0x12345678);
+-- java
+builder.setValue(LagId.of(0x12345678))
diff --git a/wireshark_gen/__init__.py b/wireshark_gen/__init__.py
index b4135ea..c4ff7f4 100644
--- a/wireshark_gen/__init__.py
+++ b/wireshark_gen/__init__.py
@@ -35,7 +35,7 @@
 
 templates_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
 
-DissectorField = namedtuple("DissectorField", ["fullname", "name", "type", "base"])
+DissectorField = namedtuple("DissectorField", ["fullname", "name", "type", "base", "enum_table"])
 
 proto_names = { 1: 'of10', 2: 'of11', 3: 'of12', 4: 'of13' }
 def make_field_name(wire_version, ofclass_name, member_name):
@@ -43,6 +43,17 @@
                          ofclass_name[3:],
                          member_name)
 
+def get_reader(version, cls, m):
+    """
+    Decide on a reader function to use for the given field
+    """
+    ofproto = of_g.ir[version]
+    enum = ofproto.enum_by_name(m.oftype)
+    if enum and 'wire_type' in enum.params:
+        return "read_" + enum.params['wire_type']
+    else:
+        return "read_" + m.oftype.replace(')', '').replace('(', '_')
+
 def get_field_info(version, cls, name, oftype):
     """
     Decide on a Wireshark type and base for a given field.
@@ -50,10 +61,14 @@
     Returns (type, base)
     """
     if oftype.startswith("list"):
-        return "bytes", "NONE"
+        return "bytes", "NONE", "nil"
 
     ofproto = of_g.ir[version]
+
     enum = ofproto.enum_by_name(oftype)
+    if not enum and (cls, name) in field_info.class_field_to_enum:
+        enum_name = field_info.class_field_to_enum[(cls, name)]
+        enum = ofproto.enum_by_name(enum_name)
 
     if enum:
         field_type = "uint32"
@@ -76,7 +91,12 @@
         print "WARN missing oftype_to_base for", oftype
         field_base = "NONE"
 
-    return field_type, field_base
+    if enum:
+        enum_table = 'enum_v%d_%s' % (version, enum.name)
+    else:
+        enum_table = 'nil'
+
+    return field_type, field_base, enum_table
 
 def create_fields():
     r = []
@@ -86,8 +106,8 @@
                 if isinstance(m, OFPadMember):
                     continue
                 fullname = make_field_name(wire_version, ofclass.name, m.name)
-                field_type, field_base = get_field_info(wire_version, ofclass.name, m.name, m.oftype)
-                r.append(DissectorField(fullname, m.name, field_type, field_base))
+                field_type, field_base, enum_table = get_field_info(wire_version, ofclass.name, m.name, m.oftype)
+                r.append(DissectorField(fullname, m.name, field_type, field_base, enum_table))
 
     return r
 
diff --git a/wireshark_gen/field_info.py b/wireshark_gen/field_info.py
index 167ff32..28f4cdb 100644
--- a/wireshark_gen/field_info.py
+++ b/wireshark_gen/field_info.py
@@ -81,6 +81,38 @@
     "of_bitmap_128_t": "NONE",
 }
 
+# Use enums for certain fields where it isn't specified in the LOXI input
+class_field_to_enum = {
+    ('of_flow_mod', 'type'): 'ofp_type',
+    ('of_error_msg', 'type'): 'ofp_type',
+    ('of_stats_request', 'type'): 'ofp_type',
+    ('of_stats_request', 'stats_type'): 'ofp_stats_type',
+    ('of_stats_request', 'flags'): 'ofp_stats_request_flags',
+    ('of_stats_reply', 'type'): 'ofp_type',
+    ('of_stats_reply', 'stats_type'): 'ofp_stats_type',
+    ('of_stats_reply', 'flags'): 'ofp_stats_reply_flags',
+    ('of_flow_mod', 'table_id'): 'ofp_table',
+    ('of_flow_mod', '_command'): 'ofp_flow_mod_command',
+    ('of_flow_mod', 'out_port'): 'ofp_port',
+    ('of_flow_mod', 'out_group'): 'ofp_group',
+    ('of_error_msg', 'err_type'): 'ofp_error_type',
+    ('of_port_mod', 'type'): 'ofp_type',
+    ('of_hello', 'type'): 'ofp_type',
+    ('of_features_request', 'type'): 'ofp_type',
+    ('of_features_reply', 'type'): 'ofp_type',
+    ('of_barrier_request', 'type'): 'ofp_type',
+    ('of_barrier_reply', 'type'): 'ofp_type',
+    ('of_echo_request', 'type'): 'ofp_type',
+    ('of_echo_reply', 'type'): 'ofp_type',
+    ('of_match_v3', 'type'): 'ofp_match_type',
+    ('of_action_set_nw_ttl', 'type'): 'ofp_action_type',
+    ('of_action_output', 'type'): 'ofp_action_type',
+    ('of_action_group', 'type'): 'ofp_action_type',
+    ('of_action_id', 'type'): 'ofp_action_type',
+    ('of_instruction_apply_actions', 'type'): 'ofp_instruction_type',
+    ('of_instruction_write_actions', 'type'): 'ofp_instruction_type',
+}
+
 # Override oftype_to_base for certain field names
 field_to_base = {
     "eth_type": "HEX",
diff --git a/wireshark_gen/templates/_ofclass_dissector.lua b/wireshark_gen/templates/_ofclass_dissector.lua
index f1c81b0..4aef886 100644
--- a/wireshark_gen/templates/_ofclass_dissector.lua
+++ b/wireshark_gen/templates/_ofclass_dissector.lua
@@ -26,7 +26,7 @@
 :: # under the EPL.
 ::
 :: from loxi_ir import *
-:: from wireshark_gen import make_field_name
+:: from wireshark_gen import make_field_name, get_reader
 :: attrs = []
 :: if ofclass.virtual: attrs.append("virtual")
 :: if ofclass.superclass: attrs.append("child")
@@ -45,7 +45,7 @@
 :: continue
 :: #endif
 :: field_name = make_field_name(version, ofclass.name, m.name)
-:: reader_name = "read_" + m.oftype.replace(')', '').replace('(', '_')
+:: reader_name = get_reader(version, ofclass, m)
     ${reader_name}(reader, ${version}, subtree, '${field_name}')
 :: #endfor
     return '${ofclass.name}'
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index 1db9f1f..c258953 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -89,6 +89,10 @@
     read_scalar(reader, subtree, field_name, 4)
 end
 
+function read_of_ipv6_t(reader, version, subtree, field_name)
+    read_scalar(reader, subtree, field_name, 16)
+end
+
 function read_of_fm_cmd_t(reader, version, subtree, field_name)
     if version == 1 then
         read_scalar(reader, subtree, field_name, 2)
@@ -97,10 +101,6 @@
     end
 end
 
-function read_ofp_flow_mod_flags(reader, version, subtree, field_name)
-    read_scalar(reader, subtree, field_name, 2)
-end
-
 function read_list_of_action_t(reader, version, subtree, field_name)
     if reader.is_empty() then
         return
@@ -111,9 +111,10 @@
         local action_len = reader.peek(2, 2):uint()
         local child_reader = reader.slice(action_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_action_v1(child_reader, child_subtree)
+        local info = dissect_of_action(child_reader, child_subtree, version)
         child_subtree:set_text(info)
     end
+    list:set_text("List of actions")
 end
 
 function read_list_of_port_desc_t(reader, version, subtree, field_name)
@@ -130,14 +131,19 @@
     end
     local list_len = reader.peek(-2,2):uint()
     local reader2 = reader.slice(list_len - 4)
-    local list = subtree:add(fields[field_name], reader2.peek_all(0))
+    local list = nil
+    if not reader2.is_empty() then
+        list = subtree:add(fields[field_name], reader2.peek_all(0))
+    end
     while not reader2.is_empty() do
         local match_len = 4 + reader2.peek(3,1):uint()
         local child_reader = reader2.slice(match_len)
         local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = dissect_of_oxm_v3(child_reader, child_subtree)
+        local info = dissect_of_oxm(child_reader, child_subtree, version)
         child_subtree:set_text(info)
     end
+    subtree:set_text("OXM")
+    list:set_text("List of matches")
     reader.skip_align()
 end
 
@@ -145,7 +151,7 @@
     if reader.is_empty() then
         return
     end
-    if not reader.is_empty() then
-        subtree:add(fields[field_name], reader.read_all())
-    end
+    local child_subtree = subtree:add(fields[field_name], reader.peek_all(0))
+    local info = dissect_of_instruction(reader, child_subtree, version)
+    child_subtree:set_text("Instructions")
 end
diff --git a/wireshark_gen/templates/openflow.lua b/wireshark_gen/templates/openflow.lua
index bf1cdf5..067dbdd 100644
--- a/wireshark_gen/templates/openflow.lua
+++ b/wireshark_gen/templates/openflow.lua
@@ -54,40 +54,10 @@
 :: #endfor
 
 
-:: values = {
-::     'of13.flow_mod.type': 'enum_v4_ofp_type',
-::     'of13.error_msg.type': 'enum_v4_ofp_type',
-::     'of13.stats_request.type': 'enum_v4_ofp_type',
-::     'of13.stats_request.stats_type': 'enum_v4_ofp_stats_type',
-::     'of13.stats_request.flags': 'enum_v4_ofp_stats_request_flags',
-::     'of13.stats_reply.type': 'enum_v4_ofp_type',
-::     'of13.stats_reply.stats_type': 'enum_v4_ofp_stats_type',
-::     'of13.stats_reply.flags': 'enum_v4_ofp_stats_reply_flags',
-::     'of13.flow_mod.table_id': 'enum_v4_ofp_table',
-::     'of13.flow_mod._command': 'enum_v4_ofp_flow_mod_command',
-::     'of13.flow_mod.out_port': 'enum_v4_ofp_port',
-::     'of13.flow_mod.out_group': 'enum_v4_ofp_group',
-::     'of13.error_msg.err_type': 'enum_v4_ofp_error_type',
-::     'of13.port_mod.type': 'enum_v4_ofp_type',
-::     'of13.hello.type': 'enum_v4_ofp_type',
-::     'of13.features_request.type': 'enum_v4_ofp_type',
-::     'of13.features_reply.type': 'enum_v4_ofp_type',
-::     'of13.barrier_request.type': 'enum_v4_ofp_type',
-::     'of13.barrier_reply.type': 'enum_v4_ofp_type',
-::     'of13.echo_request.type': 'enum_v4_ofp_type',
-::     'of13.echo_reply.type': 'enum_v4_ofp_type',
-::     'of13.match_t.type': 'enum_v4_ofp_match_type'
-:: }
-
-
 fields = {}
 :: for field in fields:
 :: if field.type in ["uint8", "uint16", "uint32", "uint64"]:
-:: if field.fullname in values:
-fields[${repr(field.fullname)}] = ProtoField.${field.type}("${field.fullname}", "${field.name}", base.${field.base}, ${values[field.fullname]})
-:: else:
-fields[${repr(field.fullname)}] = ProtoField.${field.type}("${field.fullname}", "${field.name}", base.${field.base})
-:: #endif
+fields[${repr(field.fullname)}] = ProtoField.${field.type}("${field.fullname}", "${field.name}", base.${field.base}, ${field.enum_table})
 :: elif field.type in ["ipv4", "ipv6", "ether", "bytes", "stringz"]:
 fields[${repr(field.fullname)}] = ProtoField.${field.type}("${field.fullname}", "${field.name}")
 :: else:
@@ -131,6 +101,24 @@
 :: #endfor
 }
 
+local of_oxm_dissectors = {
+:: for version in ir:
+    [${version}] = of_oxm_v${version}_dissectors,
+:: #endfor
+}
+
+local of_action_dissectors = {
+:: for version in ir:
+    [${version}] = of_action_v${version}_dissectors,
+:: #endfor
+}
+
+local of_instruction_dissectors = {
+:: for version in ir:
+    [${version}] = of_instruction_v${version}_dissectors,
+:: #endfor
+}
+
 function dissect_of_message(buf, root)
     local reader = OFReader.new(buf)
     local subtree = root:add(p_of, buf(0))
@@ -150,16 +138,36 @@
     return protocol, info
 end
 
-function dissect_of_oxm_v3(reader, subtree)
+function dissect_of_oxm(reader, subtree, version_val)
     local type_val = reader.peek(0,4):uint()
-
     local info = "unknown"
-    if of_oxm_v3_dissectors[type_val] then
-        info = of_oxm_v3_dissectors[type_val](reader, subtree)
+    if of_oxm_dissectors[version_val] and of_oxm_dissectors[version_val][type_val] then
+        info = of_oxm_dissectors[version_val][type_val](reader, subtree)
     end
 
     return info
 end
+
+function dissect_of_action(reader, subtree, version_val)
+    local type_val = reader.peek(0,2):uint()
+    local info = "unknown"
+    if of_action_dissectors[version_val] and of_action_dissectors[version_val][type_val] then
+        info = of_action_dissectors[version_val][type_val](reader, subtree)
+    end
+
+    return info
+end
+
+function dissect_of_instruction(reader, subtree, version_val)
+    local type_val = reader.peek(0,2):uint()
+    local info = "unknown"
+    if of_instruction_dissectors[version_val] and of_instruction_dissectors[version_val][type_val] then
+        info = of_instruction_dissectors[version_val][type_val](reader, subtree)
+    end
+
+    return info
+end
+
 -- of dissector function
 function p_of.dissector (buf, pkt, root)
     local offset = 0