aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-openflow_v4.c
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2013-10-19 20:19:35 +0000
committerAnders Broman <anders.broman@ericsson.com>2013-10-19 20:19:35 +0000
commit3c813bbcc13945fe137ac9cf7a62176942c52103 (patch)
treec5f034589ff95ac2a5ae89b1aead03c352b8a93b /epan/dissectors/packet-openflow_v4.c
parent09e32f5fb8310940e9bebf33e0a4398e76b41eeb (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/dissectors/packet-openflow_v4.c')
-rw-r--r--epan/dissectors/packet-openflow_v4.c755
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));
+}