diff options
author | Anders Broman <anders.broman@ericsson.com> | 2013-10-19 20:19:35 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2013-10-19 20:19:35 +0000 |
commit | 3c813bbcc13945fe137ac9cf7a62176942c52103 (patch) | |
tree | c5f034589ff95ac2a5ae89b1aead03c352b8a93b /epan | |
parent | 09e32f5fb8310940e9bebf33e0a4398e76b41eeb (diff) |
From Zoltán Lajos Kis:
dissect flow_mod body in openflow_v4
https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9283
svn path=/trunk/; revision=52696
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-openflow_v4.c | 755 |
1 files changed, 743 insertions, 12 deletions
diff --git a/epan/dissectors/packet-openflow_v4.c b/epan/dissectors/packet-openflow_v4.c index 28dc7ee756..b4fdd34b53 100644 --- a/epan/dissectors/packet-openflow_v4.c +++ b/epan/dissectors/packet-openflow_v4.c @@ -30,6 +30,7 @@ #include <glib.h> #include <epan/packet.h> +#include <epan/expert.h> void proto_reg_handoff_openflow_v4(void); static int proto_openflow_v4 = -1; @@ -37,6 +38,26 @@ static int hf_openflow_v4_version = -1; static int hf_openflow_v4_type = -1; static int hf_openflow_v4_length = -1; static int hf_openflow_v4_xid = -1; +static int hf_openflow_v4_oxm_class = -1; +static int hf_openflow_v4_oxm_field = -1; +static int hf_openflow_v4_oxm_field_basic = -1; +static int hf_openflow_v4_oxm_hm = -1; +static int hf_openflow_v4_oxm_length = -1; +static int hf_openflow_v4_oxm_value = -1; +static int hf_openflow_v4_oxm_mask = -1; +static int hf_openflow_v4_match_type = -1; +static int hf_openflow_v4_match_length = -1; +static int hf_openflow_v4_match_pad = -1; +static int hf_openflow_v4_instruction_type = -1; +static int hf_openflow_v4_instruction_length = -1; +static int hf_openflow_v4_instruction_goto_table_table_id = -1; +static int hf_openflow_v4_instruction_goto_table_pad = -1; +static int hf_openflow_v4_instruction_write_metadata_pad = -1; +static int hf_openflow_v4_instruction_write_metadata_value = -1; +static int hf_openflow_v4_instruction_write_metadata_mask = -1; +static int hf_openflow_v4_instruction_actions_pad = -1; +static int hf_openflow_v4_instruction_meter_meter_id = -1; +static int hf_openflow_v4_instruction_meter_meter_id_reserved = -1; static int hf_openflow_v4_datapath_id = -1; static int hf_openflow_datapath_v4_mac = -1; static int hf_openflow_v4_datapath_impl = -1; @@ -44,7 +65,6 @@ static int hf_openflow_v4_n_buffers = -1; static int hf_openflow_v4_n_tables = -1; static int hf_openflow_v4_auxiliary_id = -1; static int hf_openflow_v4_padd16 = -1; -static int hf_openflow_v4_pad3 = -1; static int hf_openflow_v4_padd32 = -1; static int hf_openflow_v4_capabilities = -1; static int hf_openflow_v4_cap_flow_stats = -1; @@ -54,6 +74,27 @@ static int hf_openflow_v4_group_stats = -1; static int hf_openflow__v4_ip_reasm = -1; static int hf_openflow_v4_queue_stats = -1; static int hf_openflow_v4_port_blocked = -1; +static int hf_openflow_v4_flowmod_cookie = -1; +static int hf_openflow_v4_flowmod_cookie_mask = -1; +static int hf_openflow_v4_flowmod_table_id = -1; +static int hf_openflow_v4_flowmod_table_id_reserved = -1; +static int hf_openflow_v4_flowmod_command = -1; +static int hf_openflow_v4_flowmod_idle_timeout = -1; +static int hf_openflow_v4_flowmod_hard_timeout = -1; +static int hf_openflow_v4_flowmod_priority = -1; +static int hf_openflow_v4_flowmod_buffer_id = -1; +static int hf_openflow_v4_flowmod_buffer_id_reserved = -1; +static int hf_openflow_v4_flowmod_out_port = -1; +static int hf_openflow_v4_flowmod_out_port_reserved = -1; +static int hf_openflow_v4_flowmod_out_group = -1; +static int hf_openflow_v4_flowmod_out_group_reserved = -1; +static int hf_openflow_v4_flowmod_flags = -1; +static int hf_openflow_v4_flowmod_flags_send_flow_rem = -1; +static int hf_openflow_v4_flowmod_flags_check_overlap = -1; +static int hf_openflow_v4_flowmod_flags_reset_counts = -1; +static int hf_openflow_v4_flowmod_flags_no_packet_counts = -1; +static int hf_openflow_v4_flowmod_flags_no_byte_counts = -1; +static int hf_openflow_v4_flowmod_pad = -1; static int hf_openflow_v4_multipart_type = -1; static int hf_openflow_v4_multipart_request_flags = -1; static int hf_openflow_v4_multipart_reply_flags = -1; @@ -61,6 +102,16 @@ static int hf_openflow_v4_multipart_reply_flags = -1; static gint ett_openflow_v4 = -1; static gint ett_openflow_v4_path_id = -1; static gint ett_openflow_v4_cap = -1; +static gint ett_openflow_v4_flowmod_flags = -1; +static gint ett_openflow_v4_flowmod_instructions = -1; +static gint ett_openflow_v4_oxm = -1; +static gint ett_openflow_v4_match = -1; +static gint ett_openflow_v4_match_oxm_fields = -1; +static gint ett_openflow_v4_instruction = -1; +static gint ett_openflow_v4_instruction_actions_actions = -1; + +static expert_field ei_openflow_v4_match_undecoded = EI_INIT; +static expert_field ei_openflow_v4_instruction_undecoded = EI_INIT; static const value_string openflow_v4_version_values[] = { { 0x01, "1.0" }, @@ -155,6 +206,229 @@ static const value_string openflow_v4_type_values[] = { { 0, NULL } }; +#define OFPP_MAX 0xffffff00 /* Last usable port number. */ +static const value_string openflow_v4_port_reserved_values[] = { + { 0xfffffff8, "OFPP_IN_PORT" }, + { 0xfffffff9, "OFPP_TABLE" }, + { 0xfffffffa, "OFPP_NORMAL" }, + { 0xfffffffb, "OFPP_FLOOD" }, + { 0xfffffffc, "OFPP_ALL" }, + { 0xfffffffd, "OFPP_CONTROLLER" }, + { 0xfffffffe, "OFPP_LOCAL" }, + { 0xffffffff, "OFPP_ANY" }, + { 0, NULL } +}; + +#define OFPG_MAX 0xffffff00 /* Last usable group number. */ +static const value_string openflow_v4_group_reserved_values[] = { + { 0xfffffffc, "OFPG_ALL" }, + { 0xffffffff, "OFPG_ANY" }, + { 0, NULL } +}; + +#define OFPTT_MAX 254 /* Last usable table number. */ +static const value_string openflow_v4_table_reserved_values[] = { + { 255, "OFPTT_ALL"}, + { 0, NULL} +}; + + +#define OFP_NO_BUFFER 0xffffffff /* No buffering. */ +static const value_string openflow_v4_buffer_reserved_values[] = { + { 0xffffffff, "OFP_NO_BUFFER" }, + { 0, NULL} +}; + +#define OFPXMC_NXM_0 0x0000 /* Backward compatibility with NXM */ +#define OFPXMC_NXM_1 0x0001 /* Backward compatibility with NXM */ +#define OFPXMC_OPENFLOW_BASIC 0x8000 /* Basic class for OpenFlow */ +#define OFPXMC_EXPERIMENTER 0xFFFF /* Experimenter class */ +static const value_string openflow_v4_oxm_class_values[] = { + { 0x0000, "OFPXMC_NMX_0" }, + { 0x0001, "OFPXMC_NXM_1" }, + { 0x8000, "OFPXMC_OPENFLOW_BASIC" }, + { 0xFFFF, "OFPXMC_EXPERIMENTER" }, + { 0, NULL} +}; + +static const value_string openflow_v4_oxm_basic_field_values[] = { + { 0, "OFPXMT_OFB_IN_PORT" }, + { 1, "OFPXMT_OFB_IN_PHY_PORT" }, + { 2, "OFPXMT_OFB_METADATA" }, + { 3, "OFPXMT_OFB_ETH_DST" }, + { 4, "OFPXMT_OFB_ETH_SRC" }, + { 5, "OFPXMT_OFB_ETH_TYPE" }, + { 6, "OFPXMT_OFB_VLAN_VID" }, + { 7, "OFPXMT_OFB_VLAN_PCP" }, + { 8, "OFPXMT_OFB_IP_DSCP" }, + { 9, "OFPXMT_OFB_IP_ECN" }, + { 10, "OFPXMT_OFB_IP_PROTO" }, + { 11, "OFPXMT_OFB_IPV4_SRC" }, + { 12, "OFPXMT_OFB_IPV4_DST" }, + { 13, "OFPXMT_OFB_TCP_SRC" }, + { 14, "OFPXMT_OFB_TCP_DST" }, + { 15, "OFPXMT_OFB_UDP_SRC" }, + { 16, "OFPXMT_OFB_UDP_DST" }, + { 17, "OFPXMT_OFB_SCTP_SRC" }, + { 18, "OFPXMT_OFB_SCTP_DST" }, + { 19, "OFPXMT_OFB_ICMPV4_TYPE" }, + { 20, "OFPXMT_OFB_ICMPV4_CODE" }, + { 21, "OFPXMT_OFB_ARP_OP" }, + { 22, "OFPXMT_OFB_ARP_SPA" }, + { 23, "OFPXMT_OFB_ARP_TPA" }, + { 24, "OFPXMT_OFB_ARP_SHA" }, + { 25, "OFPXMT_OFB_ARP_THA" }, + { 26, "OFPXMT_OFB_IPV6_SRC" }, + { 27, "OFPXMT_OFB_IPV6_DST" }, + { 28, "OFPXMT_OFB_IPV6_FLABEL" }, + { 29, "OFPXMT_OFB_ICMPV6_TYPE" }, + { 30, "OFPXMT_OFB_ICMPV6_CODE" }, + { 31, "OFPXMT_OFB_IPV6_ND_TARGET" }, + { 32, "OFPXMT_OFB_IPV6_ND_SLL" }, + { 33, "OFPXMT_OFB_IPV6_ND_TLL" }, + { 34, "OFPXMT_OFB_MPLS_LABEL" }, + { 35, "OFPXMT_OFB_MPLS_TC" }, + { 36, "OFPXMT_OFP_MPLS_BOS" }, + { 37, "OFPXMT_OFB_PBB_ISID" }, + { 38, "OFPXMT_OFB_TUNNEL_ID" }, + { 39, "OFPXMT_OFB_IPV6_EXTHDR" }, + { 0, NULL } +}; + +#define OXM_FIELD_MASK 0xfe +#define OXM_FIELD_OFFSET 1 +#define OXM_HM_MASK 0x01 +static int +dissect_openflow_oxm_header_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint16 length _U_) +{ + guint16 oxm_class; + + /* oxm_class */ + oxm_class = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(tree, hf_openflow_v4_oxm_class, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* oxm_field */ + if (oxm_class == OFPXMC_OPENFLOW_BASIC) { + proto_tree_add_bits_item(tree, hf_openflow_v4_oxm_field_basic, tvb, (offset * 8), 7, ENC_NA); + } else { + proto_tree_add_bits_item(tree, hf_openflow_v4_oxm_field, tvb, (offset * 8), 7, ENC_NA); + } + + /* oxm_hm */ + proto_tree_add_bits_item(tree, hf_openflow_v4_oxm_hm, tvb, (offset * 8) + 7, 1, ENC_NA); + offset+=1; + + /* oxm_length */ + proto_tree_add_item(tree, hf_openflow_v4_oxm_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset+=1; + + return offset; +} + +static int +dissect_openflow_oxm_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint16 length _U_) +{ + proto_item *ti; + proto_tree *oxm_tree; + guint8 oxm_field_hm; + guint8 oxm_hm; + guint8 oxm_length; + + oxm_field_hm = tvb_get_guint8(tvb, offset + 2); + oxm_length = tvb_get_guint8(tvb, offset + 3); + + ti = proto_tree_add_text(tree, tvb, offset, oxm_length + 4, "OXM"); + oxm_tree = proto_item_add_subtree(ti, ett_openflow_v4_oxm); + + offset = dissect_openflow_oxm_header_v4(tvb, pinfo, oxm_tree, offset, length); + + oxm_hm = oxm_field_hm & OXM_HM_MASK; + if (oxm_hm != 0) { + oxm_length /= 2; + } + + /* value */ + if (oxm_length > 0) { + proto_tree_add_item(oxm_tree, hf_openflow_v4_oxm_value, tvb, offset, oxm_length, ENC_BIG_ENDIAN); + offset += oxm_length; + } + + /* mask */ + if (oxm_length > 0 && oxm_hm != 0) { + proto_tree_add_item(oxm_tree, hf_openflow_v4_oxm_mask, tvb, offset, oxm_length, ENC_BIG_ENDIAN); + offset += oxm_length; + } + + return offset; +} + +#define OFPMT_STANDARD 0 /* Standard Match. Deprecated. */ +#define OFPMT_OXM 1 /* OpenFlow Extensible Match */ +static const value_string openflow_v4_match_type_values[] = { + { 0, "OFPMT_STANDARD" }, + { 1, "OFPMT_OXM" }, + { 0, NULL } +}; + +static int +dissect_openflow_match_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint16 length _U_) +{ + proto_item *ti; + proto_tree *match_tree, *fields_tree; + guint16 match_type; + guint16 match_length; + guint16 fields_end; + guint16 pad_length; + + ti = proto_tree_add_text(tree, tvb, offset, -1, "Match"); + match_tree = proto_item_add_subtree(ti, ett_openflow_v4_match); + + /* uint16_t type; */ + match_type = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(match_tree, hf_openflow_v4_match_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint16_t length; (excluding padding) */ + match_length = tvb_get_ntohs(tvb, offset); + pad_length = (match_length + 7)/8*8 - match_length; + proto_item_set_len(ti, match_length + pad_length); + proto_tree_add_item(match_tree, hf_openflow_v4_match_length, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* body */ + switch (match_type) { + case OFPMT_STANDARD: + proto_tree_add_expert_format(match_tree, pinfo, &ei_openflow_v4_match_undecoded, + tvb, offset, match_length - 4, "Standard match (deprecated)."); + offset+=match_length-4; + break; + case OFPMT_OXM: + ti = proto_tree_add_text(match_tree, tvb, offset, match_length - 4, "Fields"); + fields_tree = proto_item_add_subtree(ti, ett_openflow_v4_match_oxm_fields); + + fields_end = offset + match_length - 4; + while(offset < fields_end) { + offset = dissect_openflow_oxm_v4(tvb, pinfo, fields_tree, offset, length); + } + break; + default: + proto_tree_add_expert_format(match_tree, pinfo, &ei_openflow_v4_match_undecoded, + tvb, offset, match_length - 4, "Unknown match."); + offset+=match_length-4; + break; + } + + /* pad; Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of all-zero bytes. */ + if (pad_length > 0) { + proto_tree_add_item(match_tree, hf_openflow_v4_match_pad, tvb, offset, pad_length, ENC_BIG_ENDIAN); + offset+=pad_length; + } + + return offset; +} + + #define OFPC_V4_FLOW_STATS 1<<0 /* Flow statistics. */ #define OFPC_V4_TABLE_STATS 1<<1 /* Table statistics. */ #define OFPC_V4_PORT_STATS 1<<2 /* Port statistics. */ @@ -226,6 +500,239 @@ dissect_openflow_features_reply_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_ } +#define OFPIT_GOTO_TABLE 1 /* Setup the next table in the lookup */ +#define OFPIT_WRITE_METADATA 2 /* Setup the metadata field for use later in */ +#define OFPIT_WRITE_ACTIONS 3 /* Write the action(s) onto the datapath action */ +#define OFPIT_APPLY_ACTIONS 4 /* Applies the action(s) immediately */ +#define OFPIT_CLEAR_ACTIONS 5 /* Clears all actions from the datapath */ +#define OFPIT_METER 6 /* Apply meter (rate limiter) */ +#define OFPIT_EXPERIMENTER 0xFFFF /* Experimenter instruction */ +static const value_string openflow_v4_instruction_type_values[] = { + { 0x0001, "OFPIT_GOTO_TABLE" }, + { 0x0002, "OFPIT_WRITE_METADATA" }, + { 0x0003, "OFPIT_WRITE_ACTIONS" }, + { 0x0004, "OFPIT_APPLY_ACTIONS" }, + { 0x0005, "OFPIT_CLEAR_ACTIONS" }, + { 0x0006, "OFPIT_METER" }, + { 0xffff, "OFPIT_EXPERIMENTER = 0xFFFF" }, + { 0, NULL } +}; + +#define OFPM_MAX 0xffffff00 /* Last usable meter number. */ +static const value_string openflow_v4_meter_id_reserved_values[] = { + { 0xfffffffd, "OFPM_SLOWPATH" }, + { 0xfffffffe, "OFPM_CONTROLLER" }, + { 0xffffffff, "OFPM_ALL" }, + { 0, NULL } +}; + +static int +dissect_openflow_instruction_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint16 length _U_) +{ + proto_item *ti; + proto_tree *inst_tree, *actions_tree; + guint16 inst_type; + guint16 inst_length; + + ti = proto_tree_add_text(tree, tvb, offset, -1, "Instruction"); + inst_tree = proto_item_add_subtree(ti, ett_openflow_v4_instruction); + + /* uint16_t type; */ + inst_type = tvb_get_ntohs(tvb, offset); + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint16_t length; */ + inst_length = tvb_get_ntohs(tvb, offset); + proto_item_set_len(ti, inst_length); + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_length, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + switch (inst_type) { + case OFPIT_GOTO_TABLE: + /* uint8_t table_id; */ + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_goto_table_table_id, tvb, offset, 1, ENC_BIG_ENDIAN); + offset+=1; + + /* uint8_t pad[3]; */ + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_goto_table_pad, tvb, offset, 3, ENC_BIG_ENDIAN); + offset+=3; + break; + + case OFPIT_WRITE_METADATA: + /* uint8_t pad[4]; */ + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_write_metadata_pad, tvb, offset, 4, ENC_BIG_ENDIAN); + offset+=4; + + /* uint64_t metadata; */ + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_write_metadata_value, tvb, offset, 8, ENC_BIG_ENDIAN); + offset+=8; + + /* uint64_t metadata_mask; */ + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_write_metadata_mask, tvb, offset, 8, ENC_BIG_ENDIAN); + offset+=8; + break; + + case OFPIT_WRITE_ACTIONS: + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_actions_pad, tvb, offset, 4, ENC_BIG_ENDIAN); + offset+=4; + + ti = proto_tree_add_text(inst_tree, tvb, offset, inst_length - 8, "Actions"); + actions_tree = proto_item_add_subtree(ti, ett_openflow_v4_instruction_actions_actions); + + proto_tree_add_text(actions_tree, tvb, offset, 0, "Actions not dissected yet"); + offset += inst_length - 8; + break; + + case OFPIT_APPLY_ACTIONS: + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_actions_pad, tvb, offset, 4, ENC_BIG_ENDIAN); + offset+=4; + + ti = proto_tree_add_text(inst_tree, tvb, offset, inst_length - 8, "Actions"); + actions_tree = proto_item_add_subtree(ti, ett_openflow_v4_instruction_actions_actions); + + proto_tree_add_text(actions_tree, tvb, offset, 0, "Actions not dissected yet"); + offset += inst_length - 8; + break; + + case OFPIT_CLEAR_ACTIONS: + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_actions_pad, tvb, offset, 4, ENC_BIG_ENDIAN); + offset+=4; + break; + + case OFPIT_METER: + /* uint32_t meter_id; */ + if (tvb_get_ntohl(tvb, offset) <= OFPM_MAX) { + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_meter_meter_id, tvb, offset, 4, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(inst_tree, hf_openflow_v4_instruction_meter_meter_id_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); + } + offset+=4; + break; + + case OFPIT_EXPERIMENTER: + proto_tree_add_expert_format(inst_tree, pinfo, &ei_openflow_v4_instruction_undecoded, + tvb, offset, inst_length - 4, "Experimenter instruction."); + offset += inst_length - 4; + break; + + default: + proto_tree_add_expert_format(inst_tree, pinfo, &ei_openflow_v4_instruction_undecoded, + tvb, offset, inst_length - 4, "Unknown instruction."); + offset += inst_length - 4; + break; + } + + return offset; +} + + +static const value_string openflow_v4_flowmod_command_values[] = { + { 0, "OFPFC_ADD" }, + { 1, "OFPFC_MODIFY" }, + { 2, "OFPFC_MODIFY_STRICT" }, + { 3, "OFPFC_DELETE" }, + { 4, "OFPFC_DELETE_STRICT" }, + { 0, NULL } +}; + +#define OFPFF_SEND_FLOW_REM 1 << 0 /* Send flow removed message when flow expires or is deleted. */ +#define OFPFF_CHECK_OVERLAP 1 << 1 /* Check for overlapping entries first. */ +#define OFPFF_RESET_COUNTS 1 << 2 /* Reset flow packet and byte counts. */ +#define OFPFF_NO_PKT_COUNTS 1 << 3 /* Don't keep track of packet count. */ +#define OFPFF_NO_BYT_COUNTS 1 << 4 /* Don't keep track of byte count. */ + +static void +dissect_openflow_flowmod_v4(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, guint16 length) +{ + proto_item *ti; + proto_tree *flags_tree, *instructions_tree; + + /* uint64_t cookie; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_cookie, tvb, offset, 8, ENC_BIG_ENDIAN); + offset+=8; + + /* uint64_t cookie_mask; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_cookie_mask, tvb, offset, 8, ENC_BIG_ENDIAN); + offset+=8; + + /* uint8_t table_id; */ + if (tvb_get_guint8(tvb, offset) <= OFPTT_MAX) { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_table_id, tvb, offset, 1, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_table_id_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); + } + offset+=1; + + /* uint8_t command; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_command, tvb, offset, 1, ENC_BIG_ENDIAN); + offset+=1; + + /* uint16_t idle_timeout; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_idle_timeout, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint16_t hard_timeout; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_hard_timeout, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint16_t priority; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_priority, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint32_t buffer_id; */ + if (tvb_get_ntohl(tvb, offset) != OFP_NO_BUFFER) { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_buffer_id, tvb, offset, 4, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_buffer_id_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); + } + offset+=4; + + /* uint32_t out_port; */ + if (tvb_get_ntohl(tvb, offset) <= OFPP_MAX) { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_out_port, tvb, offset, 4, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_out_port_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); + } + offset+=4; + + /* uint32_t out_group; */ + if (tvb_get_ntohl(tvb, offset) <= OFPG_MAX) { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_out_group, tvb, offset, 4, ENC_BIG_ENDIAN); + } else { + proto_tree_add_item(tree, hf_openflow_v4_flowmod_out_group_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); + } + offset+=4; + + /* uint16_t flags; */ + ti = proto_tree_add_item(tree, hf_openflow_v4_flowmod_flags, tvb, offset, 2, ENC_BIG_ENDIAN); + flags_tree = proto_item_add_subtree(ti, ett_openflow_v4_flowmod_flags); + + proto_tree_add_item(flags_tree, hf_openflow_v4_flowmod_flags_send_flow_rem, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(flags_tree, hf_openflow_v4_flowmod_flags_check_overlap, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(flags_tree, hf_openflow_v4_flowmod_flags_reset_counts, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(flags_tree, hf_openflow_v4_flowmod_flags_no_packet_counts, tvb, offset, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(flags_tree, hf_openflow_v4_flowmod_flags_no_byte_counts, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* uint8_t pad[2]; */ + proto_tree_add_item(tree, hf_openflow_v4_flowmod_pad, tvb, offset, 2, ENC_BIG_ENDIAN); + offset+=2; + + /* struct ofp_match match; */ + offset = dissect_openflow_match_v4(tvb, pinfo, tree, offset, length); + + /* struct ofp_instruction instructions[0]; */ + if (offset < length) { + ti = proto_tree_add_text(tree, tvb, offset, length - offset, "Instructions"); + instructions_tree = proto_item_add_subtree(ti, ett_openflow_v4_flowmod_instructions); + + while (offset < length) { + offset = dissect_openflow_instruction_v4(tvb, pinfo, instructions_tree, offset, length); + } + } +} + /* enum ofp_multipart_types { */ /* Description of this OpenFlow switch. * The request body is empty. @@ -445,6 +952,10 @@ dissect_openflow_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d dissect_openflow_features_reply_v4(tvb, pinfo, openflow_tree, offset, length); break; + case OFPT_V4_FLOW_MOD: /* 14 */ + dissect_openflow_flowmod_v4(tvb, pinfo, openflow_tree, offset, length); + break; + case OFPT_V4_MULTIPART_REQUEST: /* 18 */ dissect_openflow_multipart_request_v4(tvb, pinfo, openflow_tree, offset, length); break; @@ -492,6 +1003,106 @@ proto_register_openflow_v4(void) FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, + { &hf_openflow_v4_oxm_class, + { "Class", "openflow_v4.oxm.class", + FT_UINT16, BASE_HEX, VALS(openflow_v4_oxm_class_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_field, + { "Field", "openflow_v4.oxm.field", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_field_basic, + { "Field", "openflow_v4.oxm.field", + FT_UINT8, BASE_DEC, VALS(openflow_v4_oxm_basic_field_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_hm, + { "Has mask", "openflow_v4.oxm.hm", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_length, + { "Length", "openflow_v4.oxm.length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_value, + { "Value", "openflow_v4.oxm.value", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_oxm_mask, + { "Mask", "openflow_v4.oxm.mask", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_match_type, + { "Type", "openflow_v4.match.type", + FT_UINT16, BASE_DEC, VALS(openflow_v4_match_type_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_match_length, + { "Length", "openflow_v4.match.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_match_pad, + { "Padding", "openflow_v4.match.pad", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_type, + { "Type", "openflow_v4.instruction.type", + FT_UINT16, BASE_DEC, VALS(openflow_v4_instruction_type_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_length, + { "Length", "openflow_v4.instruction.length", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_goto_table_table_id, + { "Table ID", "openflow_v4.instruction.goto_table.table_id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_goto_table_pad, + { "Padding", "openflow_v4.instruction.goto_table.pad", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_write_metadata_pad, + { "Padding", "openflow_v4.instruction.write_metadata.pad", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_write_metadata_value, + { "Value", "openflow_v4.instruction.write_metadata.value", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_write_metadata_mask, + { "Mask", "openflow_v4.instruction.write_metadata.mask", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_actions_pad, + { "Padding", "openflow_v4.instruction.actions.pad", + FT_BYTES, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_meter_meter_id, + { "Meter ID", "openflow_v4.instruction.meter.meter_id", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_instruction_meter_meter_id_reserved, + { "Meter ID", "openflow_v4.instruction.meter.meter_id", + FT_UINT32, BASE_HEX, VALS(openflow_v4_meter_id_reserved_values), 0x0, + NULL, HFILL } + }, { &hf_openflow_v4_datapath_id, { "Datapath unique ID", "openflow_v4.datapath_id", FT_UINT64, BASE_HEX, NULL, 0x0, @@ -527,11 +1138,6 @@ proto_register_openflow_v4(void) FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_openflow_v4_pad3, - { "Padding", "openflow_v4.pad3", - FT_UINT24, BASE_DEC, NULL, 0x0, - NULL, HFILL } - }, { &hf_openflow_v4_padd32, { "Padding", "openflow_v4.padding32", FT_UINT32, BASE_DEC, NULL, 0x0, @@ -577,6 +1183,111 @@ proto_register_openflow_v4(void) FT_BOOLEAN, 32, NULL, OFPC_V4_PORT_BLOCKED, NULL, HFILL } }, + { &hf_openflow_v4_flowmod_cookie, + { "Cookie", "openflow_v4.flowmod.cookie", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_cookie_mask, + { "Cookie mask", "openflow_v4.flowmod.cookie_mask", + FT_UINT64, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_table_id, + { "Table ID", "openflow_v4.flowmod.table_id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_table_id_reserved, + { "Table ID", "openflow_v4.flowmod.table_id", + FT_UINT8, BASE_DEC, VALS(openflow_v4_table_reserved_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_command, + { "Command", "openflow_v4.flowmod.command", + FT_UINT8, BASE_DEC, VALS(openflow_v4_flowmod_command_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_idle_timeout, + { "Idle timeout", "openflow_v4.flowmod.idle_timeout", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_hard_timeout, + { "Hard timeout", "openflow_v4.flowmod.hard_timeout", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_priority, + { "Priority", "openflow_v4.flowmod.priority", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_buffer_id, + { "Buffer ID", "openflow_v4.flowmod.buffer_id", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_buffer_id_reserved, + { "Buffer ID", "openflow_v4.flowmod.buffer_id", + FT_UINT32, BASE_HEX, VALS(openflow_v4_buffer_reserved_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_out_port, + { "Out port", "openflow_v4.flowmod.out_port", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_out_port_reserved, + { "Out port", "openflow_v4.flowmod.out_port", + FT_UINT32, BASE_HEX, VALS(openflow_v4_port_reserved_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_out_group, + { "Out group", "openflow_v4.flowmod.out_group", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_out_group_reserved, + { "Out group", "openflow_v4.flowmod.out_group", + FT_UINT32, BASE_HEX, VALS(openflow_v4_group_reserved_values), 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags, + { "Flags", "openflow_v4.flowmod.flags", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags_send_flow_rem, + { "Send flow removed", "openflow_v4.flowmod.flags.send_flow_rem", + FT_BOOLEAN, 16, NULL, OFPFF_SEND_FLOW_REM, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags_check_overlap, + { "Check overlap", "openflow_v4.flowmod.flags.check_overlap", + FT_BOOLEAN, 16, NULL, OFPFF_CHECK_OVERLAP, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags_reset_counts, + { "Reset counts", "openflow_v4.flowmod.flags.reset_counts", + FT_BOOLEAN, 16, NULL, OFPFF_RESET_COUNTS, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags_no_packet_counts, + { "Don't count packets", "openflow_v4.flowmod.flags.no_packet_counts", + FT_BOOLEAN, 16, NULL, OFPFF_NO_PKT_COUNTS, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_flags_no_byte_counts, + { "Don't count bytes", "openflow_v4.flowmod.flags.no_byte_counts", + FT_BOOLEAN, 16, NULL, OFPFF_NO_BYT_COUNTS, + NULL, HFILL } + }, + { &hf_openflow_v4_flowmod_pad, + { "Padding", "openflow_v4.flowmod.pad", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, { &hf_openflow_v4_multipart_type, { "Type", "openflow_v4.multipart_type", FT_UINT16, BASE_DEC, VALS(openflow_v4_multipart_type_values), 0x0, @@ -591,24 +1302,44 @@ proto_register_openflow_v4(void) { "Flags", "openflow_v4.multipart_request_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } - }, + } }; - static gint *ett[] = { &ett_openflow_v4, &ett_openflow_v4_path_id, - &ett_openflow_v4_cap, + &ett_openflow_v4_cap, + &ett_openflow_v4_flowmod_flags, + &ett_openflow_v4_flowmod_instructions, + &ett_openflow_v4_oxm, + &ett_openflow_v4_match, + &ett_openflow_v4_match_oxm_fields, + &ett_openflow_v4_instruction, + &ett_openflow_v4_instruction_actions_actions + }; + + static ei_register_info ei[] = { + { &ei_openflow_v4_match_undecoded, + { "openflow_v4.match.undecoded", PI_UNDECODED, PI_NOTE, + "Unknown match.", EXPFILL } + }, + { &ei_openflow_v4_instruction_undecoded, + { "openflow_v4.instruction.undecoded", PI_UNDECODED, PI_NOTE, + "Unknown instruction.", EXPFILL } + } }; + expert_module_t *expert_openflow_v4; + /* Register the protocol name and description */ proto_openflow_v4 = proto_register_protocol("OpenFlow_V4", "openflow_v4", "openflow_v4"); - new_register_dissector("openflow_v4", dissect_openflow_v4, proto_openflow_v4); + new_register_dissector("openflow_v4", dissect_openflow_v4, proto_openflow_v4); /* Required function calls to register the header fields and subtrees */ proto_register_field_array(proto_openflow_v4, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); - -}
\ No newline at end of file + expert_openflow_v4 = expert_register_protocol(proto_openflow_v4); + expert_register_field_array(expert_openflow_v4, ei, array_length(ei)); +} |