1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 //
3 // Copyright (c) 2009 INESC Porto
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License version 2 as
7 // published by the Free Software Foundation;
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 //
18 // Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt> <gjcarneiro@gmail.com>
19 // Modifications: Tommaso Pecorella <tommaso.pecorella@unifi.it>
20 //
21 
22 #include "ns3/ipv6-flow-probe.h"
23 #include "ns3/ipv6-flow-classifier.h"
24 #include "ns3/node.h"
25 #include "ns3/packet.h"
26 #include "ns3/flow-monitor.h"
27 #include "ns3/log.h"
28 #include "ns3/pointer.h"
29 #include "ns3/config.h"
30 #include "ns3/flow-id-tag.h"
31 
32 namespace ns3 {
33 
34 NS_LOG_COMPONENT_DEFINE ("Ipv6FlowProbe");
35 
36 //////////////////////////////////////
37 // Ipv6FlowProbeTag class implementation //
38 //////////////////////////////////////
39 
40 /**
41  * \ingroup flow-monitor
42  *
43  * \brief Tag used to allow a fast identification of the packet
44  *
45  * This tag is added by FlowMonitor when a packet is seen for
46  * the first time, and it is then used to classify the packet in
47  * the following hops.
48  */
49 class Ipv6FlowProbeTag : public Tag
50 {
51 public:
52   /**
53    * \brief Get the type ID.
54    * \return the object TypeId
55    */
56   static TypeId GetTypeId (void);
57   virtual TypeId GetInstanceTypeId (void) const;
58   virtual uint32_t GetSerializedSize (void) const;
59   virtual void Serialize (TagBuffer buf) const;
60   virtual void Deserialize (TagBuffer buf);
61   virtual void Print (std::ostream &os) const;
62   Ipv6FlowProbeTag ();
63   /**
64    * \brief Consructor
65    * \param flowId the flow identifier
66    * \param packetId the packet identifier
67    * \param packetSize the packet size
68    */
69   Ipv6FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize);
70   /**
71    * \brief Set the flow identifier
72    * \param flowId the flow identifier
73    */
74   void SetFlowId (uint32_t flowId);
75   /**
76    * \brief Set the packet identifier
77    * \param packetId the packet identifier
78    */
79   void SetPacketId (uint32_t packetId);
80   /**
81    * \brief Set the packet size
82    * \param packetSize the packet size
83    */
84   void SetPacketSize (uint32_t packetSize);
85   /**
86    * \brief Set the flow identifier
87    * \returns the flow identifier
88    */
89   uint32_t GetFlowId (void) const;
90   /**
91    * \brief Set the packet identifier
92    * \returns the packet identifier
93    */
94   uint32_t GetPacketId (void) const;
95   /**
96    * \brief Get the packet size
97    * \returns the packet size
98    */
99   uint32_t GetPacketSize (void) const;
100 private:
101   uint32_t m_flowId;      //!< flow identifier
102   uint32_t m_packetId;    //!< packet identifier
103   uint32_t m_packetSize;  //!< packet size
104 
105 };
106 
107 TypeId
GetTypeId(void)108 Ipv6FlowProbeTag::GetTypeId (void)
109 {
110   static TypeId tid = TypeId ("ns3::Ipv6FlowProbeTag")
111     .SetParent<Tag> ()
112     .SetGroupName ("FlowMonitor")
113     .AddConstructor<Ipv6FlowProbeTag> ()
114   ;
115   return tid;
116 }
117 TypeId
GetInstanceTypeId(void) const118 Ipv6FlowProbeTag::GetInstanceTypeId (void) const
119 {
120   return GetTypeId ();
121 }
122 uint32_t
GetSerializedSize(void) const123 Ipv6FlowProbeTag::GetSerializedSize (void) const
124 {
125   return 4 + 4 + 4;
126 }
127 void
Serialize(TagBuffer buf) const128 Ipv6FlowProbeTag::Serialize (TagBuffer buf) const
129 {
130   buf.WriteU32 (m_flowId);
131   buf.WriteU32 (m_packetId);
132   buf.WriteU32 (m_packetSize);
133 }
134 void
Deserialize(TagBuffer buf)135 Ipv6FlowProbeTag::Deserialize (TagBuffer buf)
136 {
137   m_flowId = buf.ReadU32 ();
138   m_packetId = buf.ReadU32 ();
139   m_packetSize = buf.ReadU32 ();
140 }
141 void
Print(std::ostream & os) const142 Ipv6FlowProbeTag::Print (std::ostream &os) const
143 {
144   os << "FlowId=" << m_flowId;
145   os << "PacketId=" << m_packetId;
146   os << "PacketSize=" << m_packetSize;
147 }
Ipv6FlowProbeTag()148 Ipv6FlowProbeTag::Ipv6FlowProbeTag ()
149   : Tag ()
150 {
151 }
152 
Ipv6FlowProbeTag(uint32_t flowId,uint32_t packetId,uint32_t packetSize)153 Ipv6FlowProbeTag::Ipv6FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize)
154   : Tag (), m_flowId (flowId), m_packetId (packetId), m_packetSize (packetSize)
155 {
156 }
157 
158 void
SetFlowId(uint32_t id)159 Ipv6FlowProbeTag::SetFlowId (uint32_t id)
160 {
161   m_flowId = id;
162 }
163 void
SetPacketId(uint32_t id)164 Ipv6FlowProbeTag::SetPacketId (uint32_t id)
165 {
166   m_packetId = id;
167 }
168 void
SetPacketSize(uint32_t size)169 Ipv6FlowProbeTag::SetPacketSize (uint32_t size)
170 {
171   m_packetSize = size;
172 }
173 uint32_t
GetFlowId(void) const174 Ipv6FlowProbeTag::GetFlowId (void) const
175 {
176   return m_flowId;
177 }
178 uint32_t
GetPacketId(void) const179 Ipv6FlowProbeTag::GetPacketId (void) const
180 {
181   return m_packetId;
182 }
183 uint32_t
GetPacketSize(void) const184 Ipv6FlowProbeTag::GetPacketSize (void) const
185 {
186   return m_packetSize;
187 }
188 
189 ////////////////////////////////////////
190 // Ipv6FlowProbe class implementation //
191 ////////////////////////////////////////
192 
Ipv6FlowProbe(Ptr<FlowMonitor> monitor,Ptr<Ipv6FlowClassifier> classifier,Ptr<Node> node)193 Ipv6FlowProbe::Ipv6FlowProbe (Ptr<FlowMonitor> monitor,
194                               Ptr<Ipv6FlowClassifier> classifier,
195                               Ptr<Node> node)
196   : FlowProbe (monitor),
197     m_classifier (classifier)
198 {
199   NS_LOG_FUNCTION (this << node->GetId ());
200 
201   Ptr<Ipv6L3Protocol> ipv6 = node->GetObject<Ipv6L3Protocol> ();
202 
203   if (!ipv6->TraceConnectWithoutContext ("SendOutgoing",
204                                          MakeCallback (&Ipv6FlowProbe::SendOutgoingLogger, Ptr<Ipv6FlowProbe> (this))))
205     {
206       NS_FATAL_ERROR ("trace fail");
207     }
208   if (!ipv6->TraceConnectWithoutContext ("UnicastForward",
209                                          MakeCallback (&Ipv6FlowProbe::ForwardLogger, Ptr<Ipv6FlowProbe> (this))))
210     {
211       NS_FATAL_ERROR ("trace fail");
212     }
213   if (!ipv6->TraceConnectWithoutContext ("LocalDeliver",
214                                          MakeCallback (&Ipv6FlowProbe::ForwardUpLogger, Ptr<Ipv6FlowProbe> (this))))
215     {
216       NS_FATAL_ERROR ("trace fail");
217     }
218 
219   if (!ipv6->TraceConnectWithoutContext ("Drop",
220                                          MakeCallback (&Ipv6FlowProbe::DropLogger, Ptr<Ipv6FlowProbe> (this))))
221     {
222       NS_FATAL_ERROR ("trace fail");
223     }
224 
225   std::ostringstream qd;
226   qd << "/NodeList/" << node->GetId () << "/$ns3::TrafficControlLayer/RootQueueDiscList/*/Drop";
227   Config::ConnectWithoutContextFailSafe (qd.str (), MakeCallback (&Ipv6FlowProbe::QueueDiscDropLogger, Ptr<Ipv6FlowProbe> (this)));
228 
229   // code copied from point-to-point-helper.cc
230   std::ostringstream oss;
231   oss << "/NodeList/" << node->GetId () << "/DeviceList/*/TxQueue/Drop";
232   Config::ConnectWithoutContextFailSafe (oss.str (), MakeCallback (&Ipv6FlowProbe::QueueDropLogger, Ptr<Ipv6FlowProbe> (this)));
233 }
234 
235 /* static */
236 TypeId
GetTypeId(void)237 Ipv6FlowProbe::GetTypeId (void)
238 {
239   static TypeId tid = TypeId ("ns3::Ipv6FlowProbe")
240     .SetParent<FlowProbe> ()
241     .SetGroupName ("FlowMonitor")
242     // No AddConstructor because this class has no default constructor.
243     ;
244 
245   return tid;
246 }
247 
~Ipv6FlowProbe()248 Ipv6FlowProbe::~Ipv6FlowProbe ()
249 {
250 }
251 
252 void
DoDispose()253 Ipv6FlowProbe::DoDispose ()
254 {
255   FlowProbe::DoDispose ();
256 }
257 
258 void
SendOutgoingLogger(const Ipv6Header & ipHeader,Ptr<const Packet> ipPayload,uint32_t interface)259 Ipv6FlowProbe::SendOutgoingLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
260 {
261   FlowId flowId;
262   FlowPacketId packetId;
263 
264   if (m_classifier->Classify (ipHeader, ipPayload, &flowId, &packetId))
265     {
266       uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
267       NS_LOG_DEBUG ("ReportFirstTx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<"); "
268                                      << ipHeader << *ipPayload);
269       m_flowMonitor->ReportFirstTx (this, flowId, packetId, size);
270 
271       // tag the packet with the flow id and packet id, so that the packet can be identified even
272       // when Ipv6Header is not accessible at some non-IPv6 protocol layer
273       Ipv6FlowProbeTag fTag (flowId, packetId, size);
274       ipPayload->AddByteTag (fTag);
275     }
276 }
277 
278 void
ForwardLogger(const Ipv6Header & ipHeader,Ptr<const Packet> ipPayload,uint32_t interface)279 Ipv6FlowProbe::ForwardLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
280 {
281   Ipv6FlowProbeTag fTag;
282   bool found = ipPayload->FindFirstMatchingByteTag (fTag);
283 
284   if (found)
285     {
286       FlowId flowId = fTag.GetFlowId ();
287       FlowPacketId packetId = fTag.GetPacketId ();
288 
289       uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
290       NS_LOG_DEBUG ("ReportForwarding ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
291       m_flowMonitor->ReportForwarding (this, flowId, packetId, size);
292     }
293 }
294 
295 void
ForwardUpLogger(const Ipv6Header & ipHeader,Ptr<const Packet> ipPayload,uint32_t interface)296 Ipv6FlowProbe::ForwardUpLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload, uint32_t interface)
297 {
298   Ipv6FlowProbeTag fTag;
299   bool found = ipPayload->FindFirstMatchingByteTag (fTag);
300 
301   if (found)
302     {
303       FlowId flowId = fTag.GetFlowId ();
304       FlowPacketId packetId = fTag.GetPacketId ();
305 
306       uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
307       NS_LOG_DEBUG ("ReportLastRx ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<");");
308       m_flowMonitor->ReportLastRx (this, flowId, packetId, size);
309     }
310 }
311 
312 void
DropLogger(const Ipv6Header & ipHeader,Ptr<const Packet> ipPayload,Ipv6L3Protocol::DropReason reason,Ptr<Ipv6> ipv6,uint32_t ifIndex)313 Ipv6FlowProbe::DropLogger (const Ipv6Header &ipHeader, Ptr<const Packet> ipPayload,
314                            Ipv6L3Protocol::DropReason reason, Ptr<Ipv6> ipv6, uint32_t ifIndex)
315 {
316 #if 0
317   switch (reason)
318     {
319     case Ipv6L3Protocol::DROP_NO_ROUTE:
320       break;
321 
322     case Ipv6L3Protocol::DROP_TTL_EXPIRED:
323     case Ipv6L3Protocol::DROP_BAD_CHECKSUM:
324       Ipv6Address addri = m_ipv6->GetAddress (ifIndex);
325       Ipv6Mask maski = m_ipv6->GetNetworkMask (ifIndex);
326       Ipv6Address bcast = addri.GetSubnetDirectedBroadcast (maski);
327       if (ipHeader.GetDestination () == bcast) // we don't want broadcast packets
328         {
329           return;
330         }
331     }
332 #endif
333 
334   Ipv6FlowProbeTag fTag;
335   bool found = ipPayload->FindFirstMatchingByteTag (fTag);
336 
337   if (found)
338     {
339       FlowId flowId = fTag.GetFlowId ();
340       FlowPacketId packetId = fTag.GetPacketId ();
341 
342       uint32_t size = (ipPayload->GetSize () + ipHeader.GetSerializedSize ());
343       NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << reason
344                             << ", destIp=" << ipHeader.GetDestination () << "); "
345                             << "HDR: " << ipHeader << " PKT: " << *ipPayload);
346 
347       DropReason myReason;
348 
349 
350       switch (reason)
351         {
352         case Ipv6L3Protocol::DROP_TTL_EXPIRED:
353           myReason = DROP_TTL_EXPIRE;
354           NS_LOG_DEBUG ("DROP_TTL_EXPIRE");
355           break;
356         case Ipv6L3Protocol::DROP_NO_ROUTE:
357           myReason = DROP_NO_ROUTE;
358           NS_LOG_DEBUG ("DROP_NO_ROUTE");
359           break;
360         case Ipv6L3Protocol::DROP_INTERFACE_DOWN:
361           myReason = DROP_INTERFACE_DOWN;
362           NS_LOG_DEBUG ("DROP_INTERFACE_DOWN");
363           break;
364         case Ipv6L3Protocol::DROP_ROUTE_ERROR:
365            myReason = DROP_ROUTE_ERROR;
366            NS_LOG_DEBUG ("DROP_ROUTE_ERROR");
367            break;
368         case Ipv6L3Protocol::DROP_UNKNOWN_PROTOCOL:
369            myReason = DROP_UNKNOWN_PROTOCOL;
370            NS_LOG_DEBUG ("DROP_UNKNOWN_PROTOCOL");
371            break;
372         case Ipv6L3Protocol::DROP_UNKNOWN_OPTION:
373            myReason = DROP_UNKNOWN_OPTION;
374            NS_LOG_DEBUG ("DROP_UNKNOWN_OPTION");
375            break;
376         case Ipv6L3Protocol::DROP_MALFORMED_HEADER:
377            myReason = DROP_MALFORMED_HEADER;
378            NS_LOG_DEBUG ("DROP_MALFORMED_HEADER");
379            break;
380         case Ipv6L3Protocol::DROP_FRAGMENT_TIMEOUT:
381           myReason = DROP_FRAGMENT_TIMEOUT;
382           NS_LOG_DEBUG ("DROP_FRAGMENT_TIMEOUT");
383           break;
384         default:
385           myReason = DROP_INVALID_REASON;
386           NS_FATAL_ERROR ("Unexpected drop reason code " << reason);
387         }
388 
389       m_flowMonitor->ReportDrop (this, flowId, packetId, size, myReason);
390     }
391 }
392 
393 void
QueueDropLogger(Ptr<const Packet> ipPayload)394 Ipv6FlowProbe::QueueDropLogger (Ptr<const Packet> ipPayload)
395 {
396   Ipv6FlowProbeTag fTag;
397   bool tagFound = ipPayload->FindFirstMatchingByteTag (fTag);
398 
399   if (!tagFound)
400     {
401       return;
402     }
403 
404   FlowId flowId = fTag.GetFlowId ();
405   FlowPacketId packetId = fTag.GetPacketId ();
406   uint32_t size = fTag.GetPacketSize ();
407 
408   NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << DROP_QUEUE
409                         << "); ");
410 
411   m_flowMonitor->ReportDrop (this, flowId, packetId, size, DROP_QUEUE);
412 }
413 
414 void
QueueDiscDropLogger(Ptr<const QueueDiscItem> item)415 Ipv6FlowProbe::QueueDiscDropLogger (Ptr<const QueueDiscItem> item)
416 {
417   Ipv6FlowProbeTag fTag;
418   bool tagFound = item->GetPacket ()->FindFirstMatchingByteTag (fTag);
419 
420   if (!tagFound)
421     {
422       return;
423     }
424 
425   FlowId flowId = fTag.GetFlowId ();
426   FlowPacketId packetId = fTag.GetPacketId ();
427   uint32_t size = fTag.GetPacketSize ();
428 
429   NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << DROP_QUEUE_DISC
430                         << "); ");
431 
432   m_flowMonitor->ReportDrop (this, flowId, packetId, size, DROP_QUEUE_DISC);
433 }
434 
435 } // namespace ns3
436 
437 
438