packet-cisco-fp-mim.c: Add support for FP packets that contain an extra QinQ header
authorJoerg Mayer <jmayer@loplof.de>
Fri, 29 Jun 2018 15:58:32 +0000 (17:58 +0200)
committerJörg Mayer <jmayer@loplof.de>
Sat, 30 Jun 2018 05:55:12 +0000 (05:55 +0000)
Also: Minor style cleanups (some still missing) and add two FP specific WKAs.

Change-Id: I908ec92ba4682caf8e9c9cc4fb44c2f9c336b4e3
Reviewed-on: https://code.wireshark.org/review/28535
Petri-Dish: Jörg Mayer <jmayer@loplof.de>
Tested-by: Petri Dish Buildbot
Reviewed-by: Jörg Mayer <jmayer@loplof.de>
epan/dissectors/packet-cisco-fp-mim.c
wka

index 49362c746d4ff5081c72a7e6a277d991e3ab32a1..6a9b33b9bd3e209dc94f5bf9f3ab65f8c1dbf8e2 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
@@ -10,9 +10,8 @@
  */
 
 /*
- * 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"
@@ -25,9 +24,9 @@
 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;
@@ -36,10 +35,14 @@ static int hf_d_hmac_mc = -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;
@@ -60,8 +63,7 @@ static const true_false_string ooodl_tfs = {
   "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"
@@ -91,10 +93,12 @@ static dissector_handle_t eth_maybefcs_dissector ;
 #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_ );
 
@@ -102,9 +106,9 @@ static int dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
  * 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
@@ -120,27 +124,7 @@ static int dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
 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;
@@ -185,17 +169,18 @@ fp_add_hmac (tvbuff_t *tvb, proto_tree *tree, int offset) {
 
   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;
@@ -204,19 +189,47 @@ dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
   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);
@@ -225,68 +238,83 @@ dissect_fp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
       */
       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(&ether_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(), &ether_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 */
@@ -309,6 +337,26 @@ proto_register_mim(void)
         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,
diff --git a/wka b/wka
index aea2880de2f0ceff95deaf81a1fce0a41bf8d4a5..3745abc2a9b5cb2333ac9320752bd5f9d6db7788 100644 (file)
--- a/wka
+++ b/wka
@@ -49,6 +49,9 @@
 01-00-81-00-00-02      Nortel-Network-Management
 01-00-81-00-01-00      Nortel-autodiscovery
 01-00-81-00-01-01      Nortel-autodiscovery
+# Cisco Fabric Path
+01-0F-FF-C1-01-C0      FP-Flood-to-all-VLANs
+01-0F-FF-C1-02-C0      FP-Flood-to-all-Fabrics
 #
 # As per
 #