A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
internet-stack-helper.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2008 INRIA
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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  * Author: Faker Moatamri <faker.moatamri@sophia.inria.fr>
20  */
21 
151 #include "ns3/assert.h"
152 #include "ns3/log.h"
153 #include "ns3/object.h"
154 #include "ns3/names.h"
155 #include "ns3/ipv4.h"
156 #include "ns3/ipv6.h"
157 #include "ns3/packet-socket-factory.h"
158 #include "ns3/config.h"
159 #include "ns3/simulator.h"
160 #include "ns3/string.h"
161 #include "ns3/net-device.h"
162 #include "ns3/callback.h"
163 #include "ns3/node.h"
164 #include "ns3/node-list.h"
165 #include "ns3/core-config.h"
166 #include "ns3/arp-l3-protocol.h"
167 #include "internet-stack-helper.h"
168 #include "ns3/ipv4-global-routing.h"
169 #include "ns3/ipv4-list-routing-helper.h"
170 #include "ns3/ipv4-static-routing-helper.h"
171 #include "ns3/ipv4-global-routing-helper.h"
172 #include "ns3/ipv6-list-routing-helper.h"
173 #include "ns3/ipv6-static-routing-helper.h"
174 #include "ns3/ipv6-extension.h"
175 #include "ns3/ipv6-extension-demux.h"
176 #include "ns3/ipv6-extension-header.h"
177 #include "ns3/global-router-interface.h"
178 #include <limits>
179 #include <map>
180 
181 NS_LOG_COMPONENT_DEFINE ("InternetStackHelper");
182 
183 namespace ns3 {
184 
185 //
186 // Historically, the only context written to ascii traces was the protocol.
187 // Traces from the protocols include the interface, though. It is not
188 // possible to really determine where an event originated without including
189 // this. If you want the additional context information, define
190 // INTERFACE_CONTEXT. If you want compatibility with the old-style traces
191 // comment it out.
192 //
193 #define INTERFACE_CONTEXT
194 
195 //
196 // Things are going to work differently here with respect to trace file handling
197 // than in most places because the Tx and Rx trace sources we are interested in
198 // are going to multiplex receive and transmit callbacks for all Ipv4 and
199 // interface pairs through one callback. We want packets to or from each
200 // distinct pair to go to an individual file, so we have got to demultiplex the
201 // Ipv4 and interface pair into a corresponding Ptr<PcapFileWrapper> at the
202 // callback.
203 //
204 // A complication in this situation is that the trace sources are hooked on
205 // a protocol basis. There is no trace source hooked by an Ipv4 and interface
206 // pair. This means that if we naively proceed to hook, say, a drop trace
207 // for a given Ipv4 with interface 0, and then hook for Ipv4 with interface 1
208 // we will hook the drop trace twice and get two callbacks per event. What
209 // we need to do is to hook the event once, and that will result in a single
210 // callback per drop event, and the trace source will provide the interface
211 // which we filter on in the trace sink.
212 //
213 // This has got to continue to work properly after the helper has been
214 // destroyed; but must be cleaned up at the end of time to avoid leaks.
215 // Global maps of protocol/interface pairs to file objects seems to fit the
216 // bill.
217 //
218 typedef std::pair<Ptr<Ipv4>, uint32_t> InterfacePairIpv4;
219 typedef std::map<InterfacePairIpv4, Ptr<PcapFileWrapper> > InterfaceFileMapIpv4;
220 typedef std::map<InterfacePairIpv4, Ptr<OutputStreamWrapper> > InterfaceStreamMapIpv4;
221 
225 typedef std::pair<Ptr<Ipv6>, uint32_t> InterfacePairIpv6;
226 typedef std::map<InterfacePairIpv6, Ptr<PcapFileWrapper> > InterfaceFileMapIpv6;
227 typedef std::map<InterfacePairIpv6, Ptr<OutputStreamWrapper> > InterfaceStreamMapIpv6;
228 
233  : m_routing (0),
234  m_routingv6 (0),
235  m_ipv4Enabled (true),
236  m_ipv6Enabled (true)
237 {
238  Initialize ();
239 }
240 
241 // private method called by both constructor and Reset ()
242 void
244 {
245  SetTcp ("ns3::TcpL4Protocol");
246  Ipv4StaticRoutingHelper staticRouting;
247  Ipv4GlobalRoutingHelper globalRouting;
248  Ipv4ListRoutingHelper listRouting;
249  Ipv6ListRoutingHelper listRoutingv6;
250  Ipv6StaticRoutingHelper staticRoutingv6;
251  listRouting.Add (staticRouting, 0);
252  listRouting.Add (globalRouting, -10);
253  listRoutingv6.Add (staticRoutingv6, 0);
254  SetRoutingHelper (listRouting);
255  SetRoutingHelper (listRoutingv6);
256 }
257 
259 {
260  delete m_routing;
261  delete m_routingv6;
262 }
263 
265 {
266  m_routing = o.m_routing->Copy ();
267  m_routingv6 = o.m_routingv6->Copy ();
271 }
272 
275 {
276  if (this == &o)
277  {
278  return *this;
279  }
280  m_routing = o.m_routing->Copy ();
281  m_routingv6 = o.m_routingv6->Copy ();
282  return *this;
283 }
284 
285 void
287 {
288  delete m_routing;
289  m_routing = 0;
290  delete m_routingv6;
291  m_routingv6 = 0;
292  m_ipv4Enabled = true;
293  m_ipv6Enabled = true;
294  Initialize ();
295 }
296 
297 void
299 {
300  delete m_routing;
301  m_routing = routing.Copy ();
302 }
303 
304 void
306 {
307  delete m_routingv6;
308  m_routingv6 = routing.Copy ();
309 }
310 
311 void
313 {
314  m_ipv4Enabled = enable;
315 }
316 
318 {
319  m_ipv6Enabled = enable;
320 }
321 
322 int64_t
324 {
325  int64_t currentStream = stream;
326  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
327  {
328  Ptr<Node> node = *i;
329  Ptr<GlobalRouter> router = node->GetObject<GlobalRouter> ();
330  if (router != 0)
331  {
332  Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol ();
333  if (gr != 0)
334  {
335  currentStream += gr->AssignStreams (currentStream);
336  }
337  }
339  if (demux != 0)
340  {
341  Ptr<Ipv6Extension> fe = demux->GetExtension (Ipv6ExtensionFragment::EXT_NUMBER);
342  NS_ASSERT (fe); // should always exist in the demux
343  currentStream += fe->AssignStreams (currentStream);
344  }
345  }
346  return (currentStream - stream);
347 }
348 
349 void
350 InternetStackHelper::SetTcp (const std::string tid)
351 {
352  m_tcpFactory.SetTypeId (tid);
353 }
354 
355 void
356 InternetStackHelper::SetTcp (std::string tid, std::string n0, const AttributeValue &v0)
357 {
358  m_tcpFactory.SetTypeId (tid);
359  m_tcpFactory.Set (n0,v0);
360 }
361 
362 void
364 {
365  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
366  {
367  Install (*i);
368  }
369 }
370 
371 void
373 {
375 }
376 
377 void
379 {
380  ObjectFactory factory;
381  factory.SetTypeId (typeId);
382  Ptr<Object> protocol = factory.Create <Object> ();
383  node->AggregateObject (protocol);
384 }
385 
386 void
388 {
389  if (m_ipv4Enabled)
390  {
391  if (node->GetObject<Ipv4> () != 0)
392  {
393  NS_FATAL_ERROR ("InternetStackHelper::Install (): Aggregating "
394  "an InternetStack to a node with an existing Ipv4 object");
395  return;
396  }
397 
398  CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
399  CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3Protocol");
400  CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
401  // Set routing
402  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
403  Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
404  ipv4->SetRoutingProtocol (ipv4Routing);
405  }
406 
407  if (m_ipv6Enabled)
408  {
409  /* IPv6 stack */
410  if (node->GetObject<Ipv6> () != 0)
411  {
412  NS_FATAL_ERROR ("InternetStackHelper::Install (): Aggregating "
413  "an InternetStack to a node with an existing Ipv6 object");
414  return;
415  }
416 
417  CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv6L3Protocol");
418  CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv6L4Protocol");
419  // Set routing
420  Ptr<Ipv6> ipv6 = node->GetObject<Ipv6> ();
421  Ptr<Ipv6RoutingProtocol> ipv6Routing = m_routingv6->Create (node);
422  ipv6->SetRoutingProtocol (ipv6Routing);
423 
424  /* register IPv6 extensions and options */
425  ipv6->RegisterExtensions ();
426  ipv6->RegisterOptions ();
427  }
428 
430  {
431  CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
433  Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
434  node->AggregateObject (factory);
435  }
436 }
437 
438 void
439 InternetStackHelper::Install (std::string nodeName) const
440 {
441  Ptr<Node> node = Names::Find<Node> (nodeName);
442  Install (node);
443 }
444 
445 static void
447 {
448  NS_LOG_FUNCTION (p << ipv4 << interface);
449 
450  //
451  // Since trace sources are independent of interface, if we hook a source
452  // on a particular protocol we will get traces for all of its interfaces.
453  // We need to filter this to only report interfaces for which the user
454  // has expressed interest.
455  //
456  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
457  if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ())
458  {
459  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
460  return;
461  }
462 
464  file->Write (Simulator::Now (), p);
465 }
466 
467 bool
469 {
470  for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin ();
471  i != g_interfaceFileMapIpv4.end ();
472  ++i)
473  {
474  if ((*i).first.first == ipv4)
475  {
476  return true;
477  }
478  }
479  return false;
480 }
481 
482 void
483 InternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename)
484 {
485  NS_LOG_FUNCTION (prefix << ipv4 << interface);
486 
487  if (!m_ipv4Enabled)
488  {
489  NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled");
490  return;
491  }
492 
493  //
494  // We have to create a file and a mapping from protocol/interface to file
495  // irrespective of how many times we want to trace a particular protocol.
496  //
497  PcapHelper pcapHelper;
498 
499  std::string filename;
500  if (explicitFilename)
501  {
502  filename = prefix;
503  }
504  else
505  {
506  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
507  }
508 
509  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
510 
511  //
512  // However, we only hook the trace source once to avoid multiple trace sink
513  // calls per event (connect is independent of interface).
514  //
515  if (!PcapHooked (ipv4))
516  {
517  //
518  // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to
519  // node so we can get to Ipv4L3Protocol through Ipv4.
520  //
521  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
522  NS_ASSERT_MSG (ipv4L3Protocol, "InternetStackHelper::EnablePcapIpv4Internal(): "
523  "m_ipv4Enabled and ipv4L3Protocol inconsistent");
524 
525  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
526  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv4Internal(): "
527  "Unable to connect ipv4L3Protocol \"Tx\"");
528 
529  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
530  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv4Internal(): "
531  "Unable to connect ipv4L3Protocol \"Rx\"");
532  }
533 
534  g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file;
535 }
536 
537 static void
539 {
540  NS_LOG_FUNCTION (p << ipv6 << interface);
541 
542  //
543  // Since trace sources are independent of interface, if we hook a source
544  // on a particular protocol we will get traces for all of its interfaces.
545  // We need to filter this to only report interfaces for which the user
546  // has expressed interest.
547  //
548  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
549  if (g_interfaceFileMapIpv6.find (pair) == g_interfaceFileMapIpv6.end ())
550  {
551  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
552  return;
553  }
554 
556  file->Write (Simulator::Now (), p);
557 }
558 
559 bool
561 {
562  for ( InterfaceFileMapIpv6::const_iterator i = g_interfaceFileMapIpv6.begin ();
563  i != g_interfaceFileMapIpv6.end ();
564  ++i)
565  {
566  if ((*i).first.first == ipv6)
567  {
568  return true;
569  }
570  }
571  return false;
572 }
573 
574 void
575 InternetStackHelper::EnablePcapIpv6Internal (std::string prefix, Ptr<Ipv6> ipv6, uint32_t interface, bool explicitFilename)
576 {
577  NS_LOG_FUNCTION (prefix << ipv6 << interface);
578 
579  if (!m_ipv6Enabled)
580  {
581  NS_LOG_INFO ("Call to enable Ipv6 pcap tracing but Ipv6 not enabled");
582  return;
583  }
584 
585  //
586  // We have to create a file and a mapping from protocol/interface to file
587  // irrespective of how many times we want to trace a particular protocol.
588  //
589  PcapHelper pcapHelper;
590 
591  std::string filename;
592  if (explicitFilename)
593  {
594  filename = prefix;
595  }
596  else
597  {
598  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
599  }
600 
601  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
602 
603  //
604  // However, we only hook the trace source once to avoid multiple trace sink
605  // calls per event (connect is independent of interface).
606  //
607  if (!PcapHooked (ipv6))
608  {
609  //
610  // Ptr<Ipv6> is aggregated to node and Ipv6L3Protocol is aggregated to
611  // node so we can get to Ipv6L3Protocol through Ipv6.
612  //
613  Ptr<Ipv6L3Protocol> ipv6L3Protocol = ipv6->GetObject<Ipv6L3Protocol> ();
614  NS_ASSERT_MSG (ipv6L3Protocol, "InternetStackHelper::EnablePcapIpv6Internal(): "
615  "m_ipv6Enabled and ipv6L3Protocol inconsistent");
616 
617  bool result = ipv6L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv6L3ProtocolRxTxSink));
618  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv6Internal(): "
619  "Unable to connect ipv6L3Protocol \"Tx\"");
620 
621  result = ipv6L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv6L3ProtocolRxTxSink));
622  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv6Internal(): "
623  "Unable to connect ipv6L3Protocol \"Rx\"");
624  }
625 
626  g_interfaceFileMapIpv6[std::make_pair (ipv6, interface)] = file;
627 }
628 
629 static void
632  Ipv4Header const &header,
633  Ptr<const Packet> packet,
635  Ptr<Ipv4> ipv4,
636  uint32_t interface)
637 {
638  //
639  // Since trace sources are independent of interface, if we hook a source
640  // on a particular protocol we will get traces for all of its interfaces.
641  // We need to filter this to only report interfaces for which the user
642  // has expressed interest.
643  //
644  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
645  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
646  {
647  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
648  return;
649  }
650 
651  Ptr<Packet> p = packet->Copy ();
652  p->AddHeader (header);
653  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
654 }
655 
656 static void
659  Ptr<const Packet> packet,
660  Ptr<Ipv4> ipv4,
661  uint32_t interface)
662 {
663  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
664  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
665  {
666  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
667  return;
668  }
669 
670  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
671 }
672 
673 static void
676  Ptr<const Packet> packet,
677  Ptr<Ipv4> ipv4,
678  uint32_t interface)
679 {
680  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
681  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
682  {
683  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
684  return;
685  }
686 
687  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
688 }
689 
690 static void
693  std::string context,
694  Ipv4Header const &header,
695  Ptr<const Packet> packet,
697  Ptr<Ipv4> ipv4,
698  uint32_t interface)
699 {
700  //
701  // Since trace sources are independent of interface, if we hook a source
702  // on a particular protocol we will get traces for all of its interfaces.
703  // We need to filter this to only report interfaces for which the user
704  // has expressed interest.
705  //
706  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
707  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
708  {
709  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
710  return;
711  }
712 
713  Ptr<Packet> p = packet->Copy ();
714  p->AddHeader (header);
715 #ifdef INTERFACE_CONTEXT
716  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
717  << *p << std::endl;
718 #else
719  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
720 #endif
721 }
722 
723 static void
726  std::string context,
727  Ptr<const Packet> packet,
728  Ptr<Ipv4> ipv4,
729  uint32_t interface)
730 {
731  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
732  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
733  {
734  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
735  return;
736  }
737 
738 #ifdef INTERFACE_CONTEXT
739  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
740  << *packet << std::endl;
741 #else
742  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
743 #endif
744 }
745 
746 static void
749  std::string context,
750  Ptr<const Packet> packet,
751  Ptr<Ipv4> ipv4,
752  uint32_t interface)
753 {
754  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
755  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
756  {
757  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
758  return;
759  }
760 
761 #ifdef INTERFACE_CONTEXT
762  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
763  << *packet << std::endl;
764 #else
765  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
766 #endif
767 }
768 
769 bool
771 {
772  for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin ();
773  i != g_interfaceStreamMapIpv4.end ();
774  ++i)
775  {
776  if ((*i).first.first == ipv4)
777  {
778  return true;
779  }
780  }
781  return false;
782 }
783 
784 void
786  Ptr<OutputStreamWrapper> stream,
787  std::string prefix,
788  Ptr<Ipv4> ipv4,
789  uint32_t interface,
790  bool explicitFilename)
791 {
792  if (!m_ipv4Enabled)
793  {
794  NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled");
795  return;
796  }
797 
798  //
799  // Our trace sinks are going to use packet printing, so we have to
800  // make sure that is turned on.
801  //
803 
804  //
805  // If we are not provided an OutputStreamWrapper, we are expected to create
806  // one using the usual trace filename conventions and hook WithoutContext
807  // since there will be one file per context and therefore the context would
808  // be redundant.
809  //
810  if (stream == 0)
811  {
812  //
813  // Set up an output stream object to deal with private ofstream copy
814  // constructor and lifetime issues. Let the helper decide the actual
815  // name of the file given the prefix.
816  //
817  // We have to create a stream and a mapping from protocol/interface to
818  // stream irrespective of how many times we want to trace a particular
819  // protocol.
820  //
821  AsciiTraceHelper asciiTraceHelper;
822 
823  std::string filename;
824  if (explicitFilename)
825  {
826  filename = prefix;
827  }
828  else
829  {
830  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
831  }
832 
833  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
834 
835  //
836  // However, we only hook the trace sources once to avoid multiple trace sink
837  // calls per event (connect is independent of interface).
838  //
839  if (!AsciiHooked (ipv4))
840  {
841  //
842  // We can use the default drop sink for the ArpL3Protocol since it has
843  // the usual signature. We can get to the Ptr<ArpL3Protocol> through
844  // our Ptr<Ipv4> since they must both be aggregated to the same node.
845  //
846  Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol> ();
847  asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol> (arpL3Protocol, "Drop", theStream);
848 
849  //
850  // The drop sink for the Ipv4L3Protocol uses a different signature than
851  // the default sink, so we have to cook one up for ourselves. We can get
852  // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must both
853  // be aggregated to the same node.
854  //
855  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
856  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Drop",
858  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
859  "Unable to connect ipv4L3Protocol \"Drop\"");
860  result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx",
862  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
863  "Unable to connect ipv4L3Protocol \"Tx\"");
864  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx",
866  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
867  "Unable to connect ipv4L3Protocol \"Rx\"");
868  }
869 
870  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = theStream;
871  return;
872  }
873 
874  //
875  // If we are provided an OutputStreamWrapper, we are expected to use it, and
876  // to provide a context. We are free to come up with our own context if we
877  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
878  // compatibility and simplicity, we just use Config::Connect and let it deal
879  // with the context.
880  //
881  // We need to associate the ipv4/interface with a stream to express interest
882  // in tracing events on that pair, however, we only hook the trace sources
883  // once to avoid multiple trace sink calls per event (connect is independent
884  // of interface).
885  //
886  if (!AsciiHooked (ipv4))
887  {
888  Ptr<Node> node = ipv4->GetObject<Node> ();
889  std::ostringstream oss;
890 
891  //
892  // For the ARP Drop, we are going to use the default trace sink provided by
893  // the ascii trace helper. There is actually no AsciiTraceHelper in sight
894  // here, but the default trace sinks are actually publicly available static
895  // functions that are always there waiting for just such a case.
896  //
897  oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop";
899 
900  //
901  // This has all kinds of parameters coming with, so we have to cook up our
902  // own sink.
903  //
904  oss.str ("");
905  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop";
907  oss.str ("");
908  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Tx";
910  oss.str ("");
911  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Rx";
913  }
914 
915  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream;
916 }
917 
918 static void
921  Ipv6Header const &header,
922  Ptr<const Packet> packet,
924  Ptr<Ipv6> ipv6,
925  uint32_t interface)
926 {
927  //
928  // Since trace sources are independent of interface, if we hook a source
929  // on a particular protocol we will get traces for all of its interfaces.
930  // We need to filter this to only report interfaces for which the user
931  // has expressed interest.
932  //
933  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
934  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
935  {
936  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
937  return;
938  }
939 
940  Ptr<Packet> p = packet->Copy ();
941  p->AddHeader (header);
942  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
943 }
944 
945 static void
948  Ptr<const Packet> packet,
949  Ptr<Ipv6> ipv6,
950  uint32_t interface)
951 {
952  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
953  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
954  {
955  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
956  return;
957  }
958 
959  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
960 }
961 
962 static void
965  Ptr<const Packet> packet,
966  Ptr<Ipv6> ipv6,
967  uint32_t interface)
968 {
969  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
970  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
971  {
972  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
973  return;
974  }
975 
976  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
977 }
978 
979 static void
982  std::string context,
983  Ipv6Header const &header,
984  Ptr<const Packet> packet,
986  Ptr<Ipv6> ipv6,
987  uint32_t interface)
988 {
989  //
990  // Since trace sources are independent of interface, if we hook a source
991  // on a particular protocol we will get traces for all of its interfaces.
992  // We need to filter this to only report interfaces for which the user
993  // has expressed interest.
994  //
995  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
996  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
997  {
998  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
999  return;
1000  }
1001 
1002  Ptr<Packet> p = packet->Copy ();
1003  p->AddHeader (header);
1004 #ifdef INTERFACE_CONTEXT
1005  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1006  << *p << std::endl;
1007 #else
1008  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
1009 #endif
1010 }
1011 
1012 static void
1014  Ptr<OutputStreamWrapper> stream,
1015  std::string context,
1016  Ptr<const Packet> packet,
1017  Ptr<Ipv6> ipv6,
1018  uint32_t interface)
1019 {
1020  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
1021  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
1022  {
1023  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
1024  return;
1025  }
1026 
1027 #ifdef INTERFACE_CONTEXT
1028  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1029  << *packet << std::endl;
1030 #else
1031  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
1032 #endif
1033 }
1034 
1035 static void
1037  Ptr<OutputStreamWrapper> stream,
1038  std::string context,
1039  Ptr<const Packet> packet,
1040  Ptr<Ipv6> ipv6,
1041  uint32_t interface)
1042 {
1043  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
1044  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
1045  {
1046  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
1047  return;
1048  }
1049 
1050 #ifdef INTERFACE_CONTEXT
1051  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1052  << *packet << std::endl;
1053 #else
1054  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
1055 #endif
1056 }
1057 
1058 bool
1060 {
1061  for ( InterfaceStreamMapIpv6::const_iterator i = g_interfaceStreamMapIpv6.begin ();
1062  i != g_interfaceStreamMapIpv6.end ();
1063  ++i)
1064  {
1065  if ((*i).first.first == ipv6)
1066  {
1067  return true;
1068  }
1069  }
1070  return false;
1071 }
1072 
1073 void
1075  Ptr<OutputStreamWrapper> stream,
1076  std::string prefix,
1077  Ptr<Ipv6> ipv6,
1078  uint32_t interface,
1079  bool explicitFilename)
1080 {
1081  if (!m_ipv6Enabled)
1082  {
1083  NS_LOG_INFO ("Call to enable Ipv6 ascii tracing but Ipv6 not enabled");
1084  return;
1085  }
1086 
1087  //
1088  // Our trace sinks are going to use packet printing, so we have to
1089  // make sure that is turned on.
1090  //
1092 
1093  //
1094  // If we are not provided an OutputStreamWrapper, we are expected to create
1095  // one using the usual trace filename conventions and do a hook WithoutContext
1096  // since there will be one file per context and therefore the context would
1097  // be redundant.
1098  //
1099  if (stream == 0)
1100  {
1101  //
1102  // Set up an output stream object to deal with private ofstream copy
1103  // constructor and lifetime issues. Let the helper decide the actual
1104  // name of the file given the prefix.
1105  //
1106  // We have to create a stream and a mapping from protocol/interface to
1107  // stream irrespective of how many times we want to trace a particular
1108  // protocol.
1109  //
1110  AsciiTraceHelper asciiTraceHelper;
1111 
1112  std::string filename;
1113  if (explicitFilename)
1114  {
1115  filename = prefix;
1116  }
1117  else
1118  {
1119  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
1120  }
1121 
1122  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
1123 
1124  //
1125  // However, we only hook the trace sources once to avoid multiple trace sink
1126  // calls per event (connect is independent of interface).
1127  //
1128  if (!AsciiHooked (ipv6))
1129  {
1130  //
1131  // The drop sink for the Ipv6L3Protocol uses a different signature than
1132  // the default sink, so we have to cook one up for ourselves. We can get
1133  // to the Ptr<Ipv6L3Protocol> through our Ptr<Ipv6> since they must both
1134  // be aggregated to the same node.
1135  //
1136  Ptr<Ipv6L3Protocol> ipv6L3Protocol = ipv6->GetObject<Ipv6L3Protocol> ();
1137  bool result = ipv6L3Protocol->TraceConnectWithoutContext ("Drop",
1139  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1140  "Unable to connect ipv6L3Protocol \"Drop\"");
1141  result = ipv6L3Protocol->TraceConnectWithoutContext ("Tx",
1143  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1144  "Unable to connect ipv6L3Protocol \"Tx\"");
1145  result = ipv6L3Protocol->TraceConnectWithoutContext ("Rx",
1147  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1148  "Unable to connect ipv6L3Protocol \"Rx\"");
1149  }
1150 
1151  g_interfaceStreamMapIpv6[std::make_pair (ipv6, interface)] = theStream;
1152  return;
1153  }
1154 
1155  //
1156  // If we are provided an OutputStreamWrapper, we are expected to use it, and
1157  // to provide a context. We are free to come up with our own context if we
1158  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
1159  // compatibility and simplicity, we just use Config::Connect and let it deal
1160  // with the context.
1161  //
1162  // We need to associate the ipv4/interface with a stream to express interest
1163  // in tracing events on that pair, however, we only hook the trace sources
1164  // once to avoid multiple trace sink calls per event (connect is independent
1165  // of interface).
1166  //
1167  if (!AsciiHooked (ipv6))
1168  {
1169  Ptr<Node> node = ipv6->GetObject<Node> ();
1170  std::ostringstream oss;
1171 
1172  oss.str ("");
1173  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Drop";
1175  oss.str ("");
1176  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Tx";
1178  oss.str ("");
1179  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Rx";
1181  }
1182 
1183  g_interfaceStreamMapIpv6[std::make_pair (ipv6, interface)] = stream;
1184 }
1185 
1186 } // namespace ns3