# HG changeset patch
# Parent a2215cca9d7418d88d4fe61e4f308e0dab681c80
# User Tommaso Pecorella <tommaso.pecorella@unifi.it>
# Date 1390552170 -3600

Bug 1818: FlowMonitor needs IPv6 support

diff --git a/src/flow-monitor/helper/flow-monitor-helper.cc b/src/flow-monitor/helper/flow-monitor-helper.cc
--- a/src/flow-monitor/helper/flow-monitor-helper.cc
+++ b/src/flow-monitor/helper/flow-monitor-helper.cc
@@ -24,6 +24,9 @@
 #include "ns3/ipv4-flow-classifier.h"
 #include "ns3/ipv4-flow-probe.h"
 #include "ns3/ipv4-l3-protocol.h"
+#include "ns3/ipv6-flow-classifier.h"
+#include "ns3/ipv6-flow-probe.h"
+#include "ns3/ipv6-l3-protocol.h"
 #include "ns3/node.h"
 #include "ns3/node-list.h"
 
@@ -41,7 +44,8 @@
     {
       m_flowMonitor->Dispose ();
       m_flowMonitor = 0;
-      m_flowClassifier = 0;
+      m_flowClassifier4 = 0;
+      m_flowClassifier6 = 0;
     }
 }
 
@@ -58,8 +62,10 @@
   if (!m_flowMonitor)
     {
       m_flowMonitor = m_monitorFactory.Create<FlowMonitor> ();
-      m_flowClassifier = Create<Ipv4FlowClassifier> ();
-      m_flowMonitor->SetFlowClassifier (m_flowClassifier);
+      m_flowClassifier4 = Create<Ipv4FlowClassifier> ();
+      m_flowMonitor->AddFlowClassifier (m_flowClassifier4);
+      m_flowClassifier6 = Create<Ipv6FlowClassifier> ();
+      m_flowMonitor->AddFlowClassifier (m_flowClassifier6);
     }
   return m_flowMonitor;
 }
@@ -68,11 +74,22 @@
 Ptr<FlowClassifier>
 FlowMonitorHelper::GetClassifier ()
 {
-  if (!m_flowClassifier)
+  if (!m_flowClassifier4)
     {
-      m_flowClassifier = Create<Ipv4FlowClassifier> ();
+      m_flowClassifier4 = Create<Ipv4FlowClassifier> ();
     }
-  return m_flowClassifier;
+  return m_flowClassifier4;
+}
+
+
+Ptr<FlowClassifier>
+FlowMonitorHelper::GetClassifier6 ()
+{
+  if (!m_flowClassifier6)
+    {
+      m_flowClassifier6 = Create<Ipv6FlowClassifier> ();
+    }
+  return m_flowClassifier6;
 }
 
 
@@ -88,6 +105,14 @@
                                                         DynamicCast<Ipv4FlowClassifier> (classifier),
                                                         node);
     }
+  Ptr<FlowClassifier> classifier6 = GetClassifier6 ();
+  Ptr<Ipv6L3Protocol> ipv6 = node->GetObject<Ipv6L3Protocol> ();
+  if (ipv6)
+    {
+      Ptr<Ipv6FlowProbe> probe6 = Create<Ipv6FlowProbe> (monitor,
+                                                         DynamicCast<Ipv6FlowClassifier> (classifier6),
+                                                         node);
+    }
   return m_flowMonitor;
 }
 
@@ -98,7 +123,7 @@
   for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
     {
       Ptr<Node> node = *i;
-      if (node->GetObject<Ipv4L3Protocol> ())
+      if (node->GetObject<Ipv4L3Protocol> () || node->GetObject<Ipv6L3Protocol> ())
         {
           Install (node);
         }
@@ -112,7 +137,7 @@
   for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i)
     {
       Ptr<Node> node = *i;
-      if (node->GetObject<Ipv4L3Protocol> ())
+      if (node->GetObject<Ipv4L3Protocol> () || node->GetObject<Ipv6L3Protocol> ())
         {
           Install (node);
         }
diff --git a/src/flow-monitor/helper/flow-monitor-helper.h b/src/flow-monitor/helper/flow-monitor-helper.h
--- a/src/flow-monitor/helper/flow-monitor-helper.h
+++ b/src/flow-monitor/helper/flow-monitor-helper.h
@@ -30,10 +30,11 @@
 
 class AttributeValue;
 class Ipv4FlowClassifier;
+class Ipv6FlowClassifier;
 
 /**
  * \ingroup flow-monitor
- * \brief Helper to enable IPv4 flow monitoring on a set of Nodes
+ * \brief Helper to enable IP flow monitoring on a set of Nodes
  */
 class FlowMonitorHelper
 {
@@ -74,11 +75,17 @@
   Ptr<FlowMonitor> GetMonitor ();
 
   /**
-   * \brief Retrieve the FlowClassifier object created by the Install* methods
+   * \brief Retrieve the FlowClassifier object for IPv4 created by the Install* methods
    * \returns a pointer to the FlowClassifier object
    */
   Ptr<FlowClassifier> GetClassifier ();
 
+  /**
+   * \brief Retrieve the FlowClassifier object for IPv6 created by the Install* methods
+   * \returns a pointer to the FlowClassifier object
+   */
+  Ptr<FlowClassifier> GetClassifier6 ();
+
 private:
   /**
    * \brief Copy constructor
@@ -94,9 +101,10 @@
    */
   FlowMonitorHelper& operator= (const FlowMonitorHelper&);
 
-  ObjectFactory m_monitorFactory;       //!< Object factory
-  Ptr<FlowMonitor> m_flowMonitor;       //!< the FlowMonitor object
-  Ptr<FlowClassifier> m_flowClassifier; //!< the FlowClassifier object
+  ObjectFactory m_monitorFactory;        //!< Object factory
+  Ptr<FlowMonitor> m_flowMonitor;        //!< the FlowMonitor object
+  Ptr<FlowClassifier> m_flowClassifier4; //!< the FlowClassifier object for IPv4
+  Ptr<FlowClassifier> m_flowClassifier6; //!< the FlowClassifier object for IPv6
 };
 
 } // namespace ns3
diff --git a/src/flow-monitor/model/flow-monitor.cc b/src/flow-monitor/model/flow-monitor.cc
--- a/src/flow-monitor/model/flow-monitor.cc
+++ b/src/flow-monitor/model/flow-monitor.cc
@@ -92,7 +92,12 @@
 void
 FlowMonitor::DoDispose (void)
 {
-  m_classifier = 0;
+  for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
+      iter != m_classifiers.end ();
+      iter ++)
+    {
+      *iter = 0;
+    }
   for (uint32_t i = 0; i < m_flowProbes.size (); i++)
     {
       m_flowProbes[i]->Dispose ();
@@ -391,9 +396,9 @@
 }
 
 void
-FlowMonitor::SetFlowClassifier (Ptr<FlowClassifier> classifier)
+FlowMonitor::AddFlowClassifier (Ptr<FlowClassifier> classifier)
 {
-  m_classifier = classifier;
+  m_classifiers.push_back (classifier);
 }
 
 void
@@ -458,7 +463,12 @@
   indent -= 2;
   INDENT (indent); os << "</FlowStats>\n";
 
-  m_classifier->SerializeToXmlStream (os, indent);
+  for (std::list<Ptr<FlowClassifier> >::iterator iter = m_classifiers.begin ();
+      iter != m_classifiers.end ();
+      iter ++)
+    {
+      (*iter)->SerializeToXmlStream (os, indent);
+    }
 
   if (enableProbes)
     {
diff --git a/src/flow-monitor/model/flow-monitor.h b/src/flow-monitor/model/flow-monitor.h
--- a/src/flow-monitor/model/flow-monitor.h
+++ b/src/flow-monitor/model/flow-monitor.h
@@ -146,9 +146,9 @@
   TypeId GetInstanceTypeId () const;
   FlowMonitor ();
 
-  /// Set the FlowClassifier to be used by the flow monitor.
+  /// Add a FlowClassifier to be used by the flow monitor.
   /// \param classifier the FlowClassifier
-  void SetFlowClassifier (Ptr<FlowClassifier> classifier);
+  void AddFlowClassifier (Ptr<FlowClassifier> classifier);
 
   /// Set the time, counting from the current time, from which to start monitoring flows.
   /// \param time delta time to start
@@ -266,7 +266,7 @@
   std::vector< Ptr<FlowProbe> > m_flowProbes; //!< all the FlowProbes
 
   // note: this is needed only for serialization
-  Ptr<FlowClassifier> m_classifier; //!< the FlowClassifier
+  std::list<Ptr<FlowClassifier> > m_classifiers; //!< the FlowClassifiers
 
   EventId m_startEvent;     //!< Start event
   EventId m_stopEvent;      //!< Stop event
diff --git a/src/flow-monitor/model/ipv6-flow-classifier.cc b/src/flow-monitor/model/ipv6-flow-classifier.cc
new file mode 100644
--- /dev/null
+++ b/src/flow-monitor/model/ipv6-flow-classifier.cc
@@ -0,0 +1,218 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2009 INESC Porto
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
+// Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
+//
+
+#include "ns3/packet.h"
+
+#include "ipv6-flow-classifier.h"
+#include "ns3/udp-header.h"
+#include "ns3/tcp-header.h"
+
+namespace ns3 {
+
+/* see http://www.iana.org/assignments/protocol-numbers */
+const uint8_t TCP_PROT_NUMBER = 6;  //!< TCP Protocol number
+const uint8_t UDP_PROT_NUMBER = 17; //!< UDP Protocol number
+
+
+
+bool operator < (const Ipv6FlowClassifier::FiveTuple &t1,
+                 const Ipv6FlowClassifier::FiveTuple &t2)
+{
+  if (t1.sourceAddress < t2.sourceAddress)
+    {
+      return true;
+    }
+  if (t1.sourceAddress != t2.sourceAddress)
+    {
+      return false;
+    }
+
+  if (t1.destinationAddress < t2.destinationAddress)
+    {
+      return true;
+    }
+  if (t1.destinationAddress != t2.destinationAddress)
+    {
+      return false;
+    }
+
+  if (t1.protocol < t2.protocol)
+    {
+      return true;
+    }
+  if (t1.protocol != t2.protocol)
+    {
+      return false;
+    }
+
+  if (t1.sourcePort < t2.sourcePort)
+    {
+      return true;
+    }
+  if (t1.sourcePort != t2.sourcePort)
+    {
+      return false;
+    }
+
+  if (t1.destinationPort < t2.destinationPort)
+    {
+      return true;
+    }
+  if (t1.destinationPort != t2.destinationPort)
+    {
+      return false;
+    }
+
+  return false;
+}
+
+bool operator == (const Ipv6FlowClassifier::FiveTuple &t1,
+                  const Ipv6FlowClassifier::FiveTuple &t2)
+{
+  return (t1.sourceAddress      == t2.sourceAddress &&
+          t1.destinationAddress == t2.destinationAddress &&
+          t1.protocol           == t2.protocol &&
+          t1.sourcePort         == t2.sourcePort &&
+          t1.destinationPort    == t2.destinationPort);
+}
+
+
+
+Ipv6FlowClassifier::Ipv6FlowClassifier ()
+{
+}
+
+bool
+Ipv6FlowClassifier::Classify (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload,
+                              uint32_t *out_flowId, uint32_t *out_packetId)
+{
+  if (ipHeader.GetDestinationAddress ().IsMulticast ())
+    {
+      // we are not prepared to handle multicast yet
+      return false;
+    }
+
+  FiveTuple tuple;
+  tuple.sourceAddress = ipHeader.GetSourceAddress ();
+  tuple.destinationAddress = ipHeader.GetDestinationAddress ();
+  tuple.protocol = ipHeader.GetNextHeader ();
+
+  if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
+    {
+      return false;
+    }
+
+  if (ipPayload->GetSize () < 4)
+    {
+      // the packet doesn't carry enough bytes
+      return false;
+    }
+
+  // we rely on the fact that for both TCP and UDP the ports are
+  // carried in the first 4 octects.
+  // This allows to read the ports even on fragmented packets
+  // not carrying a full TCP or UDP header.
+
+  uint8_t data[4];
+  ipPayload->CopyData (data, 4);
+
+  uint16_t srcPort = 0;
+  srcPort |= data[0];
+  srcPort <<= 8;
+  srcPort |= data[1];
+
+  uint16_t dstPort = 0;
+  dstPort |= data[2];
+  dstPort <<= 8;
+  dstPort |= data[3];
+
+  tuple.sourcePort = srcPort;
+  tuple.destinationPort = dstPort;
+
+  // try to insert the tuple, but check if it already exists
+  std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert
+    = m_flowMap.insert (std::pair<FiveTuple, FlowId> (tuple, 0));
+
+  // if the insertion succeeded, we need to assign this tuple a new flow identifier
+  if (insert.second)
+    {
+      FlowId newFlowId = GetNewFlowId ();
+      insert.first->second = newFlowId;
+      m_flowPktIdMap[newFlowId] = 0;
+    }
+  else
+    {
+      m_flowPktIdMap[insert.first->second] ++;
+    }
+
+  *out_flowId = insert.first->second;
+  *out_packetId = m_flowPktIdMap[*out_flowId];
+
+  return true;
+}
+
+
+Ipv6FlowClassifier::FiveTuple
+Ipv6FlowClassifier::FindFlow (FlowId flowId) const
+{
+  for (std::map<FiveTuple, FlowId>::const_iterator
+       iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++)
+    {
+      if (iter->second == flowId)
+        {
+          return iter->first;
+        }
+    }
+  NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
+  FiveTuple retval = { Ipv6Address::GetZero (), Ipv6Address::GetZero (), 0, 0, 0 };
+  return retval;
+}
+
+void
+Ipv6FlowClassifier::SerializeToXmlStream (std::ostream &os, int indent) const
+{
+#define INDENT(level) for (int __xpto = 0; __xpto < level; __xpto++) os << ' ';
+
+  INDENT (indent); os << "<Ipv6FlowClassifier>\n";
+
+  indent += 2;
+  for (std::map<FiveTuple, FlowId>::const_iterator
+       iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++)
+    {
+      INDENT (indent);
+      os << "<Flow flowId=\"" << iter->second << "\""
+         << " sourceAddress=\"" << iter->first.sourceAddress << "\""
+         << " destinationAddress=\"" << iter->first.destinationAddress << "\""
+         << " protocol=\"" << int(iter->first.protocol) << "\""
+         << " sourcePort=\"" << iter->first.sourcePort << "\""
+         << " destinationPort=\"" << iter->first.destinationPort << "\""
+         << " />\n";
+    }
+
+  indent -= 2;
+  INDENT (indent); os << "</Ipv6FlowClassifier>\n";
+
+#undef INDENT
+}
+
+
+} // namespace ns3
+
diff --git a/src/flow-monitor/model/ipv6-flow-classifier.h b/src/flow-monitor/model/ipv6-flow-classifier.h
new file mode 100644
--- /dev/null
+++ b/src/flow-monitor/model/ipv6-flow-classifier.h
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2009 INESC Porto
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
+// Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
+//
+
+#ifndef IPV6_FLOW_CLASSIFIER_H
+#define IPV6_FLOW_CLASSIFIER_H
+
+#include <stdint.h>
+#include <map>
+
+#include "ns3/ipv6-header.h"
+#include "ns3/flow-classifier.h"
+
+namespace ns3 {
+
+class Packet;
+
+/// Classifies packets by looking at their IP and TCP/UDP headers.
+/// From these packet headers, a tuple (source-ip, destination-ip,
+/// protocol, source-port, destination-port) is created, and a unique
+/// flow identifier is assigned for each different tuple combination
+class Ipv6FlowClassifier : public FlowClassifier
+{
+public:
+
+  /// Structure to classify a packet
+  struct FiveTuple
+  {
+    Ipv6Address sourceAddress;      //!< Source address
+    Ipv6Address destinationAddress; //!< Destination address
+    uint8_t protocol;               //!< Protocol
+    uint16_t sourcePort;            //!< Source port
+    uint16_t destinationPort;       //!< Destination port
+  };
+
+  Ipv6FlowClassifier ();
+
+  /// \brief try to classify the packet into flow-id and packet-id
+  ///
+  /// \warning: it must be called only once per packet, from SendOutgoingLogger.
+  ///
+  /// \return true if the packet was classified, false if not (i.e. it
+  /// does not appear to be part of a flow).
+  /// \param ipHeader packet's IP header
+  /// \param ipPayload packet's IP payload
+  /// \param out_flowId packet's FlowId
+  /// \param out_packetId packet's identifier
+  bool Classify (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload,
+                 uint32_t *out_flowId, uint32_t *out_packetId);
+
+  /// Searches for the FiveTuple corresponding to the given flowId
+  /// \param flowId the FlowId to search for
+  /// \returns the FiveTuple corresponding to flowId
+  FiveTuple FindFlow (FlowId flowId) const;
+
+  virtual void SerializeToXmlStream (std::ostream &os, int indent) const;
+
+private:
+
+  /// Map to Flows Identifiers to FlowIds
+  std::map<FiveTuple, FlowId> m_flowMap;
+  std::map<FlowId, FlowPacketId> m_flowPktIdMap;
+
+};
+
+/**
+ * \brief Less than operator.
+ *
+ * \param t1 the first operand
+ * \param t2 the first operand
+ * \returns true if the operands are equal
+ */
+bool operator < (const Ipv6FlowClassifier::FiveTuple &t1, const Ipv6FlowClassifier::FiveTuple &t2);
+
+/**
+ * \brief Equal to operator.
+ *
+ * \param t1 the first operand
+ * \param t2 the first operand
+ * \returns true if the operands are equal
+ */
+bool operator == (const Ipv6FlowClassifier::FiveTuple &t1, const Ipv6FlowClassifier::FiveTuple &t2);
+
+
+} // namespace ns3
+
+#endif /* IPV6_FLOW_CLASSIFIER_H */
diff --git a/src/flow-monitor/model/ipv6-flow-probe.cc b/src/flow-monitor/model/ipv6-flow-probe.cc
new file mode 100644
--- /dev/null
+++ b/src/flow-monitor/model/ipv6-flow-probe.cc
@@ -0,0 +1,409 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2009 INESC Porto
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
+// Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
+//
+
+#include "ns3/ipv6-flow-probe.h"
+#include "ns3/ipv6-flow-classifier.h"
+#include "ns3/node.h"
+#include "ns3/packet.h"
+#include "ns3/flow-monitor.h"
+#include "ns3/log.h"
+#include "ns3/pointer.h"
+#include "ns3/config.h"
+#include "ns3/flow-id-tag.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("Ipv6FlowProbe")
+  ;
+
+//////////////////////////////////////
+// Ipv6FlowProbeTag class implementation //
+//////////////////////////////////////
+
+/**
+ * \ingroup flow-monitor
+ *
+ * \brief Tag used to allow a fast identification of the packet
+ *
+ * This tag is added by FlowMonitor when a packet is seen for
+ * the first time, and it is then used to classify the packet in
+ * the following hops.
+ */
+class Ipv6FlowProbeTag : public Tag
+{
+public:
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (TagBuffer buf) const;
+  virtual void Deserialize (TagBuffer buf);
+  virtual void Print (std::ostream &os) const;
+  Ipv6FlowProbeTag ();
+  /**
+   * \brief Consructor
+   * \param flowId the flow identifier
+   * \param packetId the packet identifier
+   * \param packetSize the packet size
+   */
+  Ipv6FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize);
+  /**
+   * \brief Set the flow identifier
+   * \param flowId the flow identifier
+   */
+  void SetFlowId (uint32_t flowId);
+  /**
+   * \brief Set the packet identifier
+   * \param packetId the packet identifier
+   */
+  void SetPacketId (uint32_t packetId);
+  /**
+   * \brief Set the packet size
+   * \param packetSize the packet size
+   */
+  void SetPacketSize (uint32_t packetSize);
+  /**
+   * \brief Set the flow identifier
+   * \returns the flow identifier
+   */
+  uint32_t GetFlowId (void) const;
+  /**
+   * \brief Set the packet identifier
+   * \returns the packet identifier
+   */
+  uint32_t GetPacketId (void) const;
+  /**
+   * \brief Get the packet size
+   * \returns the packet size
+   */
+  uint32_t GetPacketSize (void) const;
+private:
+  uint32_t m_flowId;      //!< flow identifier
+  uint32_t m_packetId;    //!< packet identifier
+  uint32_t m_packetSize;  //!< packet size
+
+};
+
+TypeId 
+Ipv6FlowProbeTag::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::Ipv6FlowProbeTag")
+    .SetParent<Tag> ()
+    .AddConstructor<Ipv6FlowProbeTag> ()
+  ;
+  return tid;
+}
+TypeId 
+Ipv6FlowProbeTag::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+uint32_t 
+Ipv6FlowProbeTag::GetSerializedSize (void) const
+{
+  return 4 + 4 + 4;
+}
+void 
+Ipv6FlowProbeTag::Serialize (TagBuffer buf) const
+{
+  buf.WriteU32 (m_flowId);
+  buf.WriteU32 (m_packetId);
+  buf.WriteU32 (m_packetSize);
+}
+void 
+Ipv6FlowProbeTag::Deserialize (TagBuffer buf)
+{
+  m_flowId = buf.ReadU32 ();
+  m_packetId = buf.ReadU32 ();
+  m_packetSize = buf.ReadU32 ();
+}
+void 
+Ipv6FlowProbeTag::Print (std::ostream &os) const
+{
+  os << "FlowId=" << m_flowId;
+  os << "PacketId=" << m_packetId;
+  os << "PacketSize=" << m_packetSize;
+}
+Ipv6FlowProbeTag::Ipv6FlowProbeTag ()
+  : Tag () 
+{
+}
+
+Ipv6FlowProbeTag::Ipv6FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize)
+  : Tag (), m_flowId (flowId), m_packetId (packetId), m_packetSize (packetSize)
+{
+}
+
+void
+Ipv6FlowProbeTag::SetFlowId (uint32_t id)
+{
+  m_flowId = id;
+}
+void
+Ipv6FlowProbeTag::SetPacketId (uint32_t id)
+{
+  m_packetId = id;
+}
+void
+Ipv6FlowProbeTag::SetPacketSize (uint32_t size)
+{
+  m_packetSize = size;
+}
+uint32_t
+Ipv6FlowProbeTag::GetFlowId (void) const
+{
+  return m_flowId;
+}
+uint32_t
+Ipv6FlowProbeTag::GetPacketId (void) const
+{
+  return m_packetId;
+} 
+uint32_t
+Ipv6FlowProbeTag::GetPacketSize (void) const
+{
+  return m_packetSize;
+} 
+
+////////////////////////////////////////
+// Ipv6FlowProbe class implementation //
+////////////////////////////////////////
+
+Ipv6FlowProbe::Ipv6FlowProbe (Ptr<FlowMonitor> monitor,
+                              Ptr<Ipv6FlowClassifier> classifier,
+                              Ptr<Node> node)
+  : FlowProbe (monitor),
+    m_classifier (classifier)
+{
+  NS_LOG_FUNCTION (this << node->GetId ());
+
+  Ptr<Ipv6L3Protocol> ipv6 = node->GetObject<Ipv6L3Protocol> ();
+
+  if (!ipv6->TraceConnectWithoutContext ("SendOutgoing",
+                                         MakeCallback (&Ipv6FlowProbe::SendOutgoingLogger, Ptr<Ipv6FlowProbe> (this))))
+    {
+      NS_FATAL_ERROR ("trace fail");
+    }
+  if (!ipv6->TraceConnectWithoutContext ("UnicastForward",
+                                         MakeCallback (&Ipv6FlowProbe::ForwardLogger, Ptr<Ipv6FlowProbe> (this))))
+    {
+      NS_FATAL_ERROR ("trace fail");
+    }
+  if (!ipv6->TraceConnectWithoutContext ("LocalDeliver",
+                                         MakeCallback (&Ipv6FlowProbe::ForwardUpLogger, Ptr<Ipv6FlowProbe> (this))))
+    {
+      NS_FATAL_ERROR ("trace fail");
+    }
+
+  if (!ipv6->TraceConnectWithoutContext ("Drop",
+                                         MakeCallback (&Ipv6FlowProbe::DropLogger, Ptr<Ipv6FlowProbe> (this))))
+    {
+      NS_FATAL_ERROR ("trace fail");
+    }
+
+  // code copied from point-to-point-helper.cc
+  std::ostringstream oss;
+  oss << "/NodeList/" << node->GetId () << "/DeviceList/*/TxQueue/Drop";
+  Config::ConnectWithoutContext (oss.str (), MakeCallback (&Ipv6FlowProbe::QueueDropLogger, Ptr<Ipv6FlowProbe> (this)));
+}
+
+Ipv6FlowProbe::~Ipv6FlowProbe ()
+{
+}
+
+void
+Ipv6FlowProbe::DoDispose ()
+{
+  FlowProbe::DoDispose ();
+}
+
+void
+Ipv6FlowProbe::SendOutgoingLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
+{
+  FlowId flowId;
+  FlowPacketId packetId;
+
+  if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
+    {
+      uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
+      NS_LOG_DEBUG ("ReportFirstTx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<"); "
+                                     << ipHeader << *ipPayload);
+      m_flowMonitor->ReportFirstTx (this, flowId, packetId, size);
+
+      // tag the packet with the flow id and packet id, so that the packet can be identified even
+      // when Ipv6Header is not accessible at some non-IPv6 protocol layer
+      Ipv6FlowProbeTag fTag (flowId, packetId, size);
+      ipPayload->AddPacketTag (fTag);
+    }
+}
+
+void
+Ipv6FlowProbe::ForwardLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
+{
+  // peek the tags that are added by Ipv6FlowProbe::SendOutgoingLogger ()
+  Ipv6FlowProbeTag fTag;
+
+  bool found = ipPayload->PeekPacketTag (fTag);
+
+  if (found)
+    {
+      FlowId flowId = fTag.GetFlowId ();
+      FlowPacketId packetId = fTag.GetPacketId ();
+
+      uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
+      NS_LOG_DEBUG ("ReportForwarding ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
+      m_flowMonitor->ReportForwarding (this, flowId, packetId, size);
+    }
+}
+
+void
+Ipv6FlowProbe::ForwardUpLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
+{
+  // remove the tags that are added by Ipv6FlowProbe::SendOutgoingLogger ()
+  Ipv6FlowProbeTag fTag;
+
+  // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+  bool found = ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+
+  if (found)
+    {
+      FlowId flowId = fTag.GetFlowId ();
+      FlowPacketId packetId = fTag.GetPacketId ();
+
+      uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
+      NS_LOG_DEBUG ("ReportLastRx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
+      m_flowMonitor->ReportLastRx (this, flowId, packetId, size);
+    }
+}
+
+void
+Ipv6FlowProbe::DropLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload,
+                           Ipv6L3Protocol::DropReason reason, Ptr<Ipv6> ipv6, uint32_t ifIndex)
+{
+#if 0
+  switch (reason)
+    {
+    case Ipv6L3Protocol::DROP_NO_ROUTE:
+      break;
+
+    case Ipv6L3Protocol::DROP_TTL_EXPIRED:
+    case Ipv6L3Protocol::DROP_BAD_CHECKSUM:
+      Ipv6Address addri = m_ipv6->GetAddress (ifIndex);
+      Ipv6Mask maski = m_ipv6->GetNetworkMask (ifIndex);
+      Ipv6Address bcast = addri.GetSubnetDirectedBroadcast (maski);
+      if (ipHeader.GetDestination () == bcast) // we don't want broadcast packets
+        {
+          return;
+        }
+    }
+#endif
+
+  // remove the tags that are added by Ipv6FlowProbe::SendOutgoingLogger ()
+  Ipv6FlowProbeTag fTag;
+
+  // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+  bool found = ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+
+  if (found)
+    {
+      FlowId flowId = fTag.GetFlowId ();
+      FlowPacketId packetId = fTag.GetPacketId ();
+
+      uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
+      NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << reason 
+                            << ", destIp=" << ipHeader.GetDestinationAddress () << "); "
+                            << "HDR: " << ipHeader << " PKT: " << *ipPayload);
+
+      DropReason myReason;
+
+
+      switch (reason)
+        {
+        case Ipv6L3Protocol::DROP_TTL_EXPIRED:
+          myReason = DROP_TTL_EXPIRE;
+          NS_LOG_DEBUG ("DROP_TTL_EXPIRE");
+          break;
+        case Ipv6L3Protocol::DROP_NO_ROUTE:
+          myReason = DROP_NO_ROUTE;
+          NS_LOG_DEBUG ("DROP_NO_ROUTE");
+          break;
+        case Ipv6L3Protocol::DROP_INTERFACE_DOWN:
+          myReason = DROP_INTERFACE_DOWN;
+          NS_LOG_DEBUG ("DROP_INTERFACE_DOWN");
+          break;
+        case Ipv6L3Protocol::DROP_ROUTE_ERROR:
+           myReason = DROP_ROUTE_ERROR;
+           NS_LOG_DEBUG ("DROP_ROUTE_ERROR");
+           break;
+        case Ipv6L3Protocol::DROP_UNKNOWN_PROTOCOL:
+           myReason = DROP_UNKNOWN_PROTOCOL;
+           NS_LOG_DEBUG ("DROP_UNKNOWN_PROTOCOL");
+           break;
+        case Ipv6L3Protocol::DROP_UNKNOWN_OPTION:
+           myReason = DROP_UNKNOWN_OPTION;
+           NS_LOG_DEBUG ("DROP_UNKNOWN_OPTION");
+           break;
+        case Ipv6L3Protocol::DROP_MALFORMED_HEADER:
+           myReason = DROP_MALFORMED_HEADER;
+           NS_LOG_DEBUG ("DROP_MALFORMED_HEADER");
+           break;
+        case Ipv6L3Protocol::DROP_FRAGMENT_TIMEOUT:
+          myReason = DROP_FRAGMENT_TIMEOUT;
+          NS_LOG_DEBUG ("DROP_FRAGMENT_TIMEOUT");
+          break;
+        default:
+          myReason = DROP_INVALID_REASON;
+          NS_FATAL_ERROR ("Unexpected drop reason code " << reason);
+        }
+
+      m_flowMonitor->ReportDrop (this, flowId, packetId, size, myReason);
+    }
+}
+
+void 
+Ipv6FlowProbe::QueueDropLogger (Ptr<const Packet> ipPayload)
+{
+  // remove the tags that are added by Ipv6FlowProbe::SendOutgoingLogger ()
+  Ipv6FlowProbeTag fTag;
+
+  // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+  bool tagFound = ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+  if (!tagFound)
+    {
+      return;
+    }
+
+  FlowId flowId = fTag.GetFlowId ();
+  FlowPacketId packetId = fTag.GetPacketId ();
+  uint32_t size = fTag.GetPacketSize ();
+
+  NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << DROP_QUEUE 
+                        << "); ");
+
+  m_flowMonitor->ReportDrop (this, flowId, packetId, size, DROP_QUEUE);
+}
+
+} // namespace ns3
+
+
diff --git a/src/flow-monitor/model/ipv6-flow-probe.h b/src/flow-monitor/model/ipv6-flow-probe.h
new file mode 100644
--- /dev/null
+++ b/src/flow-monitor/model/ipv6-flow-probe.h
@@ -0,0 +1,120 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2009 INESC Porto
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation;
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
+// Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
+//
+
+#ifndef IPV6_FLOW_PROBE_H
+#define IPV6_FLOW_PROBE_H
+
+#include "ns3/flow-probe.h"
+#include "ns3/ipv6-flow-classifier.h"
+#include "ns3/ipv6-l3-protocol.h"
+
+namespace ns3 {
+
+class FlowMonitor;
+class Node;
+
+/// \ingroup flow-monitor
+/// \brief Class that monitors flows at the IPv6 layer of a Node
+///
+/// For each node in the simulation, one instance of the class
+/// Ipv4FlowProbe is created to monitor that node.  Ipv4FlowProbe
+/// accomplishes this by connecting callbacks to trace sources in the
+/// Ipv6L3Protocol interface of the node.
+class Ipv6FlowProbe : public FlowProbe
+{
+
+public:
+  /// \brief Constructor
+  /// \param monitor the FlowMonitor this probe is associated with
+  /// \param classifier the Ipv4FlowClassifier this probe is associated with
+  /// \param node the Node this probe is associated with
+  Ipv6FlowProbe (Ptr<FlowMonitor> monitor, Ptr<Ipv6FlowClassifier> classifier, Ptr<Node> node);
+  virtual ~Ipv6FlowProbe ();
+
+  /// \brief enumeration of possible reasons why a packet may be dropped
+  enum DropReason 
+  {
+    /// Packet dropped due to missing route to the destination
+    DROP_NO_ROUTE = 0,
+
+    /// Packet dropped due to TTL decremented to zero during IPv4 forwarding
+    DROP_TTL_EXPIRE,
+
+    /// Packet dropped due to invalid checksum in the IPv4 header
+    DROP_BAD_CHECKSUM,
+
+    /// Packet dropped due to queue overflow.  Note: only works for
+    /// NetDevices that provide a TxQueue attribute of type Queue
+    /// with a Drop trace source.  It currently works with Csma and
+    /// PointToPoint devices, but not with WiFi or WiMax.
+    DROP_QUEUE,
+
+    DROP_INTERFACE_DOWN,   /**< Interface is down so can not send packet */
+    DROP_ROUTE_ERROR,   /**< Route error */
+
+    DROP_UNKNOWN_PROTOCOL, /**< Unknown L4 protocol */
+    DROP_UNKNOWN_OPTION, /**< Unknown option */
+    DROP_MALFORMED_HEADER, /**< Malformed header */
+
+    DROP_FRAGMENT_TIMEOUT, /**< Fragment timeout exceeded */
+
+    DROP_INVALID_REASON, /**< Fallback reason (no known reason) */
+  };
+
+protected:
+
+  virtual void DoDispose (void);
+
+private:
+  /// Log a packet being sent
+  /// \param ipHeader IP header
+  /// \param ipPayload IP payload
+  /// \param interface outgoing interface
+  void SendOutgoingLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
+  /// Log a packet being forwarded
+  /// \param ipHeader IP header
+  /// \param ipPayload IP payload
+  /// \param interface incoming interface
+  void ForwardLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
+  /// Log a packet being received by the destination
+  /// \param ipHeader IP header
+  /// \param ipPayload IP payload
+  /// \param interface incoming interface
+  void ForwardUpLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface);
+  /// Log a packet being dropped
+  /// \param ipHeader IP header
+  /// \param ipPayload IP payload
+  /// \param reason drop reason
+  /// \param ipv6 pointer to the IP object dropping the packet
+  /// \param ifIndex interface index
+  void DropLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload,
+                   Ipv6L3Protocol::DropReason reason, Ptr<Ipv6> ipv6, uint32_t ifIndex);
+  /// Log a packet being dropped by a queue
+  /// \param ipPayload IP payload
+  void QueueDropLogger (Ptr<const Packet> ipPayload);
+
+  Ptr<Ipv6FlowClassifier> m_classifier; //!< the Ipv6FlowClassifier this probe is associated with
+};
+
+
+} // namespace ns3
+
+#endif /* IPV6_FLOW_PROBE_H */
diff --git a/src/flow-monitor/wscript b/src/flow-monitor/wscript
--- a/src/flow-monitor/wscript
+++ b/src/flow-monitor/wscript
@@ -8,6 +8,8 @@
        'flow-probe.cc',
        'ipv4-flow-classifier.cc',
        'ipv4-flow-probe.cc',
+       'ipv6-flow-classifier.cc',
+       'ipv6-flow-probe.cc',
        'histogram.cc',	
         ]]
     obj.source.append("helper/flow-monitor-helper.cc")
@@ -25,6 +27,8 @@
        'flow-classifier.h',
        'ipv4-flow-classifier.h',
        'ipv4-flow-probe.h',
+       'ipv6-flow-classifier.h',
+       'ipv6-flow-probe.h',
        'histogram.h',
         ]]
     headers.source.append("helper/flow-monitor-helper.h")
diff --git a/src/internet/model/ipv6-l3-protocol.cc b/src/internet/model/ipv6-l3-protocol.cc
--- a/src/internet/model/ipv6-l3-protocol.cc
+++ b/src/internet/model/ipv6-l3-protocol.cc
@@ -85,6 +85,13 @@
                      MakeTraceSourceAccessor (&Ipv6L3Protocol::m_rxTrace))
     .AddTraceSource ("Drop", "Drop IPv6 packet",
                      MakeTraceSourceAccessor (&Ipv6L3Protocol::m_dropTrace))
+
+    .AddTraceSource ("SendOutgoing", "A newly-generated packet by this node is about to be queued for transmission",
+                     MakeTraceSourceAccessor (&Ipv6L3Protocol::m_sendOutgoingTrace))
+    .AddTraceSource ("UnicastForward", "A unicast IPv6 packet was received by this node and is being forwarded to another node",
+                     MakeTraceSourceAccessor (&Ipv6L3Protocol::m_unicastForwardTrace))
+    .AddTraceSource ("LocalDeliver", "An IPv6 packet was received by/for this node, and it is being forward up the stack",
+                     MakeTraceSourceAccessor (&Ipv6L3Protocol::m_localDeliverTrace))
   ;
   return tid;
 }
@@ -747,6 +754,8 @@
     {
       NS_LOG_LOGIC ("Ipv6L3Protocol::Send case 1: passed in with a route");
       hdr = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, tclass);
+      int32_t interface = GetInterfaceForDevice (route->GetOutputDevice ());
+      m_sendOutgoingTrace (hdr, packet, interface);
       SendRealOut (route, packet, hdr);
       return;
     }
@@ -757,6 +766,8 @@
       NS_LOG_LOGIC ("Ipv6L3Protocol::Send case 1: probably sent to machine on same IPv6 network");
       /* NS_FATAL_ERROR ("This case is not yet implemented"); */
       hdr = BuildHeader (source, destination, protocol, packet->GetSize (), ttl, tclass);
+      int32_t interface = GetInterfaceForDevice (route->GetOutputDevice ());
+      m_sendOutgoingTrace (hdr, packet, interface);
       SendRealOut (route, packet, hdr);
       return;
     }
@@ -786,6 +797,8 @@
 
   if (newRoute)
     {
+      int32_t interface = GetInterfaceForDevice (newRoute->GetOutputDevice ());
+      m_sendOutgoingTrace (hdr, packet, interface);
       SendRealOut (newRoute, packet, hdr);
     }
   else
@@ -1076,7 +1089,8 @@
           icmpv6->SendRedirection (copy, linkLocal, src, target, dst, Address ());
         }
     }
-
+  int32_t interface = GetInterfaceForDevice (rtentry->GetOutputDevice ());
+  m_unicastForwardTrace (ipHeader, packet, interface);
   SendRealOut (rtentry, packet, ipHeader);
 }
 
@@ -1187,6 +1201,9 @@
 
               /* L4 protocol */
               Ptr<Packet> copy = p->Copy ();
+
+              m_localDeliverTrace (ip, p, iif);
+
               enum IpL4Protocol::RxStatus status = protocol->Receive (p, ip, GetInterface (iif));
 
               switch (status)
diff --git a/src/internet/model/ipv6-l3-protocol.h b/src/internet/model/ipv6-l3-protocol.h
--- a/src/internet/model/ipv6-l3-protocol.h
+++ b/src/internet/model/ipv6-l3-protocol.h
@@ -427,6 +427,13 @@
    */ 
   TracedCallback<const Ipv6Header &, Ptr<const Packet>, DropReason, Ptr<Ipv6>, uint32_t> m_dropTrace;
 
+  /// Trace of sent packets
+  TracedCallback<const Ipv6Header &, Ptr<const Packet>, uint32_t> m_sendOutgoingTrace;
+  /// Trace of unicast forwarded packets
+  TracedCallback<const Ipv6Header &, Ptr<const Packet>, uint32_t> m_unicastForwardTrace;
+  /// Trace of locally delivered packets
+  TracedCallback<const Ipv6Header &, Ptr<const Packet>, uint32_t> m_localDeliverTrace;
+
   /**
    * \brief Copy constructor.
    *
