diff options
-rwxr-xr-x | tools/dissectors/lua/color_rules.rfnoc | 13 | ||||
-rwxr-xr-x | tools/dissectors/lua/rfnoc.lua | 556 |
2 files changed, 569 insertions, 0 deletions
diff --git a/tools/dissectors/lua/color_rules.rfnoc b/tools/dissectors/lua/color_rules.rfnoc new file mode 100755 index 000000000..6b99db019 --- /dev/null +++ b/tools/dissectors/lua/color_rules.rfnoc @@ -0,0 +1,13 @@ +# Copyright 2022 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# These color rules ease orientation in RFNoC packet display. +# Import this file in Wireshark's Coloring Rules dialog +# (View -> Coloring Rules…) +@RFNoC Management@rfnoc.PktType == 0@[65535, 50372, 2313][0,0,0] +@RFNoC Stream Status@rfnoc.PktType == 1@[0,46774,30583][0,0,0] +@RFNoC Stream Command@rfnoc.PktType == 2@[1028,16705,8995][65535,65535,65535] +@RFNoC Control Transaction@rfnoc.PktType == 4@[25759,46003,59110][0,0,0] +@RFNoC Data Packet without a Timestamp@rfnoc.PktType == 6@[56283, 56283, 51400][32639,32639,32639] +@RFNoC Data Packet with a Timestamp@rfnoc.PktType == 7@[56283, 56283, 51400][0,0,0] diff --git a/tools/dissectors/lua/rfnoc.lua b/tools/dissectors/lua/rfnoc.lua new file mode 100755 index 000000000..866c8ea69 --- /dev/null +++ b/tools/dissectors/lua/rfnoc.lua @@ -0,0 +1,556 @@ +-- Copyright 2022 Ettus Research, a National Instruments Brand +-- +-- SPDX-License-Identifier: GPL-3.0-or-later + +-- This file defines a LUA dissector for RFNoC. All chapter references refer to +-- https://files.ettus.com/app_notes/RFNoC_Specification.pdf. + +-- to install the dissector choose a global or personal LUA plugin folder +-- these folder can be found under Help -> About Wireshark -> Folders + +-- RFNoC UDP port +local RFNOC_PORT = 49153 + +-- general purpose lookup for boolean fields +local yesno = { + [0] = "no", + [1] = "yes" +} + +-- lookup table for CHDR with preferences +local chdr_widths = { + { 0, "64", 64 }, + { 1, "128", 128 }, + { 2, "256", 256 }, + { 3, "512", 512 } +} + +-- Packet type definitions for RFNoC (2.2.1) +local packet_types = { + [0x0] = "Management", + [0x1] = "Stream Status", + [0x2] = "Stream Command", + [0x3] = "<Reserved>", + [0x4] = "Control Transaction", + [0x5] = "<Reserved>", + [0x6] = "Data Packet without a Timestamp", + [0x7] = "Data Packet with a Timestamp" +} + +-- same packet type definitions as short names +local packet_types_short = { + [0x0] = "Mgmt", + [0x1] = "StrS", + [0x2] = "StrC", + [0x3] = "<Re>", + [0x4] = "Ctrl", + [0x5] = "<Re>", + [0x6] = "Data", + [0x7] = "DaTS" +} + +-- CHDR widths reported by management packet (table 15) +local mgmt_chdr_widths = { + [0x0] = "64 bits", + [0x1] = "128 bits", + [0x2] = "256 bits", + [0x3] = "512 bits", + [0x4] = "<Reserved>", + [0x5] = "<Reserved>", + [0x6] = "<Reserved>", + [0x7] = "<Reserved>" +} + +-- op codes for control transaction packet (table 9) +local ctrl_op_codes = { + [0] = "sleep", + [1] = "write", + [2] = "read", + [3] = "read then write", + [4] = "block write", + [5] = "block read", + [6] = "poll", + [7] = "<reserved>", + [8] = "<reserved>", + [9] = "<reserved>", + [10] = "user 1", + [11] = "user 2", + [12] = "user 3", + [13] = "user 4", + [14] = "user 5", + [15] = "user 6" +} + +-- op codes for stream command packet (table 13) +local strc_op_codes = { + [0] = "Initialize stream", + [1] = "Ping", + [2] = "Resynchronize flow control", + [3] = "<reserved>", + [4] = "<reserved>", + [5] = "<reserved>", + [6] = "<reserved>", + [7] = "<reserved>" +} + +-- op codes for management packet (table 15) +local mgmt_op_codes = { + [0] = "no-op", + [1] = "advertise", + [2] = "select destination", + [3] = "return to sender", + [4] = "node info request", + [5] = "node info response", + [6] = "config write", + [7] = "config read request", + [8] = "config read response" +} + +-- node types from management node info response (no ref) +local mgmt_op_nir_types = { + [0] = "<invalid>", + [1] = "Crossbar", + [2] = "Stream Endpoint", + [3] = "Transport Adapter" +} + +-- fill remaining types +for i = 4, 255 do + mgmt_op_nir_types[i] = "<invalid>" +end + +-- states of control status field (table 8) +local ctrl_states = { + [0] = "OK", + [1] = "CMDERR", + [2] = "TSERR", + [3] = "WARNING", +} + +-- states of stream status' status field (table 11) +local strs_states = { + [0] = "Okay (No Error)", + [1] = "Command Error (Command execution failed)", + [2] = "Sequence Error (Sequence number discontinuity)", + [3] = "Data Error (Data integrity check failed)", + [4] = "Routing Error (Unexpected destination)", + [5] = "<reserved>", + [6] = "<reserved>", + [7] = "<reserved>" +} + +-- Protocol field definitions +-- Definitions are made for all fields of 32 bit or smaller. Larger fields +-- are handled directly, because the ProtoField does not support bitmasks +-- bigger than 32 bit. Therefore CHDR header fields are split into +-- 32 bit chunks (to make use of the bit-wise display of the ProtoField +-- which eases orientation in the detail pane). Also all CHDR header +-- fields are uint32 even if they would fit into a smaller field. +-- This eases orientation in the bit-wise display of the detail pane. +-- Because most stream packets fields are bigger than 32 bit there are no +-- ProtoField definitions with bit mask for the stream command/status +-- packets. +-- The naming convention for the ProtoFields follows the specification +-- names. All fields starts with rfnoc followed by a dot. CHDR header +-- fields have the format rfnoc.<field_name>. Packet fields follow the +-- convention rfnoc.<packet_short_name>.<field_name>. +-- The display name is a human readable form of the field name without +-- references to the packet name they are associated with. +-- The protocol field LUA names follow the naming scheme +-- pf_<packet_short_name>_<field_name>. CHDR fields use chdr instead of +-- the packet short name. The field name uses underscores as word separator. + +-- CHDR header fields +pf_chdr_dst_epid = ProtoField.uint32("rfnoc.DstEPID", "dest EPID", base.DEC, nil, 0x0000FFFF) +pf_chdr_length = ProtoField.uint32("rfnoc.Length", "length", base.DEC, nil, 0xFFFF0000) +pf_chdr_seq_num = ProtoField.uint32("rfnoc.SeqNum", "seq num", base.DEC, nil, 0x0000FFFF) +pf_chdr_num_mdata = ProtoField.uint32("rfnoc.NumMData", "num metadata", base.DEC, nil, 0x001F0000) +pf_chdr_pkt_type = ProtoField.uint32("rfnoc.PktType", "packet type", base.DEC, packet_types, 0x00E00000) +pf_chdr_end_of_vector = ProtoField.uint32("rfnoc.EOV", "end of vector", base.DEC, yesno, 0x01000000) +pf_chdr_end_of_burst = ProtoField.uint32("rfnoc.EOB", "end of burst", base.DEC, yesno, 0x02000000) +pf_chdr_virtual_channel = ProtoField.uint32("rfnoc.VC", "virtual channel", base.DEC, nil, 0xFC000000) + +pf_chdr_timestamp = ProtoField.uint64("rfnoc.Timestamp", "timestamp", base.HEX) +pf_chdr_metadata = ProtoField.bytes("rfnoc.Metadata", "metadata") +pf_chdr_payload = ProtoField.bytes("rfnoc.Payload", "payload") + +-- Management packet fields +pf_mgmt_src_epid = ProtoField.uint32("rfnoc.mgmt.SrcEPID", "src EPID", base.DEC, nil, 0x0000FFFF) +pf_mgmt_num_hops = ProtoField.uint32("rfnoc.mgmt.NumHops", "num hops", base.DEC, nil, 0x03FF0000) +-- reserved 0xFC000000 +-- reserved 0x00001FFF +pf_mgmt_chdr_width = ProtoField.uint32("rfnoc.mgmt.CHDRWidth", "CHDR width", base.DEC, mgmt_chdr_widths, 0x0000E000) +pf_mgmt_proto_ver = ProtoField.uint32("rfnoc.mgmt.ProtoVer", "protocol version", base.DEC, nil, 0xFFFF0000) +pf_mgmt_proto_major = ProtoField.uint32("rfnoc.mgmt.MajorVer", "major version", base.DEC, nil, 0xFF000000) +pf_mgmt_proto_minor = ProtoField.uint32("rfnoc.mgmt.MinorVer", "minor version", base.DEC, nil, 0x00FF0000) + +pf_mgmt_op_codes = ProtoField.uint8("rfnoc.mgmt.OpCode", "op code", base.DEC, mgmt_op_codes) +pf_mgmt_op_sd_dest = ProtoField.uint16("rfnoc.mgmt.sd.dest", "select dest", base.DEC) +pf_mgmt_op_nir_device_id = ProtoField.uint16("rfnoc.mgmt.nir.DeviceID", "device ID", base.DEC, nil) +pf_mgmt_op_nir_node_type = ProtoField.uint8("rfnoc.mgmt.nir.NodeType", "node type", base.DEC, mgmt_op_nir_types) +pf_mgmt_op_nir_node_inst = ProtoField.uint32("rfnoc.mgmt.nir.NodeInst", "node inst", base.DEC, nil) +pf_mgmt_op_nir_node_info = ProtoField.uint32("rfnoc.mgmt.nir.ExtendedInfo", "extended info", base.HEX, nil) +pf_mgmt_op_conf_address = ProtoField.uint16("rfnoc.mgmt.conf.Address", "address", base.HEX) +pf_mgmt_op_conf_data = ProtoField.uint32("rfnoc.mgmt.conf.Data", "data", base.HEX) + +-- Control packet fields +pf_ctrl_dst_port = ProtoField.uint32("rfnoc.ctrl.DstPort", "dst port", base.DEC, nil, 0x000003FF) +pf_ctrl_src_port = ProtoField.uint32("rfnoc.ctrl.SrcPort", "src port", base.DEC, nil, 0x000FFC00) +pf_ctrl_num_data = ProtoField.uint32("rfnoc.ctrl.NumData", "num data", base.DEC, nil, 0x00F00000) +pf_ctrl_ctrl_seq_num = ProtoField.uint32("rfnoc.ctrl.SeqNum", "ctrl seq num", base.DEC, nil, 0x3F000000) +pf_ctrl_has_timestamp = ProtoField.uint32("rfnoc.ctrl.HasTimestamp", "has time", base.DEC, yesno, 0x40000000) +pf_ctrl_is_ack = ProtoField.uint32("rfnoc.ctrl.IsACK", "is ACK", base.DEC, yesno, 0x80000000) +pf_ctrl_src_epid = ProtoField.uint32("rfnoc.ctrl.SrcEPID", "src EPID", base.DEC, nil, 0x0000FFFF) +-- reserved 0xFFFF0000 +pf_ctrl_timestamp = ProtoField.uint64("rfnoc.ctrl.Timestamp", "timestamp", base.HEX) +pf_ctrl_address = ProtoField.uint32("rfnoc.ctrl.Address", "address", base.HEX, nil, 0x000FFFFF) +pf_ctrl_byte_enable = ProtoField.uint32("rfnoc.ctrl.ByteEnable", "byte enable", base.HEX, nil, 0x00F00000) +pf_ctrl_op_code = ProtoField.uint32("rfnoc.ctrl.OpCode", "op code", base.DEC, ctrl_op_codes, 0x0F000000) +-- reserved 0x30000000 +pf_ctrl_status = ProtoField.uint32("rfnoc.ctrl.Status", "status", base.DEC, ctrl_states, 0xC0000000) + +pf_ctrl_data = ProtoField.bytes("rfnoc.ctrl.Data", "data") + +-- Stream Status fields +pf_strs_src_epid = ProtoField.uint16("rfnoc.strs.SrcEPID", "src EPID") +pf_strs_status = ProtoField.uint8("rfnoc.strs.Status", "status", base.DEC, strs_states) +pf_strs_capacity_bytes = ProtoField.uint64("rfnoc.strs.CapacityBytes", "capacity bytes") +pf_strs_capacity_packets = ProtoField.uint32("rfnoc.strs.CapacityPackets", "capacity packets") +pf_strs_xfer_count_packets = ProtoField.uint64("rfnoc.strs.XfcerCountPackets", "transferred packets") +pf_strs_xfer_count_bytes = ProtoField.uint64("rfnoc.strs.XferCountBytes", "transferred bytes") +pf_strs_buff_info = ProtoField.uint16("rfnoc.strs.BuffInfo", "buffer info") +pf_strs_status_info = ProtoField.uint64("rfnoc.strs.StatusInfo", "status info") + +-- Stream Command fields +pf_strc_src_epid = ProtoField.uint16("rfnoc.strc.SrcEPID", "src EPID") +pf_strc_op_code = ProtoField.uint8("rfnoc.strc.OpCode", "op code", base.DEC, strc_op_codes) +pf_strc_op_data = ProtoField.uint8("rfnoc.strc.OpData", "op data") +pf_strc_num_packets = ProtoField.uint64("rfnoc.strc.NumPkts", "num packets") +pf_strc_num_bytes = ProtoField.uint64("rfnoc.strc.NumBytes", "num bytes") + + +-- RFNoC protocol dissector +rfnoc_proto = Proto("RFNoC", "RFNoC Protocol") +rfnoc_proto.fields = { + pf_chdr_dst_epid, + pf_chdr_length, + pf_chdr_seq_num, + pf_chdr_num_mdata, + pf_chdr_pkt_type, + pf_chdr_end_of_vector, + pf_chdr_end_of_burst, + pf_chdr_virtual_channel, + + pf_chdr_timestamp, + pf_chdr_metadata, + pf_chdr_payload, + + pf_mgmt_src_epid, + pf_mgmt_num_hops, + pf_mgmt_chdr_width, + pf_mgmt_proto_ver, + pf_mgmt_proto_major, + pf_mgmt_proto_minor, + pf_mgmt_op_codes, + pf_mgmt_op_sd_dest, + pf_mgmt_op_nir_device_id, + pf_mgmt_op_nir_node_type, + pf_mgmt_op_nir_node_inst, + pf_mgmt_op_nir_node_info, + pf_mgmt_op_conf_address, + pf_mgmt_op_conf_data, + + pf_ctrl_dst_port, + pf_ctrl_src_port, + pf_ctrl_num_data, + pf_ctrl_ctrl_seq_num, + pf_ctrl_has_timestamp, + pf_ctrl_is_ack, + pf_ctrl_src_epid, + pf_ctrl_timestamp, + pf_ctrl_address, + pf_ctrl_byte_enable, + pf_ctrl_op_code, + pf_ctrl_status, + + pf_ctrl_data, + + pf_strs_src_epid, + pf_strs_status, + pf_strs_capacity_bytes, + pf_strs_capacity_packets, + pf_strs_xfer_count_packets, + pf_strs_xfer_count_bytes, + pf_strs_buff_info, + pf_strs_status_info, + + pf_strc_src_epid, + pf_strc_op_code, + pf_strc_op_data, + pf_strc_num_packets, + pf_strc_num_bytes, +} + +-- define preferences +rfnoc_proto.prefs.chdr_width = Pref.enum( + "CHDR width", -- label + 64, -- default + "CHDR width used for decoding", -- description + chdr_widths, -- lookup + true -- use radio buttons in config +) + +-- main entry point for dissector +-- * decode the CHDR header +-- * dissect metadata +-- - metadata dissector return new dissector offset +-- * lookup decoder for packet type to decode packet-specific fields +-- - each packet decoder returns a tuple of src EPID (might be nil) +-- and additional info that will be placed along with the info +-- column in the main view +-- - the CHDR header is passed to the packet decoder, because +-- some decoders need references to CHDR fields. +function rfnoc_proto.dissector(buffer, pinfo, tree) + buf_length = buffer:len() + if buf_length == 0 then return end + + pinfo.cols.protocol = rfnoc_proto.name + pinfo.cols.info:clear() + + local subtree = tree:add(rfnoc_proto, buffer(), "RFNoC") + local chdr = subtree:add(rfnoc_proto, buffer(0, 8), "CHDR") + + chdr:add_le(pf_chdr_dst_epid, buffer(0, 4)) + chdr:add_le(pf_chdr_length, buffer(0, 4)) + chdr:add_le(pf_chdr_seq_num, buffer(4, 4)) + chdr:add_le(pf_chdr_num_mdata, buffer(4, 4)) + chdr:add_le(pf_chdr_pkt_type, buffer(4, 4)) + chdr:add_le(pf_chdr_end_of_vector, buffer(4, 4)) + chdr:add_le(pf_chdr_end_of_burst, buffer(4, 4)) + chdr:add_le(pf_chdr_virtual_channel, buffer(4, 4)) + + local packet_decoders = { + [0] = dissect_mgmt_packet, + [1] = dissect_stream_status_packet, + [2] = dissect_stream_command_packet, + [3] = dissect_reserved_packet, + [4] = dissect_ctrl_packet, + [5] = dissect_reserved_packet, + [6] = dissect_data_packet_without_ts, + [7] = dissect_data_packet_with_ts + } + + local packet_len = buffer(2, 2):le_uint() + local packet_type = buffer(6, 1):bitfield(0, 3) + local offset = dissect_metadata(buffer, packet_type, pinfo, subtree) + local src, info = packet_decoders[buffer(6, 1):bitfield(0, 3)]( + buffer(0, offset), + buffer(offset, packet_len - offset), + pinfo, subtree) + + local src_str = src == nil and " " or string.format("%3d", src) + pinfo.cols.info:append(string.format("[%s] %s -> %3d %s", + packet_types_short[packet_type], -- packet type + src_str, -- src EPID + buffer(0, 2):le_uint(), -- dst EPID + info -- packet specific info + )) +end + +-- see 2.2.1 for details about metadata memory layout depending +-- on CHDR width. +function dissect_metadata(buffer, packet_type, pinfo, subtree) + local mdata_len = buffer(6,1):bitfield(3, 5) + local chdr_width_in_bytes = rfnoc_proto.prefs.chdr_width / 8 + local packet_offset = 0 + if rfnoc_proto.prefs.chdr_width == 64 and packet_type == 7 then + packet_offset = chdr_width_in_bytes * (2 + mdata_len); + else + packet_offset = chdr_width_in_bytes * (1 + mdata_len); + end + if mdata_len > 0 then + subtree:add(pf_chdr_metadata, buffer(packet_offset, mdata_len * chdr_width_in_bytes)) + end + return packet_offset + mdata_len * chdr_width_in_bytes +end + +function dissect_mgmt_op(buffer, hop_node, op_index, op_code, op_payload) + local op_node = hop_node:add(rfnoc_proto, buffer(), "Operation " .. op_index) + local op_code = buffer(1, 1):le_uint() + local ext_info = bit.rshift(buffer(5, 3):le_uint(), 6) + local op_info = mgmt_op_codes[buffer(1, 1):le_uint()] + + op_node:add_le(pf_mgmt_op_codes, buffer(1, 1)) + if op_code == 2 then -- select destination + op_node:add(pf_mgmt_op_sd_dest, bit.band(buffer(2, 2):le_uint(), 0x3FF)) + op_info = op_info .. " " .. bit.band(buffer(2, 2):le_uint(), 0x3FF) + elseif op_code == 5 then -- node response info + local node_type = bit.band(buffer(4, 1):le_uint(), 0xF) + local node_inst = bit.rshift(bit.band(buffer(4, 2):le_uint(), 0x3FF0), 4) + op_node:add_le(pf_mgmt_op_nir_device_id, buffer(2, 2)) + op_node:add_le(pf_mgmt_op_nir_node_type, node_type) + op_node:add_le(pf_mgmt_op_nir_node_inst, node_inst) + local node_ext_info = op_node:add_le(pf_mgmt_op_nir_node_info, ext_info) + if node_type == 1 then -- crossbar + node_ext_info:set_text(string.format( + "NPORTS=%d, NPORTS_MGMT=%d, EXT_RTCFG_PORT=%d (0x%05X)", + bit.band(ext_info, 0xFF), + bit.band(bit.rshift(ext_info, 8), 0xFF), + bit.band(bit.rshift(ext_info, 16), 1), + ext_info + )) + elseif node_type == 2 then -- streaming endpoint + node_ext_info:set_text(string.format( + "AXIS_CTRL_EN=%d, AXIS_DATA_EN=%d, NUM_DATA_I=%d NUM_DATA_O=%d, REPORT_STREAM_ERRS=%d (0x%05X)", + bit.band(ext_info, 1), + bit.band(bit.rshift(ext_info, 1), 1), + bit.band(bit.rshift(ext_info, 2), 0x3F), + bit.band(bit.rshift(ext_info, 8), 0x3F), + bit.band(bit.rshift(ext_info, 14), 1), + ext_info + )) + elseif node_type == 3 then -- transport adapter + node_ext_info:set_text(string.format( + "NODE_SUBTYPE=%d (0x%05X)", + bit.band(ext_info, 0xFF), + ext_info + )) + else + node_ext_info:append_text(" <invalid>") + end + elseif op_code == 6 then -- config write + op_node:add_le(pf_mgmt_op_conf_address, buffer(2, 2)) + op_node:add_le(pf_mgmt_op_conf_data, buffer(4, 4)) + op_info = string.format("%s %x->%4.4x", op_info, buffer(4, 4):le_uint(), buffer(2, 2):le_uint()) + elseif op_code == 7 then -- config read request + op_node:add_le(pf_mgmt_op_conf_address, buffer(2, 2)) + elseif op_code == 8 then -- config read response + op_node:add_le(pf_mgmt_op_conf_address, buffer(2, 2)) + op_node:add_le(pf_mgmt_op_conf_data, buffer(4, 4)) + end + return op_info +end + +function dissect_mgmt_packet(header_buffer, buffer, pinfo, tree) + local header = tree:add(rfnoc_proto, buffer(), "Management") + header:add_le(pf_mgmt_src_epid, buffer(0, 4)) + header:add_le(pf_mgmt_num_hops, buffer(0, 4)) + header:add_le(pf_mgmt_chdr_width, buffer(4, 4)) + header:add_le(pf_mgmt_proto_ver, buffer(4, 4)) + header:add_le(pf_mgmt_proto_major, buffer(4, 4)) + header:add_le(pf_mgmt_proto_minor, buffer(4, 4)) + + local num_hops = bit.band(buffer(2, 4):le_uint(), 0x3FF) + local offset = 8 + local hop_info = "" + for hop = 0, num_hops - 1 do + local ops_pending = buffer(offset, 1):le_uint() + local hop_node = header:add(rfnoc_proto, buffer(offset, 8 * (ops_pending + 1)), "Hop " .. hop) + for op_nr = 0, ops_pending do + hop_info = hop_info .. dissect_mgmt_op(buffer(offset, 8), hop_node, op_nr, buffer(offset + 1, 1), buffer(offset + 2, 6)) + offset = offset + 8 + if ops_pending > 0 then + ops_pending = buffer(offset, 1):le_uint() + hop_info = hop_info .. ", " + end + end + if hop < num_hops - 1 then + hop_info = hop_info .. " | " + end + end + return buffer(0, 2):le_uint(), hop_info +end + +function dissect_stream_status_packet(header_buffer, buffer, pinfo, tree) + local header = tree:add(rfnoc_proto, buffer(), "Stream Status") + header:add_le(pf_strs_src_epid, buffer(0, 2)) + header:add_le(pf_strs_status, buffer(2, 1):bitfield(0, 4)) + header:add_le(pf_strs_capacity_bytes, buffer(3, 5)) + header:add_le(pf_strs_capacity_packets, buffer(8, 3)) + header:add_le(pf_strs_xfer_count_packets, buffer(11, 5)) + header:add_le(pf_strs_xfer_count_bytes, buffer(16, 8)) + header:add_le(pf_strs_buff_info, buffer(24, 2)) + header:add_le(pf_strs_status_info, buffer(26, 6)) + return buffer(0, 2):le_uint(), string.format("%s (packets: %s, bytes: %s)", + strs_states[buffer(2, 1):bitfield(0, 4)], -- stream status + tostring(UInt64(buffer(11, 4):le_uint(), buffer(15, 1):le_uint())), -- transferred packets + tostring(UInt64(buffer(16, 4):le_uint(), buffer(20, 4):le_uint())) -- transferred bytes + ) +end + +function dissect_stream_command_packet(header_buffer, buffer, pinfo, tree) + local header = tree:add(rfnoc_proto, buffer(), "Stream Command") + header:add_le(pf_strc_src_epid, buffer(0, 2)) + header:add_le(pf_strc_op_code, buffer(2, 1):bitfield(4, 4)) + header:add_le(pf_strc_op_data, buffer(2, 1):bitfield(0, 4)) + header:add_le(pf_strc_num_packets, buffer(3, 5)) + header:add_le(pf_strc_num_bytes, buffer(8, 8)) + return buffer(0, 2):le_uint(), string.format("%s (packets: %s, bytes: %s)", + strc_op_codes[buffer(2, 1):bitfield(4, 4)], -- op code + tostring(UInt64(buffer(3, 4):le_uint(), buffer(7, 1):le_uint())), -- packets + tostring(UInt64(buffer(8, 4):le_uint(), buffer(12, 4):le_uint())) -- bytes + ) +end + +function dissect_reserved_packet(header_buffer, buffer, pinfo, tree) + return nil, "" +end + +function dissect_ctrl_packet(header_buffer, buffer, pinfo, tree) + local header = tree:add(rfnoc_proto, buffer(), "Control") + header:add_le(pf_ctrl_dst_port, buffer(0,4)) + header:add_le(pf_ctrl_src_port, buffer(0,4)) + header:add_le(pf_ctrl_num_data, buffer(0,4)) + header:add_le(pf_ctrl_ctrl_seq_num, buffer(0,4)) + header:add_le(pf_ctrl_has_timestamp, buffer(0,4)) + header:add_le(pf_ctrl_is_ack, buffer(0,4)) + header:add_le(pf_ctrl_src_epid, buffer(4,4)) + local offset = 8 + local has_ts = buffer(3,1):bitfield(1) + local ack_info = "" + local time_info = "" + if buffer(3,1):bitfield(0) == 1 then + ack_info = "ACK " + end + if has_ts == 1 then + header:add_le(pf_ctrl_timestamp, buffer(offset, 8)) + time_info = " @ 0x" .. tostring(buffer(offset, 8):le_uint64():tohex()) + offset = offset + 8 + end + header:add_le(pf_ctrl_address, buffer(offset, 4)) + header:add_le(pf_ctrl_byte_enable, buffer(offset, 4)) + header:add_le(pf_ctrl_op_code, buffer(offset, 4)) + header:add_le(pf_ctrl_status, buffer(offset, 4)) + header:add(pf_ctrl_data, buffer(offset + 4)) + return buffer(4, 2):le_uint(), string.format("%s%s %s -> %s%s", + ack_info, -- add ACK when is_ack is 1 + ctrl_op_codes[buffer(offset + 3):bitfield(4,4)], -- op code + buffer(offset + 4):bytes():tohex(), -- data + bit.tohex(bit.band(buffer(offset, 4):le_uint(), 0xFFFFF)), -- address + time_info -- timestamp if has_ts is 1 + ) +end + +function dissect_data_packet_without_ts(header_buffer, buffer, pinfo, tree) + tree:add(pf_chdr_payload, buffer) + local burst_info = "" + + if header_buffer(7, 1):bitfield(6) == 1 then + burst_info = burst_info .. "EOB " + end + return nil, burst_info +end + +function dissect_data_packet_with_ts(header_buffer, buffer, pinfo, tree) + tree:add_le(pf_chdr_timestamp, header_buffer(8, 8)) + dstEpid, info = dissect_data_packet_without_ts(header_buffer, buffer, pinfo, tree) + info = info .. string.format("time: 0x%.8x%.8x", + header_buffer(12, 4):le_uint(), + header_buffer(8, 4):le_uint() + ) + return nil, info +end + +-- register RFNoC dissector +local udp_port = DissectorTable.get("udp.port") +udp_port:add(RFNOC_PORT, rfnoc_proto) |