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