# HG changeset patch # Parent a2215cca9d7418d88d4fe61e4f308e0dab681c80 # User Tommaso Pecorella # 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 (); - m_flowClassifier = Create (); - m_flowMonitor->SetFlowClassifier (m_flowClassifier); + m_flowClassifier4 = Create (); + m_flowMonitor->AddFlowClassifier (m_flowClassifier4); + m_flowClassifier6 = Create (); + m_flowMonitor->AddFlowClassifier (m_flowClassifier6); } return m_flowMonitor; } @@ -68,11 +74,22 @@ Ptr FlowMonitorHelper::GetClassifier () { - if (!m_flowClassifier) + if (!m_flowClassifier4) { - m_flowClassifier = Create (); + m_flowClassifier4 = Create (); } - return m_flowClassifier; + return m_flowClassifier4; +} + + +Ptr +FlowMonitorHelper::GetClassifier6 () +{ + if (!m_flowClassifier6) + { + m_flowClassifier6 = Create (); + } + return m_flowClassifier6; } @@ -88,6 +105,14 @@ DynamicCast (classifier), node); } + Ptr classifier6 = GetClassifier6 (); + Ptr ipv6 = node->GetObject (); + if (ipv6) + { + Ptr probe6 = Create (monitor, + DynamicCast (classifier6), + node); + } return m_flowMonitor; } @@ -98,7 +123,7 @@ for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) { Ptr node = *i; - if (node->GetObject ()) + if (node->GetObject () || node->GetObject ()) { Install (node); } @@ -112,7 +137,7 @@ for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) { Ptr node = *i; - if (node->GetObject ()) + if (node->GetObject () || node->GetObject ()) { 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 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 GetClassifier (); + /** + * \brief Retrieve the FlowClassifier object for IPv6 created by the Install* methods + * \returns a pointer to the FlowClassifier object + */ + Ptr GetClassifier6 (); + private: /** * \brief Copy constructor @@ -94,9 +101,10 @@ */ FlowMonitorHelper& operator= (const FlowMonitorHelper&); - ObjectFactory m_monitorFactory; //!< Object factory - Ptr m_flowMonitor; //!< the FlowMonitor object - Ptr m_flowClassifier; //!< the FlowClassifier object + ObjectFactory m_monitorFactory; //!< Object factory + Ptr m_flowMonitor; //!< the FlowMonitor object + Ptr m_flowClassifier4; //!< the FlowClassifier object for IPv4 + Ptr 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 >::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 classifier) +FlowMonitor::AddFlowClassifier (Ptr classifier) { - m_classifier = classifier; + m_classifiers.push_back (classifier); } void @@ -458,7 +463,12 @@ indent -= 2; INDENT (indent); os << "\n"; - m_classifier->SerializeToXmlStream (os, indent); + for (std::list >::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 classifier); + void AddFlowClassifier (Ptr 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 > m_flowProbes; //!< all the FlowProbes // note: this is needed only for serialization - Ptr m_classifier; //!< the FlowClassifier + std::list > 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 +// Modifications: Tommaso Pecorella +// + +#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 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::iterator, bool> insert + = m_flowMap.insert (std::pair (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::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 << "\n"; + + indent += 2; + for (std::map::const_iterator + iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++) + { + INDENT (indent); + os << "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 << "\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 +// Modifications: Tommaso Pecorella +// + +#ifndef IPV6_FLOW_CLASSIFIER_H +#define IPV6_FLOW_CLASSIFIER_H + +#include +#include + +#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 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 m_flowMap; + std::map 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 +// Modifications: Tommaso Pecorella +// + +#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 () + .AddConstructor () + ; + 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 monitor, + Ptr classifier, + Ptr node) + : FlowProbe (monitor), + m_classifier (classifier) +{ + NS_LOG_FUNCTION (this << node->GetId ()); + + Ptr ipv6 = node->GetObject (); + + if (!ipv6->TraceConnectWithoutContext ("SendOutgoing", + MakeCallback (&Ipv6FlowProbe::SendOutgoingLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + if (!ipv6->TraceConnectWithoutContext ("UnicastForward", + MakeCallback (&Ipv6FlowProbe::ForwardLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + if (!ipv6->TraceConnectWithoutContext ("LocalDeliver", + MakeCallback (&Ipv6FlowProbe::ForwardUpLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + + if (!ipv6->TraceConnectWithoutContext ("Drop", + MakeCallback (&Ipv6FlowProbe::DropLogger, Ptr (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 (this))); +} + +Ipv6FlowProbe::~Ipv6FlowProbe () +{ +} + +void +Ipv6FlowProbe::DoDispose () +{ + FlowProbe::DoDispose (); +} + +void +Ipv6FlowProbe::SendOutgoingLogger (const Ipv6Header &ipHeader, Ptr 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 ("<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 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 ("<ReportForwarding (this, flowId, packetId, size); + } +} + +void +Ipv6FlowProbe::ForwardUpLogger (const Ipv6Header &ipHeader, Ptr 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 (ipPayload)->RemovePacketTag (fTag); + + if (found) + { + FlowId flowId = fTag.GetFlowId (); + FlowPacketId packetId = fTag.GetPacketId (); + + uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ()); + NS_LOG_DEBUG ("ReportLastRx ("<ReportLastRx (this, flowId, packetId, size); + } +} + +void +Ipv6FlowProbe::DropLogger (const Ipv6Header &ipHeader, Ptr ipPayload, + Ipv6L3Protocol::DropReason reason, Ptr 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 (ipPayload)->RemovePacketTag (fTag); + + if (found) + { + FlowId flowId = fTag.GetFlowId (); + FlowPacketId packetId = fTag.GetPacketId (); + + uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ()); + NS_LOG_DEBUG ("Drop ("<ReportDrop (this, flowId, packetId, size, myReason); + } +} + +void +Ipv6FlowProbe::QueueDropLogger (Ptr 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 (ipPayload)->RemovePacketTag (fTag); + if (!tagFound) + { + return; + } + + FlowId flowId = fTag.GetFlowId (); + FlowPacketId packetId = fTag.GetPacketId (); + uint32_t size = fTag.GetPacketSize (); + + NS_LOG_DEBUG ("Drop ("<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 +// Modifications: Tommaso Pecorella +// + +#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 monitor, Ptr classifier, Ptr 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 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 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 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 ipPayload, + Ipv6L3Protocol::DropReason reason, Ptr ipv6, uint32_t ifIndex); + /// Log a packet being dropped by a queue + /// \param ipPayload IP payload + void QueueDropLogger (Ptr ipPayload); + + Ptr 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 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, DropReason, Ptr, uint32_t> m_dropTrace; + /// Trace of sent packets + TracedCallback, uint32_t> m_sendOutgoingTrace; + /// Trace of unicast forwarded packets + TracedCallback, uint32_t> m_unicastForwardTrace; + /// Trace of locally delivered packets + TracedCallback, uint32_t> m_localDeliverTrace; + /** * \brief Copy constructor. *