A Discrete-Event Network Simulator
API
trace-helper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 University of Washington
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17 
18 #include "trace-helper.h"
19 
20 #include "ns3/abort.h"
21 #include "ns3/assert.h"
22 #include "ns3/log.h"
23 #include "ns3/names.h"
24 #include "ns3/net-device.h"
25 #include "ns3/node.h"
26 #include "ns3/pcap-file-wrapper.h"
27 #include "ns3/ptr.h"
28 
29 #include <fstream>
30 #include <stdint.h>
31 #include <string>
32 
33 namespace ns3
34 {
35 
36 NS_LOG_COMPONENT_DEFINE("TraceHelper");
37 
39 {
41 }
42 
44 {
46 }
47 
49 PcapHelper::CreateFile(std::string filename,
50  std::ios::openmode filemode,
51  DataLinkType dataLinkType,
52  uint32_t snapLen,
53  int32_t tzCorrection)
54 {
55  NS_LOG_FUNCTION(filename << filemode << dataLinkType << snapLen << tzCorrection);
56 
57  Ptr<PcapFileWrapper> file = CreateObject<PcapFileWrapper>();
58  file->Open(filename, filemode);
59  NS_ABORT_MSG_IF(file->Fail(), "Unable to Open " << filename << " for mode " << filemode);
60 
61  file->Init(dataLinkType, snapLen, tzCorrection);
62  NS_ABORT_MSG_IF(file->Fail(), "Unable to Init " << filename);
63 
64  //
65  // Note that the pcap helper promptly forgets all about the pcap file. We
66  // rely on the reference count of the file object which will soon be owned
67  // by the caller to keep the object alive. If the caller uses the file
68  // object to hook a trace source, ownership of the file object will be
69  // implicitly transferred to the callback which keeps the object alive.
70  // When the callback is destroyed (when either the trace is disconnected or
71  // the object with the trace source is deleted) the callback will be destroyed
72  // and the file object will be destroyed, releasing the pointer and closing
73  // the file.
74  //
75  return file;
76 }
77 
78 std::string
79 PcapHelper::GetFilenameFromDevice(std::string prefix, Ptr<NetDevice> device, bool useObjectNames)
80 {
81  NS_LOG_FUNCTION(prefix << device << useObjectNames);
82  NS_ABORT_MSG_UNLESS(!prefix.empty(), "Empty prefix string");
83 
84  std::ostringstream oss;
85  oss << prefix << "-";
86 
87  std::string nodename;
88  std::string devicename;
89 
90  Ptr<Node> node = device->GetNode();
91 
92  if (useObjectNames)
93  {
94  nodename = Names::FindName(node);
95  devicename = Names::FindName(device);
96  }
97 
98  if (!nodename.empty())
99  {
100  oss << nodename;
101  }
102  else
103  {
104  oss << node->GetId();
105  }
106 
107  oss << "-";
108 
109  if (!devicename.empty())
110  {
111  oss << devicename;
112  }
113  else
114  {
115  oss << device->GetIfIndex();
116  }
117 
118  oss << ".pcap";
119 
120  return oss.str();
121 }
122 
123 std::string
125  Ptr<Object> object,
126  uint32_t interface,
127  bool useObjectNames)
128 {
129  NS_LOG_FUNCTION(prefix << object << interface << useObjectNames);
130  NS_ABORT_MSG_UNLESS(!prefix.empty(), "Empty prefix string");
131 
132  std::ostringstream oss;
133  oss << prefix << "-";
134 
135  std::string objname;
136  std::string nodename;
137 
138  Ptr<Node> node = object->GetObject<Node>();
139 
140  if (useObjectNames)
141  {
142  objname = Names::FindName(object);
143  nodename = Names::FindName(node);
144  }
145 
146  if (!objname.empty())
147  {
148  oss << objname;
149  }
150  else if (!nodename.empty())
151  {
152  oss << nodename;
153  }
154  else
155  {
156  oss << "n" << node->GetId();
157  }
158 
159  oss << "-i" << interface << ".pcap";
160 
161  return oss.str();
162 }
163 
164 //
165 // The basic default trace sink. This one just writes the packet to the pcap
166 // file which is good enough for most kinds of captures.
167 //
168 void
170 {
171  NS_LOG_FUNCTION(file << p);
172  file->Write(Simulator::Now(), p);
173 }
174 
175 void
177 {
178  NS_LOG_FUNCTION(file << p);
179  file->Write(Simulator::Now(), header, p);
180 }
181 
183 {
185 }
186 
188 {
190 }
191 
193 AsciiTraceHelper::CreateFileStream(std::string filename, std::ios::openmode filemode)
194 {
195  NS_LOG_FUNCTION(filename << filemode);
196 
197  Ptr<OutputStreamWrapper> StreamWrapper = Create<OutputStreamWrapper>(filename, filemode);
198 
199  //
200  // Note that the ascii trace helper promptly forgets all about the trace file.
201  // We rely on the reference count of the file object which will soon be owned
202  // by the caller to keep the object alive. If the caller uses the stream
203  // object to hook a trace source, ownership of the stream object will be
204  // implicitly transferred to the callback which keeps the object alive.
205  // When the callback is destroyed (when either the trace is disconnected or
206  // the object with the trace source is deleted) the callback will be destroyed
207  // and the stream object will be destroyed, releasing the pointer and closing
208  // the underlying file.
209  //
210  return StreamWrapper;
211 }
212 
213 std::string
215  Ptr<NetDevice> device,
216  bool useObjectNames)
217 {
218  NS_LOG_FUNCTION(prefix << device << useObjectNames);
219  NS_ABORT_MSG_UNLESS(!prefix.empty(), "Empty prefix string");
220 
221  std::ostringstream oss;
222  oss << prefix << "-";
223 
224  std::string nodename;
225  std::string devicename;
226 
227  Ptr<Node> node = device->GetNode();
228 
229  if (useObjectNames)
230  {
231  nodename = Names::FindName(node);
232  devicename = Names::FindName(device);
233  }
234 
235  if (!nodename.empty())
236  {
237  oss << nodename;
238  }
239  else
240  {
241  oss << node->GetId();
242  }
243 
244  oss << "-";
245 
246  if (!devicename.empty())
247  {
248  oss << devicename;
249  }
250  else
251  {
252  oss << device->GetIfIndex();
253  }
254 
255  oss << ".tr";
256 
257  return oss.str();
258 }
259 
260 std::string
262  Ptr<Object> object,
263  uint32_t interface,
264  bool useObjectNames)
265 {
266  NS_LOG_FUNCTION(prefix << object << interface << useObjectNames);
267  NS_ABORT_MSG_UNLESS(!prefix.empty(), "Empty prefix string");
268 
269  std::ostringstream oss;
270  oss << prefix << "-";
271 
272  std::string objname;
273  std::string nodename;
274 
275  Ptr<Node> node = object->GetObject<Node>();
276 
277  if (useObjectNames)
278  {
279  objname = Names::FindName(object);
280  nodename = Names::FindName(node);
281  }
282 
283  if (!objname.empty())
284  {
285  oss << objname;
286  }
287  else if (!nodename.empty())
288  {
289  oss << nodename;
290  }
291  else
292  {
293  oss << "n" << node->GetId();
294  }
295 
296  oss << "-i" << interface << ".tr";
297 
298  return oss.str();
299 }
300 
301 //
302 // One of the basic default trace sink sets. Enqueue:
303 //
304 // When a packet has been sent to a device for transmission, the device is
305 // expected to place the packet onto a transmit queue even if it does not
306 // have to delay the packet at all, if only to trigger this event. This
307 // event will eventually translate into a '+' operation in the trace file.
308 //
309 // This is typically implemented by hooking the "TxQueue/Enqueue" trace hook
310 // in the device (actually the Queue in the device).
311 //
312 void
315 {
316  NS_LOG_FUNCTION(stream << p);
317  *stream->GetStream() << "+ " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
318 }
319 
320 void
322  std::string context,
324 {
325  NS_LOG_FUNCTION(stream << p);
326  *stream->GetStream() << "+ " << Simulator::Now().GetSeconds() << " " << context << " " << *p
327  << std::endl;
328 }
329 
330 //
331 // One of the basic default trace sink sets. Drop:
332 //
333 // When a packet has been sent to a device for transmission, the device is
334 // expected to place the packet onto a transmit queue. If this queue is
335 // full the packet will be dropped. The device is expected to trigger an
336 // event to indicate that an outbound packet is being dropped. This event
337 // will eventually translate into a 'd' operation in the trace file.
338 //
339 // This is typically implemented by hooking the "TxQueue/Drop" trace hook
340 // in the device (actually the Queue in the device).
341 //
342 void
345 {
346  NS_LOG_FUNCTION(stream << p);
347  *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
348 }
349 
350 void
352  std::string context,
354 {
355  NS_LOG_FUNCTION(stream << p);
356  *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << " " << *p
357  << std::endl;
358 }
359 
360 //
361 // One of the basic default trace sink sets. Dequeue:
362 //
363 // When a packet has been sent to a device for transmission, the device is
364 // expected to place the packet onto a transmit queue even if it does not
365 // have to delay the packet at all. The device removes the packet from the
366 // transmit queue when the packet is ready to send, and this dequeue will
367 // fire a corresponding event. This event will eventually translate into a
368 // '-' operation in the trace file.
369 //
370 // This is typically implemented by hooking the "TxQueue/Dequeue" trace hook
371 // in the device (actually the Queue in the device).
372 //
373 void
376 {
377  NS_LOG_FUNCTION(stream << p);
378  *stream->GetStream() << "- " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
379 }
380 
381 void
383  std::string context,
385 {
386  NS_LOG_FUNCTION(stream << p);
387  *stream->GetStream() << "- " << Simulator::Now().GetSeconds() << " " << context << " " << *p
388  << std::endl;
389 }
390 
391 //
392 // One of the basic default trace sink sets. Receive:
393 //
394 // When a packet is received by a device for transmission, the device is
395 // expected to trigger this event to indicate the reception has occurred.
396 // This event will eventually translate into an 'r' operation in the trace
397 // file.
398 //
399 // This is typically implemented by hooking the "MacRx" trace hook in the
400 // device.
401 void
404 {
405  NS_LOG_FUNCTION(stream << p);
406  *stream->GetStream() << "r " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
407 }
408 
409 void
411  std::string context,
413 {
414  NS_LOG_FUNCTION(stream << p);
415  *stream->GetStream() << "r " << Simulator::Now().GetSeconds() << " " << context << " " << *p
416  << std::endl;
417 }
418 
419 void
421  Ptr<NetDevice> nd,
422  bool promiscuous,
423  bool explicitFilename)
424 {
425  EnablePcapInternal(prefix, nd, promiscuous, explicitFilename);
426 }
427 
428 void
430  std::string ndName,
431  bool promiscuous,
432  bool explicitFilename)
433 {
434  Ptr<NetDevice> nd = Names::Find<NetDevice>(ndName);
435  EnablePcap(prefix, nd, promiscuous, explicitFilename);
436 }
437 
438 void
439 PcapHelperForDevice::EnablePcap(std::string prefix, NetDeviceContainer d, bool promiscuous)
440 {
441  for (auto i = d.Begin(); i != d.End(); ++i)
442  {
443  Ptr<NetDevice> dev = *i;
444  EnablePcap(prefix, dev, promiscuous);
445  }
446 }
447 
448 void
449 PcapHelperForDevice::EnablePcap(std::string prefix, NodeContainer n, bool promiscuous)
450 {
451  NetDeviceContainer devs;
452  for (auto i = n.Begin(); i != n.End(); ++i)
453  {
454  Ptr<Node> node = *i;
455  for (uint32_t j = 0; j < node->GetNDevices(); ++j)
456  {
457  devs.Add(node->GetDevice(j));
458  }
459  }
460  EnablePcap(prefix, devs, promiscuous);
461 }
462 
463 void
464 PcapHelperForDevice::EnablePcapAll(std::string prefix, bool promiscuous)
465 {
466  EnablePcap(prefix, NodeContainer::GetGlobal(), promiscuous);
467 }
468 
469 void
471  uint32_t nodeid,
472  uint32_t deviceid,
473  bool promiscuous)
474 {
476 
477  for (auto i = n.Begin(); i != n.End(); ++i)
478  {
479  Ptr<Node> node = *i;
480  if (node->GetId() != nodeid)
481  {
482  continue;
483  }
484 
485  NS_ABORT_MSG_IF(deviceid >= node->GetNDevices(),
486  "PcapHelperForDevice::EnablePcap(): Unknown deviceid = " << deviceid);
487  Ptr<NetDevice> nd = node->GetDevice(deviceid);
488  EnablePcap(prefix, nd, promiscuous);
489  return;
490  }
491 }
492 
493 //
494 // Public API
495 //
496 void
497 AsciiTraceHelperForDevice::EnableAscii(std::string prefix, Ptr<NetDevice> nd, bool explicitFilename)
498 {
499  EnableAsciiInternal(Ptr<OutputStreamWrapper>(), prefix, nd, explicitFilename);
500 }
501 
502 //
503 // Public API
504 //
505 void
507 {
508  EnableAsciiInternal(stream, std::string(), nd, false);
509 }
510 
511 //
512 // Public API
513 //
514 void
516  std::string ndName,
517  bool explicitFilename)
518 {
519  EnableAsciiImpl(Ptr<OutputStreamWrapper>(), prefix, ndName, explicitFilename);
520 }
521 
522 //
523 // Public API
524 //
525 void
527 {
528  EnableAsciiImpl(stream, std::string(), ndName, false);
529 }
530 
531 //
532 // Private API
533 //
534 void
536  std::string prefix,
537  std::string ndName,
538  bool explicitFilename)
539 {
540  Ptr<NetDevice> nd = Names::Find<NetDevice>(ndName);
541  EnableAsciiInternal(stream, prefix, nd, explicitFilename);
542 }
543 
544 //
545 // Public API
546 //
547 void
549 {
551 }
552 
553 //
554 // Public API
555 //
556 void
558 {
559  EnableAsciiImpl(stream, std::string(), d);
560 }
561 
562 //
563 // Private API
564 //
565 void
567  std::string prefix,
569 {
570  for (auto i = d.Begin(); i != d.End(); ++i)
571  {
572  Ptr<NetDevice> dev = *i;
573  EnableAsciiInternal(stream, prefix, dev, false);
574  }
575 }
576 
577 //
578 // Public API
579 //
580 void
582 {
584 }
585 
586 //
587 // Public API
588 //
589 void
591 {
592  EnableAsciiImpl(stream, std::string(), n);
593 }
594 
595 //
596 // Private API
597 //
598 void
600  std::string prefix,
601  NodeContainer n)
602 {
603  NetDeviceContainer devs;
604  for (auto i = n.Begin(); i != n.End(); ++i)
605  {
606  Ptr<Node> node = *i;
607  for (uint32_t j = 0; j < node->GetNDevices(); ++j)
608  {
609  devs.Add(node->GetDevice(j));
610  }
611  }
612  EnableAsciiImpl(stream, prefix, devs);
613 }
614 
615 //
616 // Public API
617 //
618 void
620 {
622 }
623 
624 //
625 // Public API
626 //
627 void
629 {
630  EnableAsciiImpl(stream, std::string(), NodeContainer::GetGlobal());
631 }
632 
633 //
634 // Public API
635 //
636 void
638  uint32_t nodeid,
639  uint32_t deviceid)
640 {
641  EnableAsciiImpl(stream, std::string(), nodeid, deviceid, false);
642 }
643 
644 //
645 // Public API
646 //
647 void
649  uint32_t nodeid,
650  uint32_t deviceid,
651  bool explicitFilename)
652 {
653  EnableAsciiImpl(Ptr<OutputStreamWrapper>(), prefix, nodeid, deviceid, explicitFilename);
654 }
655 
656 //
657 // Private API
658 //
659 void
661  std::string prefix,
662  uint32_t nodeid,
663  uint32_t deviceid,
664  bool explicitFilename)
665 {
667 
668  for (auto i = n.Begin(); i != n.End(); ++i)
669  {
670  Ptr<Node> node = *i;
671  if (node->GetId() != nodeid)
672  {
673  continue;
674  }
675 
677  deviceid >= node->GetNDevices(),
678  "AsciiTraceHelperForDevice::EnableAscii(): Unknown deviceid = " << deviceid);
679 
680  Ptr<NetDevice> nd = node->GetDevice(deviceid);
681 
682  EnableAsciiInternal(stream, prefix, nd, explicitFilename);
683  return;
684  }
685 }
686 
687 } // namespace ns3
void EnableAsciiImpl(Ptr< OutputStreamWrapper > stream, std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename)
Enable ascii trace output on the device specified by a global node-id (of a previously created node) ...
void EnableAscii(std::string prefix, Ptr< NetDevice > nd, bool explicitFilename=false)
Enable ascii trace output on the indicated net device.
void EnableAsciiAll(std::string prefix)
Enable ascii trace output on each device (which is of the appropriate type) in the set of all nodes c...
virtual void EnableAsciiInternal(Ptr< OutputStreamWrapper > stream, std::string prefix, Ptr< NetDevice > nd, bool explicitFilename)=0
Enable ascii trace output on the indicated net device.
std::string GetFilenameFromDevice(std::string prefix, Ptr< NetDevice > device, bool useObjectNames=true)
Let the ascii trace helper figure out a reasonable filename to use for an ascii trace file associated...
static void DefaultDropSinkWithContext(Ptr< OutputStreamWrapper > file, std::string context, Ptr< const Packet > p)
Basic Drop default trace sink.
std::string GetFilenameFromInterfacePair(std::string prefix, Ptr< Object > object, uint32_t interface, bool useObjectNames=true)
Let the ascii trace helper figure out a reasonable filename to use for an ascii trace file associated...
static void DefaultReceiveSinkWithContext(Ptr< OutputStreamWrapper > file, std::string context, Ptr< const Packet > p)
Basic Receive default trace sink.
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we'll use to write the traced bits.
AsciiTraceHelper()
Create an ascii trace helper.
static void DefaultDequeueSinkWithoutContext(Ptr< OutputStreamWrapper > file, Ptr< const Packet > p)
Basic Dequeue default trace sink.
static void DefaultEnqueueSinkWithContext(Ptr< OutputStreamWrapper > file, std::string context, Ptr< const Packet > p)
Basic Enqueue default trace sink.
static void DefaultDropSinkWithoutContext(Ptr< OutputStreamWrapper > file, Ptr< const Packet > p)
Basic Drop default trace sink.
static void DefaultDequeueSinkWithContext(Ptr< OutputStreamWrapper > file, std::string context, Ptr< const Packet > p)
Basic Dequeue default trace sink.
static void DefaultEnqueueSinkWithoutContext(Ptr< OutputStreamWrapper > file, Ptr< const Packet > p)
Basic Enqueue default trace sink.
~AsciiTraceHelper()
Destroy an ascii trace helper.
static void DefaultReceiveSinkWithoutContext(Ptr< OutputStreamWrapper > file, Ptr< const Packet > p)
Basic Receive default trace sink.
Protocol header serialization and deserialization.
Definition: header.h:44
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and,...
Definition: names.cc:829
holds a vector of ns3::NetDevice pointers
Iterator Begin() const
Get an iterator which refers to the first NetDevice in the container.
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
Iterator End() const
Get an iterator which indicates past-the-last NetDevice in the container.
keep track of a set of node pointers.
Iterator End() const
Get an iterator which indicates past-the-last Node in the container.
static NodeContainer GetGlobal()
Create a NodeContainer that contains a list of all nodes created through NodeContainer::Create() and ...
Iterator Begin() const
Get an iterator which refers to the first Node in the container.
A network Node.
Definition: node.h:57
uint32_t GetNDevices() const
Definition: node.cc:162
uint32_t GetId() const
Definition: node.cc:117
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:152
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
std::ostream * GetStream()
Return a pointer to an ostream previously set in the wrapper.
void EnablePcapAll(std::string prefix, bool promiscuous=false)
Enable pcap output on each device (which is of the appropriate type) in the set of all nodes created ...
void EnablePcap(std::string prefix, Ptr< NetDevice > nd, bool promiscuous=false, bool explicitFilename=false)
Enable pcap output the indicated net device.
virtual void EnablePcapInternal(std::string prefix, Ptr< NetDevice > nd, bool promiscuous, bool explicitFilename)=0
Enable pcap output the indicated net device.
std::string GetFilenameFromDevice(std::string prefix, Ptr< NetDevice > device, bool useObjectNames=true)
Let the pcap helper figure out a reasonable filename to use for a pcap file associated with a device.
Definition: trace-helper.cc:79
Ptr< PcapFileWrapper > CreateFile(std::string filename, std::ios::openmode filemode, DataLinkType dataLinkType, uint32_t snapLen=std::numeric_limits< uint32_t >::max(), int32_t tzCorrection=0)
Create and initialize a pcap file.
Definition: trace-helper.cc:49
DataLinkType
This enumeration holds the data link types that will be written to the pcap file.
Definition: trace-helper.h:52
static void SinkWithHeader(Ptr< PcapFileWrapper > file, const Header &header, Ptr< const Packet > p)
This trace sink passes a header separately from the packet to prevent creating a new packet (for perf...
std::string GetFilenameFromInterfacePair(std::string prefix, Ptr< Object > object, uint32_t interface, bool useObjectNames=true)
Let the pcap helper figure out a reasonable filename to use for the pcap file associated with a node.
~PcapHelper()
Destroy a pcap helper.
Definition: trace-helper.cc:43
static void DefaultSink(Ptr< PcapFileWrapper > file, Ptr< const Packet > p)
The basic default trace sink.
PcapHelper()
Create a pcap helper.
Definition: trace-helper.cc:38
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Every class exported by the ns3 library is enclosed in the ns3 namespace.