/* packet-cisco-fp-mim.c
- * Routines for analyzing Cisco FabricPath MiM packets
+ * Routines for analyzing Cisco FabricPath MiM (MAC-in-MAA) packets
* Copyright 2011, Leonard Tracy <letracy@cisco.com>
*
* Wireshark - Network traffic analyzer
*/
/*
- * See
- *
- * http://www.cisco.com/c/en/us/products/collateral/switches/nexus-7000-series-switches/white_paper_c11-687554.html
+ * https://clnv.s3.amazonaws.com/2016/usa/pdf/BRKDCT-3313.pdf
+ * https://clnv.s3.amazonaws.com/2014/eur/pdf/BRKDCT-2081.pdf
*/
#include "config.h"
void proto_register_mim(void);
void proto_reg_handoff_fabricpath(void);
-static int proto_fp = -1 ;
-static gint ett_mim = -1 ;
-static gint ett_hmac = -1 ;
+static int proto_fp = -1;
+static gint ett_mim = -1;
+static gint ett_hmac = -1;
/* Main protocol items */
static int hf_s_hmac = -1;
static int hf_ftag = -1;
static int hf_ttl = -1;
-
+static int hf_fp_etype = -1;
+static int hf_fp_1ad_etype = -1;
+static int hf_fp_1ad_priority = -1;
+static int hf_fp_1ad_cfi = -1;
+static int hf_fp_1ad_svid = -1;
/* HMAC subtrees */
-static int hf_swid = -1 ;
+static int hf_swid = -1;
static int hf_sswid = -1;
static int hf_eid = -1;
static int hf_lid = -1;
"Deliver in order (If DA) or Learn (If SA)"
};
-static dissector_handle_t eth_maybefcs_dissector ;
-
+static dissector_handle_t eth_maybefcs_dissector;
#define FP_PROTO_COL_NAME "FabricPath"
#define FP_PROTO_COL_INFO "Cisco FabricPath MiM Encapsulated Frame"
#define FP_HMAC_SSWID_MASK G_GINT64_CONSTANT(0x000000FF0000)
#define FP_HMAC_LID_MASK G_GINT64_CONSTANT(0x00000000FFFF)
-
#define FP_HMAC_LEN 6
#define FP_HEADER_SIZE (16)
+#define FP_HEADER_WITH_1AD_SIZE (20)
+/* 0100.0000.0000 */
+#define MAC_MC_BC G_GINT64_CONSTANT(0x010000000000)
static int dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ );
* These packets are a bit strange.
*
* They run over Ethernet, but, instead of a normal 14-octet Ethernet
- * header, they have a 16-octet header, which happens to have, in the
- * position occupied by the Type/Length field in an Ethernet header,
- * the Ethertype value reserved for FabricPath.
+ * header, they have a 16-octet or 20-octet header, which happens to
+ * have, in the position occupied by the Type/Length field in an
+ * Ethernet header, the Ethertype value reserved for FabricPath.
*
* The fields in the positions occupied by the destination and source
* MAC addresses in an Ethernet header are occupied by addresses that
static gboolean
dissect_fp_heur (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
-
- guint16 type = 0;
-
- /*
- * Is ethertype ETHERTYPE_DCE
- */
-
- type = tvb_get_ntohs (tvb, 12);
-
- if (type == ETHERTYPE_DCE) {
- dissect_fp (tvb, pinfo, tree, NULL);
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
-static gboolean
-fp_is_ig_set (guint64 hmac)
-{
- if (hmac & FP_HMAC_IG_MASK) {
+ if (dissect_fp (tvb, pinfo, tree, NULL) > 0) {
return TRUE;
} else {
return FALSE;
proto_tree_add_item (tree, hf_lid, tvb, offset, FP_LID_LEN, ENC_BIG_ENDIAN);
/*offset += FP_LID_LEN;*/
-
}
+
/* FabricPath MiM Dissector */
static int
dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ )
{
- proto_item *ti ;
- proto_tree *fp_tree ;
- proto_tree *fp_addr_tree ;
- tvbuff_t *next_tvb ;
- int offset = 0 ;
+ proto_item *ti;
+ proto_tree *fp_tree;
+ proto_tree *fp_addr_tree;
+ tvbuff_t *next_tvb;
+ int offset = 0;
+ int header_size = 0;
guint64 hmac_src;
guint64 hmac_dst;
guint16 sswid = 0;
guint16 dswid = 0;
guint16 dsswid = 0;
guint16 dlid = 0;
+ guint16 etype = 0;
const guint8 *dst_addr = NULL;
- gboolean dest_ig = FALSE;
+ gboolean dest_as_mac = FALSE;
+
+ etype = tvb_get_ntohs (tvb, 12);
+
+ if (etype == ETHERTYPE_DCE) {
+ header_size = FP_HEADER_SIZE;
+ } else if (etype == ETHERTYPE_IEEE_802_1AD && tvb_get_ntohs(tvb, 16) == ETHERTYPE_DCE) {
+ header_size = FP_HEADER_WITH_1AD_SIZE;
+ } else {
+ return 0;
+ }
- col_set_str( pinfo->cinfo, COL_PROTOCOL, FP_PROTO_COL_NAME ) ;
- col_set_str( pinfo->cinfo, COL_INFO, FP_PROTO_COL_INFO ) ;
+ col_set_str( pinfo->cinfo, COL_PROTOCOL, FP_PROTO_COL_NAME );
+ col_set_str( pinfo->cinfo, COL_INFO, FP_PROTO_COL_INFO );
if (tree) {
+ /*
+ * Outer SA:
+ * - SwitchID ingress FP switch system ID
+ * - SubswitchID is used in some cases of VPC+
+ * - LID (Local ID) is specific to the implementation
+ * + N7K the LID is generally the port index of the ingress interface
+ * + N5K/N6K LID most of the time will be 0
+ * + EndnodeID is not currently used
+ *
+ * Outer DA:
+ * - For known SA/DA is taken from MAC table for DMAC
+ * - For broadcast and multicast is the same as DMAC
+ * - For unknown unicast DA is 010f.ffc1.01c0 (flood to vlan)
+ * - For known unicast DA, but unknown SA is 010f.ffc1.02c0 (flood to fabric)
+ */
hmac_dst = tvb_get_ntoh48 (tvb, 0);
hmac_src = tvb_get_ntoh48 (tvb, 6);
- dest_ig = fp_is_ig_set(hmac_dst);
- if (!dest_ig) {
+ if (hmac_dst & MAC_MC_BC) {
+ dest_as_mac = TRUE;
+ }
+ if (!dest_as_mac) {
fp_get_hmac_addr (hmac_dst, &dswid, &dsswid, &dlid);
} else {
hmac_dst = GUINT64_TO_BE (hmac_dst);
*/
dst_addr = ((const guint8 *) &hmac_dst) + 2;
}
-
-
-
fp_get_hmac_addr (hmac_src, &sswid, &ssswid, &slid);
+ /* FIXME: Does this make sense??? */
if (PTREE_DATA(tree)->visible) {
- if (dest_ig) {
+ if (dest_as_mac) {
address ether_addr;
set_address(ðer_addr, AT_ETHER, 6, dst_addr);
- ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, FP_HEADER_SIZE,
+ ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, header_size,
"Cisco FabricPath, Src: %03x.%02x.%04x, Dst: %s",
sswid, ssswid, slid,
address_with_resolution_to_str(wmem_packet_scope(), ðer_addr));
} else {
- ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, FP_HEADER_SIZE,
+ ti = proto_tree_add_protocol_format(tree, proto_fp, tvb, 0, header_size,
"Cisco FabricPath, Src: %03x.%02x.%04x, Dst: %03x.%02x.%04x",
sswid, ssswid, slid,
dswid, dsswid, dlid);
}
} else {
- ti = proto_tree_add_item( tree, proto_fp, tvb, 0, -1, ENC_NA ) ;
+ ti = proto_tree_add_item( tree, proto_fp, tvb, 0, header_size, ENC_NA );
}
- fp_tree = proto_item_add_subtree( ti, ett_mim ) ;
+ fp_tree = proto_item_add_subtree( ti, ett_mim );
- offset = 0;
/* Add dest and source heir. mac */
- if (dest_ig) {
+ if (dest_as_mac) {
/* MCAST address */
- proto_tree_add_ether( fp_tree, hf_d_hmac_mc, tvb, offset, 6,
- dst_addr);
+ proto_tree_add_ether( fp_tree, hf_d_hmac_mc, tvb, offset, 6, dst_addr);
} else {
/* Unicast */
ti = proto_tree_add_none_format (fp_tree, hf_d_hmac, tvb, offset, 6, "Destination: %03x.%02x.%04x", dswid, dsswid, dlid);
fp_addr_tree = proto_item_add_subtree (ti, ett_hmac);
fp_add_hmac (tvb, fp_addr_tree, offset);
}
-
offset += FP_HMAC_LEN;
+
ti = proto_tree_add_none_format (fp_tree, hf_s_hmac, tvb, offset, 6,
"Source: %03x.%02x.%04x", sswid, ssswid, slid);
fp_addr_tree = proto_item_add_subtree (ti, ett_hmac);
fp_add_hmac (tvb, fp_addr_tree, offset);
-
offset += FP_HMAC_LEN;
- /* Skip ethertype */
- offset += 2;
- proto_tree_add_item (fp_tree, hf_ftag, tvb, offset, FP_FTAG_LEN, ENC_BIG_ENDIAN);
+ etype = tvb_get_ntohs(tvb, offset);
+ switch (etype) {
+ case ETHERTYPE_DCE:
+ proto_tree_add_item(fp_tree, hf_fp_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ break;
+ case ETHERTYPE_IEEE_802_1AD:
+ proto_tree_add_item(fp_tree, hf_fp_1ad_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(fp_tree, hf_fp_1ad_priority, tvb, offset, 2, ENC_NA);
+ proto_tree_add_item(fp_tree, hf_fp_1ad_cfi, tvb, offset, 2, ENC_NA);
+ proto_tree_add_item(fp_tree, hf_fp_1ad_svid, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ proto_tree_add_item(fp_tree, hf_fp_etype, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
+ break;
+ default:
+ offset += 2;
+ /* The heuristics should prevent us from getting here */
+ DISSECTOR_ASSERT(0);
+ }
+ proto_tree_add_item (fp_tree, hf_ftag, tvb, offset, FP_FTAG_LEN, ENC_BIG_ENDIAN);
proto_tree_add_item (fp_tree, hf_ttl, tvb, offset, FP_FTAG_LEN, ENC_BIG_ENDIAN);
-
+ offset += 2;
}
+
/* call the eth dissector */
- next_tvb = tvb_new_subset_remaining( tvb, FP_HEADER_SIZE) ;
+ next_tvb = tvb_new_subset_remaining( tvb, header_size );
/*
* For now, we don't know whether there's an FCS in the captured data.
*/
- call_dissector( eth_maybefcs_dissector, next_tvb, pinfo, tree ) ;
+ call_dissector( eth_maybefcs_dissector, next_tvb, pinfo, tree );
- return tvb_captured_length( tvb ) ;
+ return tvb_captured_length( tvb );
}
/* Register the protocol with Wireshark */
FT_ETHER, BASE_NONE, NULL,
0, "Multicast Destination Address", HFILL }},
+ { &hf_fp_etype,
+ { "FP Ethertype", "cfp.etype", FT_UINT16, BASE_HEX,
+ VALS(etype_vals), 0x0, NULL, HFILL }},
+
+ { &hf_fp_1ad_etype,
+ { "1AD Ethertype", "cfp.1ad.etype", FT_UINT16, BASE_HEX,
+ VALS(etype_vals), 0x0, NULL, HFILL }},
+
+ { &hf_fp_1ad_priority,
+ { "Priority", "cfp.1ad.priority", FT_UINT16, BASE_DEC,
+ 0, 0xE000, NULL, HFILL }},
+
+ { &hf_fp_1ad_cfi,
+ { "DEI", "cfp.1ad.dei", FT_UINT16, BASE_DEC,
+ 0, 0x1000, "Drop Eligibility", HFILL }},
+
+ { &hf_fp_1ad_svid,
+ { "ID", "cfp.1ad.id", FT_UINT16, BASE_DEC,
+ 0, 0x0FFF, "Vlan ID", HFILL }},
+
{ &hf_ftag,
{ "FTAG", "cfp.ftag",
FT_UINT16, BASE_DEC, NULL, FP_FTAG_MASK,