Merge remote-tracking branch 'origin/master' into loci-split

Conflicts:
	c_gen/codegen.py
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index 2bc62ca..3249747 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -62,7 +62,7 @@
                     # Special case for version
                     pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, "obj->version"))
                 else:
-                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, m.value))
+                    pwtms.append(PushWireTypesMember(m.name, m.offset, m.length, hex(m.value)))
         type_members_by_version[version] = pwtms
 
     # Merge versions with identical type members
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index 3d55da8..a66c321 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -371,5 +371,7 @@
 #define LOCI_SHOW_u16_partner_port_num(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
 #define LOCI_SHOW_u16_partner_key(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
 #define LOCI_SHOW_u64_time_ms(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
+#define LOCI_SHOW_desc_str_uri(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
+#define LOCI_SHOW_u8_state(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/loxi_ir/ir.py b/loxi_ir/ir.py
index 6fae92b..6a053c6 100644
--- a/loxi_ir/ir.py
+++ b/loxi_ir/ir.py
@@ -176,6 +176,10 @@
             raise Exception("Not a fixed length class: {}".format(self.name))
 
     @property
+    def length_member(self):
+        return find(lambda m: type(m) == OFLengthMember, self.members)
+
+    @property
     def has_internal_alignment(self):
         return self.params.get('length_includes_align') == 'True'
 
diff --git a/openflow_input/bsn_controller_connections b/openflow_input/bsn_controller_connections
new file mode 100644
index 0000000..eae315e
--- /dev/null
+++ b/openflow_input/bsn_controller_connections
@@ -0,0 +1,71 @@
+// 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.
+
+// Retrieve a list of configured controller connections and their status.
+// When auxiliary connections are used there may be multiple connections
+// to the same controller. All connections to a given controller will
+// share the same role (so there may be multiple master connections in
+// the list).
+
+// The URIs are of the form tcp://1.2.3.4:6553
+
+#version 4
+
+enum ofp_bsn_controller_connection_state(wire_type=uint8_t) {
+    OFP_BSN_CONTROLLER_CONNECTION_STATE_DISCONNECTED = 0,
+    OFP_BSN_CONTROLLER_CONNECTION_STATE_CONNECTED = 1,
+};
+
+struct of_bsn_controller_connections_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 56;
+};
+
+struct of_bsn_controller_connection {
+    enum ofp_bsn_controller_connection_state state;
+    uint8_t auxiliary_id;
+    pad(2);
+    enum ofp_controller_role role;
+    of_desc_str_t uri;
+};
+
+struct of_bsn_controller_connections_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 57;
+    list(of_bsn_controller_connection_t) connections;
+};
diff --git a/openflow_input/bsn_role_status b/openflow_input/bsn_role_status
new file mode 100644
index 0000000..f53ff23
--- /dev/null
+++ b/openflow_input/bsn_role_status
@@ -0,0 +1,55 @@
+// 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.
+
+// Backport the OpenFlow 1.4 role status message
+//
+// This message will be sent when a controller's role changes for any reason
+// other than it using OFPT_ROLE_REQUEST.
+
+#version 4
+
+enum ofp_bsn_controller_role_reason(wire_type=uint8_t) {
+    OFP_BSN_CONTROLLER_ROLE_REASON_MASTER_REQUEST = 0,
+    OFP_BSN_CONTROLLER_ROLE_REASON_CONFIG = 1,
+    OFP_BSN_CONTROLLER_ROLE_REASON_EXPERIMENTER = 2,
+};
+
+struct of_bsn_role_status : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 55;
+    enum ofp_controller_role role;
+    enum ofp_bsn_controller_role_reason reason;
+    pad(3);
+    uint64_t generation_id;
+};
diff --git a/test_data/of10/packet_in.data b/test_data/of10/packet_in.data
index a8de82c..d5ccf32 100644
--- a/test_data/of10/packet_in.data
+++ b/test_data/of10/packet_in.data
@@ -18,7 +18,7 @@
     data='abc')
 -- c
 obj = of_packet_in_new(OF_VERSION_1_0);
-of_packet_in_buffer_id_set(obj, 2882400001);
+of_packet_in_buffer_id_set(obj, 0xabcdef01);
 {
     of_octets_t data = { .bytes=3, .data=(uint8_t *)"\x61\x62\x63" };
     of_packet_in_data_set(obj, &data);
diff --git a/test_data/of10/packet_out.data b/test_data/of10/packet_out.data
index fdd1c3d..a3c642b 100644
--- a/test_data/of10/packet_out.data
+++ b/test_data/of10/packet_out.data
@@ -25,7 +25,7 @@
     data='abc')
 -- c
 obj = of_packet_out_new(OF_VERSION_1_0);
-of_packet_out_buffer_id_set(obj, 2882400001);
+of_packet_out_buffer_id_set(obj, 0xabcdef01);
 of_packet_out_in_port_set(obj, 65534);
 of_packet_out_xid_set(obj, 305419896);
 {
diff --git a/test_data/of10/port_mod.data b/test_data/of10/port_mod.data
index 53e09ce..754e139 100644
--- a/test_data/of10/port_mod.data
+++ b/test_data/of10/port_mod.data
@@ -18,12 +18,12 @@
     advertise=0xCAFE6789)
 -- c
 obj = of_port_mod_new(OF_VERSION_1_0);
-of_port_mod_advertise_set(obj, 3405670281);
-of_port_mod_config_set(obj, 2427178479);
+of_port_mod_advertise_set(obj, 0xCAFE6789);
+of_port_mod_config_set(obj, 0x90ABCDEF);
 {
     of_mac_addr_t hw_addr = { { 1, 2, 3, 4, 5, 6 } };
     of_port_mod_hw_addr_set(obj, hw_addr);
 }
-of_port_mod_mask_set(obj, 4279369489);
+of_port_mod_mask_set(obj, 0xFF11FF11);
 of_port_mod_port_no_set(obj, 65533);
 of_port_mod_xid_set(obj, 2);
diff --git a/wireshark_gen/field_info.py b/wireshark_gen/field_info.py
index cf3192c..94e5243 100644
--- a/wireshark_gen/field_info.py
+++ b/wireshark_gen/field_info.py
@@ -104,6 +104,9 @@
     ('of_barrier_reply', 'type'): 'ofp_type',
     ('of_echo_request', 'type'): 'ofp_type',
     ('of_echo_reply', 'type'): 'ofp_type',
+    ('of_flow_delete', 'type'): 'ofp_type',
+    ('of_flow_add', 'type'): 'ofp_type',
+    ('of_port_status', 'type'): 'ofp_type',
     ('of_match_v3', 'type'): 'ofp_match_type',
     ('of_action_set_nw_ttl', 'type'): 'ofp_action_type',
     ('of_action_set_field', 'type'): 'ofp_action_type',
diff --git a/wireshark_gen/templates/_ofclass_dissector.lua b/wireshark_gen/templates/_ofclass_dissector.lua
index 1e1520f..d327b49 100644
--- a/wireshark_gen/templates/_ofclass_dissector.lua
+++ b/wireshark_gen/templates/_ofclass_dissector.lua
@@ -39,17 +39,39 @@
 -- Discriminator is ${ofclass.discriminator.name}
 :: #endif
 function ${name}(reader, subtree)
+:: field_length_members = []
 :: if ofclass.virtual:
     return ${ofclass.name}_v${version.wire_version}_dissectors[reader.peek(${ofclass.discriminator.offset},${ofclass.discriminator.length}):uint()](reader, subtree)
 :: else:
+:: if not ofclass.is_fixed_length:
+    local _length = reader.peek(${ofclass.length_member.offset}, ${ofclass.length_member.base_length}):uint()
+    local orig_reader = reader
+    reader = orig_reader.slice(_length)
+:: #endif
 :: for m in ofclass.members:
 :: if isinstance(m, OFPadMember):
     reader.skip(${m.length})
 :: continue
 :: #endif
+:: if isinstance(m, OFFieldLengthMember):
+    local _${m.field_name}_length = reader.peek(0, ${m.base_length}):uint()
+:: field_length_members.append(m.field_name)
+:: #endif
+:: if m.oftype.startswith("list"):
+:: class_name = m.oftype.replace('_t)', '').replace('(', '').replace('list', '')
+:: if m.name in field_length_members:
+    read_list(reader.slice(_${m.name}_length), dissect_${class_name}_v${version.wire_version}, subtree, '${class_name}')
+:: else:
+    read_list(reader, dissect_${class_name}_v${version.wire_version}, subtree, '${class_name}')
+:: #endif
+:: if ofclass.has_external_alignment:
+    orig_reader.skip_align()
+:: #endif
+:: else:
 :: field_name = make_field_name(version, ofclass.name, m.name)
 :: reader_name = get_reader(version, ofclass, m)
     ${reader_name}(reader, ${version.wire_version}, subtree, '${field_name}')
+:: #endif
 :: #endfor
     return '${ofclass.name}'
 :: #endif
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index 10f13ca..6c7fb5c 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -57,11 +57,11 @@
 
 function read_of_match_t(reader, version, subtree, field_name)
     if version == 1 then
-        dissect_of_match_v1_v1(reader, subtree:add(fields[field_name]))
+        dissect_of_match_v1_v1(reader, subtree:add("of_match"))
     elseif version == 2 then
-        dissect_of_match_v2_v2(reader, subtree:add(fields[field_name]))
+        dissect_of_match_v2_v2(reader, subtree:add("of_match"))
     elseif version >= 3 then
-        dissect_of_match_v3_v3(reader, subtree:add(fields[field_name]))
+        dissect_of_match_v3_v3(reader, subtree:add("of_match"))
     end
 end
 
@@ -105,122 +105,6 @@
     end
 end
 
-function read_list_of_action_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-
-    local list_len = 0
-
-    if string.find(field_name,'packet_out') then
-        if version == 1 then
-            list_len = reader.peek(-2,2):uint()
-        else
-            list_len = reader.peek(-8,2):uint()
-        end
-    end
-
-    local list = nil
-    local reader2 = nil
-
-    if list_len == 0 then
-        list = subtree:add(fields[field_name], reader.peek_all(0))
-        reader2 = reader
-    else
-        list = subtree:add(fields[field_name], reader.peek(0, list_len))
-        reader2 = reader.slice(list_len)
-    end
-
-    while not reader2.is_empty() do
-        local action_len = reader2.peek(2, 2):uint()
-        local child_reader = reader2.slice(action_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_action_dissectors[version](child_reader, child_subtree)
-        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)
-    if reader.is_empty() then
-        return
-    end
-    local list = subtree:add(fields[field_name], reader.peek_all(0))
-    list:set_text("List of port descriptions")
-    while not reader.is_empty() do
-        local port_desc_len = 64
-        local child_reader = reader.slice(port_desc_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_port_desc_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-end
-
-function read_list_of_flow_stats_entry_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local list = subtree:add(fields[field_name], reader.peek_all(0))
-    list:set_text("List of flow stats entries")
-    while not reader.is_empty() do
-        local stats_len = reader.peek(0,2):uint()
-        local child_reader = reader.slice(stats_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_flow_stats_entry_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-end
-
-function read_list_of_port_stats_entry_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local list = subtree:add(fields[field_name], reader.peek_all(0))
-    list:set_text("List of port stats entries")
-    while not reader.is_empty() do
-        local stats_len = 112
-        local child_reader = reader.slice(stats_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_port_stats_entry_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-end
-
-function read_list_of_table_stats_entry_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local list = subtree:add(fields[field_name], reader.peek_all(0))
-    list:set_text("List of table stats entries")
-    while not reader.is_empty() do
-        local stats_len = 24
-        local child_reader = reader.slice(stats_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_table_stats_entry_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-end
-
-function read_list_of_queue_stats_entry_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local list = subtree:add(fields[field_name], reader.peek_all(0))
-    list:set_text("List of flow stats entries")
-    while not reader.is_empty() do
-        local stats_len = 40
-        local child_reader = reader.slice(stats_len)
-        local child_subtree = list:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_queue_stats_entry_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-end
-
-function read_list_of_packet_queue_t(reader, version, subtree, field_name)
-    -- TODO
-    read_of_octets_t()
-end
-
 function read_of_desc_str_t(reader, version, subtree, field_name)
     read_scalar(reader, subtree, field_name, 256)
 end
@@ -229,50 +113,13 @@
     read_scalar(reader, subtree, field_name, 32)
 end
 
-function read_list_of_oxm_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local list_len = reader.peek(-2,2):uint()
-    local reader2 = reader.slice(list_len - 4)
-    local list = nil
-    if not reader2.is_empty() then
-        list = subtree:add(fields[field_name], reader2.peek_all(0))
-        list:set_text("List of matches")
-    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 = of_oxm_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
-    subtree:set_text("OXM")
-    reader.skip_align()
-end
-
-function read_list_of_instruction_t(reader, version, subtree, field_name)
+function read_of_port_desc_t(reader, version, subtree, field_name)
     if reader.is_empty() then
         return
     end
     local child_subtree = subtree:add(fields[field_name], reader.peek_all(0))
-    local info = of_instruction_dissectors[version](reader, child_subtree)
-    child_subtree:set_text("Instructions")
-end
-
-function read_list_of_bucket_t(reader, version, subtree, field_name)
-    if reader.is_empty() then
-        return
-    end
-    local bucket_list_subtree = subtree:add(fields[field_name], reader.peek_all(0))
-    bucket_list_subtree:set_text("List of buckets")
-    while not reader.is_empty() do
-        local bucket_len = reader.peek(0,2):uint()
-        local child_reader = reader.slice(bucket_len)
-        local child_subtree = bucket_list_subtree:add(fields[field_name], child_reader.peek_all(0))
-        local info = of_bucket_dissectors[version](child_reader, child_subtree)
-        child_subtree:set_text(info)
-    end
+    local info = of_port_desc_dissectors[version](reader, child_subtree)
+    child_subtree:set_text(info)
 end
 
 function read_of_oxm_t(reader, version, subtree, field_name)
@@ -283,3 +130,16 @@
     local info = of_oxm_dissectors[version](reader, child_subtree)
     child_subtree:set_text(info)
 end
+
+function read_list(reader, dissector, subtree, field_name)
+    if not reader.is_empty() then
+        local list_subtree = subtree:add(field_name .. " list", reader.peek_all(0))
+        while not reader.is_empty() do
+            local atom_subtree = list_subtree:add(field_name, reader.peek_all(0))
+            local info = dissector(reader, atom_subtree)
+            atom_subtree:set_text(info)
+        end
+    else
+        return
+    end
+end
diff --git a/wireshark_gen/templates/openflow.lua b/wireshark_gen/templates/openflow.lua
index bdbe2ec..cad61a5 100644
--- a/wireshark_gen/templates/openflow.lua
+++ b/wireshark_gen/templates/openflow.lua
@@ -106,69 +106,15 @@
 :: #endfor
 }
 
-local of_oxm_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_oxm_v${version.wire_version},
-:: #endfor
-}
-
-local of_action_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_action_v${version.wire_version},
-:: #endfor
-}
-
-local of_instruction_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_instruction_v${version.wire_version},
-:: #endfor
-}
-
-local of_bucket_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_bucket_v${version.wire_version},
-:: #endfor
-}
-
 local of_port_desc_dissectors = {
 :: for version in ir:
     [${version.wire_version}] = dissect_of_port_desc_v${version.wire_version},
 :: #endfor
 }
 
-local of_stats_reply_dissectors = {
+local of_oxm_dissectors = {
 :: for version in ir:
-    [${version.wire_version}] = dissect_of_stats_reply_v${version.wire_version},
-:: #endfor
-}
-
-local of_stats_request_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_stats_request_v${version.wire_version},
-:: #endfor
-}
-
-local of_flow_stats_entry_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_flow_stats_entry_v${version.wire_version},
-:: #endfor
-}
-
-local of_port_stats_entry_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_port_stats_entry_v${version.wire_version},
-:: #endfor
-}
-
-local of_table_stats_entry_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_table_stats_entry_v${version.wire_version},
-:: #endfor
-}
-
-local of_queue_stats_entry_dissectors = {
-:: for version in ir:
-    [${version.wire_version}] = dissect_of_queue_stats_entry_v${version.wire_version},
+    [${version.wire_version}] = dissect_of_oxm_v${version.wire_version},
 :: #endfor
 }