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  CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
403  Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
404  node->AggregateObject (factory);
405  // Set routing
406  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
407  Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create (node);
408  ipv4->SetRoutingProtocol (ipv4Routing);
409  }
410 
411  if (m_ipv6Enabled)
412  {
413  /* IPv6 stack */
414  if (node->GetObject<Ipv6> () != 0)
415  {
416  NS_FATAL_ERROR ("InternetStackHelper::Install (): Aggregating "
417  "an InternetStack to a node with an existing Ipv6 object");
418  return;
419  }
420 
421  CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv6L3Protocol");
422  CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv6L4Protocol");
423  /* TODO add UdpL4Protocol/TcpL4Protocol for IPv6 */
424  Ptr<Ipv6> ipv6 = node->GetObject<Ipv6> ();
425  Ptr<Ipv6RoutingProtocol> ipv6Routing = m_routingv6->Create (node);
426  ipv6->SetRoutingProtocol (ipv6Routing);
427 
428  /* register IPv6 extensions and options */
429  ipv6->RegisterExtensions ();
430  ipv6->RegisterOptions ();
431  }
432 }
433 
434 void
435 InternetStackHelper::Install (std::string nodeName) const
436 {
437  Ptr<Node> node = Names::Find<Node> (nodeName);
438  Install (node);
439 }
440 
441 static void
443 {
444  NS_LOG_FUNCTION (p << ipv4 << interface);
445 
446  //
447  // Since trace sources are independent of interface, if we hook a source
448  // on a particular protocol we will get traces for all of its interfaces.
449  // We need to filter this to only report interfaces for which the user
450  // has expressed interest.
451  //
452  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
453  if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ())
454  {
455  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
456  return;
457  }
458 
460  file->Write (Simulator::Now (), p);
461 }
462 
463 bool
465 {
466  for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin ();
467  i != g_interfaceFileMapIpv4.end ();
468  ++i)
469  {
470  if ((*i).first.first == ipv4)
471  {
472  return true;
473  }
474  }
475  return false;
476 }
477 
478 void
479 InternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename)
480 {
481  NS_LOG_FUNCTION (prefix << ipv4 << interface);
482 
483  if (!m_ipv4Enabled)
484  {
485  NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled");
486  return;
487  }
488 
489  //
490  // We have to create a file and a mapping from protocol/interface to file
491  // irrespective of how many times we want to trace a particular protocol.
492  //
493  PcapHelper pcapHelper;
494 
495  std::string filename;
496  if (explicitFilename)
497  {
498  filename = prefix;
499  }
500  else
501  {
502  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
503  }
504 
505  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
506 
507  //
508  // However, we only hook the trace source once to avoid multiple trace sink
509  // calls per event (connect is independent of interface).
510  //
511  if (!PcapHooked (ipv4))
512  {
513  //
514  // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to
515  // node so we can get to Ipv4L3Protocol through Ipv4.
516  //
517  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
518  NS_ASSERT_MSG (ipv4L3Protocol, "InternetStackHelper::EnablePcapIpv4Internal(): "
519  "m_ipv4Enabled and ipv4L3Protocol inconsistent");
520 
521  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
522  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv4Internal(): "
523  "Unable to connect ipv4L3Protocol \"Tx\"");
524 
525  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
526  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv4Internal(): "
527  "Unable to connect ipv4L3Protocol \"Rx\"");
528  }
529 
530  g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file;
531 }
532 
533 static void
535 {
536  NS_LOG_FUNCTION (p << ipv6 << interface);
537 
538  //
539  // Since trace sources are independent of interface, if we hook a source
540  // on a particular protocol we will get traces for all of its interfaces.
541  // We need to filter this to only report interfaces for which the user
542  // has expressed interest.
543  //
544  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
545  if (g_interfaceFileMapIpv6.find (pair) == g_interfaceFileMapIpv6.end ())
546  {
547  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
548  return;
549  }
550 
552  file->Write (Simulator::Now (), p);
553 }
554 
555 bool
557 {
558  for ( InterfaceFileMapIpv6::const_iterator i = g_interfaceFileMapIpv6.begin ();
559  i != g_interfaceFileMapIpv6.end ();
560  ++i)
561  {
562  if ((*i).first.first == ipv6)
563  {
564  return true;
565  }
566  }
567  return false;
568 }
569 
570 void
571 InternetStackHelper::EnablePcapIpv6Internal (std::string prefix, Ptr<Ipv6> ipv6, uint32_t interface, bool explicitFilename)
572 {
573  NS_LOG_FUNCTION (prefix << ipv6 << interface);
574 
575  if (!m_ipv6Enabled)
576  {
577  NS_LOG_INFO ("Call to enable Ipv6 pcap tracing but Ipv6 not enabled");
578  return;
579  }
580 
581  //
582  // We have to create a file and a mapping from protocol/interface to file
583  // irrespective of how many times we want to trace a particular protocol.
584  //
585  PcapHelper pcapHelper;
586 
587  std::string filename;
588  if (explicitFilename)
589  {
590  filename = prefix;
591  }
592  else
593  {
594  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
595  }
596 
597  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
598 
599  //
600  // However, we only hook the trace source once to avoid multiple trace sink
601  // calls per event (connect is independent of interface).
602  //
603  if (!PcapHooked (ipv6))
604  {
605  //
606  // Ptr<Ipv6> is aggregated to node and Ipv6L3Protocol is aggregated to
607  // node so we can get to Ipv6L3Protocol through Ipv6.
608  //
609  Ptr<Ipv6L3Protocol> ipv6L3Protocol = ipv6->GetObject<Ipv6L3Protocol> ();
610  NS_ASSERT_MSG (ipv6L3Protocol, "InternetStackHelper::EnablePcapIpv6Internal(): "
611  "m_ipv6Enabled and ipv6L3Protocol inconsistent");
612 
613  bool result = ipv6L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv6L3ProtocolRxTxSink));
614  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv6Internal(): "
615  "Unable to connect ipv6L3Protocol \"Tx\"");
616 
617  result = ipv6L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv6L3ProtocolRxTxSink));
618  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnablePcapIpv6Internal(): "
619  "Unable to connect ipv6L3Protocol \"Rx\"");
620  }
621 
622  g_interfaceFileMapIpv6[std::make_pair (ipv6, interface)] = file;
623 }
624 
625 static void
628  Ipv4Header const &header,
629  Ptr<const Packet> packet,
631  Ptr<Ipv4> ipv4,
632  uint32_t interface)
633 {
634  //
635  // Since trace sources are independent of interface, if we hook a source
636  // on a particular protocol we will get traces for all of its interfaces.
637  // We need to filter this to only report interfaces for which the user
638  // has expressed interest.
639  //
640  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
641  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
642  {
643  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
644  return;
645  }
646 
647  Ptr<Packet> p = packet->Copy ();
648  p->AddHeader (header);
649  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
650 }
651 
652 static void
655  Ptr<const Packet> packet,
656  Ptr<Ipv4> ipv4,
657  uint32_t interface)
658 {
659  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
660  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
661  {
662  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
663  return;
664  }
665 
666  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
667 }
668 
669 static void
672  Ptr<const Packet> packet,
673  Ptr<Ipv4> ipv4,
674  uint32_t interface)
675 {
676  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
677  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
678  {
679  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
680  return;
681  }
682 
683  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
684 }
685 
686 static void
689  std::string context,
690  Ipv4Header const &header,
691  Ptr<const Packet> packet,
693  Ptr<Ipv4> ipv4,
694  uint32_t interface)
695 {
696  //
697  // Since trace sources are independent of interface, if we hook a source
698  // on a particular protocol we will get traces for all of its interfaces.
699  // We need to filter this to only report interfaces for which the user
700  // has expressed interest.
701  //
702  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
703  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
704  {
705  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
706  return;
707  }
708 
709  Ptr<Packet> p = packet->Copy ();
710  p->AddHeader (header);
711 #ifdef INTERFACE_CONTEXT
712  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
713  << *p << std::endl;
714 #else
715  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
716 #endif
717 }
718 
719 static void
722  std::string context,
723  Ptr<const Packet> packet,
724  Ptr<Ipv4> ipv4,
725  uint32_t interface)
726 {
727  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
728  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
729  {
730  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
731  return;
732  }
733 
734 #ifdef INTERFACE_CONTEXT
735  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
736  << *packet << std::endl;
737 #else
738  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
739 #endif
740 }
741 
742 static void
745  std::string context,
746  Ptr<const Packet> packet,
747  Ptr<Ipv4> ipv4,
748  uint32_t interface)
749 {
750  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
751  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
752  {
753  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
754  return;
755  }
756 
757 #ifdef INTERFACE_CONTEXT
758  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
759  << *packet << std::endl;
760 #else
761  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
762 #endif
763 }
764 
765 bool
767 {
768  for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin ();
769  i != g_interfaceStreamMapIpv4.end ();
770  ++i)
771  {
772  if ((*i).first.first == ipv4)
773  {
774  return true;
775  }
776  }
777  return false;
778 }
779 
780 void
782  Ptr<OutputStreamWrapper> stream,
783  std::string prefix,
784  Ptr<Ipv4> ipv4,
785  uint32_t interface,
786  bool explicitFilename)
787 {
788  if (!m_ipv4Enabled)
789  {
790  NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled");
791  return;
792  }
793 
794  //
795  // Our trace sinks are going to use packet printing, so we have to
796  // make sure that is turned on.
797  //
799 
800  //
801  // If we are not provided an OutputStreamWrapper, we are expected to create
802  // one using the usual trace filename conventions and hook WithoutContext
803  // since there will be one file per context and therefore the context would
804  // be redundant.
805  //
806  if (stream == 0)
807  {
808  //
809  // Set up an output stream object to deal with private ofstream copy
810  // constructor and lifetime issues. Let the helper decide the actual
811  // name of the file given the prefix.
812  //
813  // We have to create a stream and a mapping from protocol/interface to
814  // stream irrespective of how many times we want to trace a particular
815  // protocol.
816  //
817  AsciiTraceHelper asciiTraceHelper;
818 
819  std::string filename;
820  if (explicitFilename)
821  {
822  filename = prefix;
823  }
824  else
825  {
826  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
827  }
828 
829  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
830 
831  //
832  // However, we only hook the trace sources once to avoid multiple trace sink
833  // calls per event (connect is independent of interface).
834  //
835  if (!AsciiHooked (ipv4))
836  {
837  //
838  // We can use the default drop sink for the ArpL3Protocol since it has
839  // the usual signature. We can get to the Ptr<ArpL3Protocol> through
840  // our Ptr<Ipv4> since they must both be aggregated to the same node.
841  //
842  Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol> ();
843  asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol> (arpL3Protocol, "Drop", theStream);
844 
845  //
846  // The drop sink for the Ipv4L3Protocol uses a different signature than
847  // the default sink, so we have to cook one up for ourselves. We can get
848  // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must both
849  // be aggregated to the same node.
850  //
851  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
852  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Drop",
854  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
855  "Unable to connect ipv4L3Protocol \"Drop\"");
856  result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx",
858  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
859  "Unable to connect ipv4L3Protocol \"Tx\"");
860  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx",
862  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv4Internal(): "
863  "Unable to connect ipv4L3Protocol \"Rx\"");
864  }
865 
866  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = theStream;
867  return;
868  }
869 
870  //
871  // If we are provided an OutputStreamWrapper, we are expected to use it, and
872  // to provide a context. We are free to come up with our own context if we
873  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
874  // compatibility and simplicity, we just use Config::Connect and let it deal
875  // with the context.
876  //
877  // We need to associate the ipv4/interface with a stream to express interest
878  // in tracing events on that pair, however, we only hook the trace sources
879  // once to avoid multiple trace sink calls per event (connect is independent
880  // of interface).
881  //
882  if (!AsciiHooked (ipv4))
883  {
884  Ptr<Node> node = ipv4->GetObject<Node> ();
885  std::ostringstream oss;
886 
887  //
888  // For the ARP Drop, we are going to use the default trace sink provided by
889  // the ascii trace helper. There is actually no AsciiTraceHelper in sight
890  // here, but the default trace sinks are actually publicly available static
891  // functions that are always there waiting for just such a case.
892  //
893  oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop";
895 
896  //
897  // This has all kinds of parameters coming with, so we have to cook up our
898  // own sink.
899  //
900  oss.str ("");
901  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop";
903  oss.str ("");
904  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Tx";
906  oss.str ("");
907  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Rx";
909  }
910 
911  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream;
912 }
913 
914 static void
917  Ipv6Header const &header,
918  Ptr<const Packet> packet,
920  Ptr<Ipv6> ipv6,
921  uint32_t interface)
922 {
923  //
924  // Since trace sources are independent of interface, if we hook a source
925  // on a particular protocol we will get traces for all of its interfaces.
926  // We need to filter this to only report interfaces for which the user
927  // has expressed interest.
928  //
929  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
930  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
931  {
932  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
933  return;
934  }
935 
936  Ptr<Packet> p = packet->Copy ();
937  p->AddHeader (header);
938  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
939 }
940 
941 static void
944  Ptr<const Packet> packet,
945  Ptr<Ipv6> ipv6,
946  uint32_t interface)
947 {
948  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
949  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
950  {
951  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
952  return;
953  }
954 
955  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
956 }
957 
958 static void
961  Ptr<const Packet> packet,
962  Ptr<Ipv6> ipv6,
963  uint32_t interface)
964 {
965  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
966  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
967  {
968  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
969  return;
970  }
971 
972  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
973 }
974 
975 static void
978  std::string context,
979  Ipv6Header const &header,
980  Ptr<const Packet> packet,
982  Ptr<Ipv6> ipv6,
983  uint32_t interface)
984 {
985  //
986  // Since trace sources are independent of interface, if we hook a source
987  // on a particular protocol we will get traces for all of its interfaces.
988  // We need to filter this to only report interfaces for which the user
989  // has expressed interest.
990  //
991  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
992  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
993  {
994  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
995  return;
996  }
997 
998  Ptr<Packet> p = packet->Copy ();
999  p->AddHeader (header);
1000 #ifdef INTERFACE_CONTEXT
1001  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1002  << *p << std::endl;
1003 #else
1004  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
1005 #endif
1006 }
1007 
1008 static void
1010  Ptr<OutputStreamWrapper> stream,
1011  std::string context,
1012  Ptr<const Packet> packet,
1013  Ptr<Ipv6> ipv6,
1014  uint32_t interface)
1015 {
1016  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
1017  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
1018  {
1019  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
1020  return;
1021  }
1022 
1023 #ifdef INTERFACE_CONTEXT
1024  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1025  << *packet << std::endl;
1026 #else
1027  *stream->GetStream () << "t " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
1028 #endif
1029 }
1030 
1031 static void
1033  Ptr<OutputStreamWrapper> stream,
1034  std::string context,
1035  Ptr<const Packet> packet,
1036  Ptr<Ipv6> ipv6,
1037  uint32_t interface)
1038 {
1039  InterfacePairIpv6 pair = std::make_pair (ipv6, interface);
1040  if (g_interfaceStreamMapIpv6.find (pair) == g_interfaceStreamMapIpv6.end ())
1041  {
1042  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
1043  return;
1044  }
1045 
1046 #ifdef INTERFACE_CONTEXT
1047  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
1048  << *packet << std::endl;
1049 #else
1050  *stream->GetStream () << "r " << Simulator::Now ().GetSeconds () << " " << context << " " << *packet << std::endl;
1051 #endif
1052 }
1053 
1054 bool
1056 {
1057  for ( InterfaceStreamMapIpv6::const_iterator i = g_interfaceStreamMapIpv6.begin ();
1058  i != g_interfaceStreamMapIpv6.end ();
1059  ++i)
1060  {
1061  if ((*i).first.first == ipv6)
1062  {
1063  return true;
1064  }
1065  }
1066  return false;
1067 }
1068 
1069 void
1071  Ptr<OutputStreamWrapper> stream,
1072  std::string prefix,
1073  Ptr<Ipv6> ipv6,
1074  uint32_t interface,
1075  bool explicitFilename)
1076 {
1077  if (!m_ipv6Enabled)
1078  {
1079  NS_LOG_INFO ("Call to enable Ipv6 ascii tracing but Ipv6 not enabled");
1080  return;
1081  }
1082 
1083  //
1084  // Our trace sinks are going to use packet printing, so we have to
1085  // make sure that is turned on.
1086  //
1088 
1089  //
1090  // If we are not provided an OutputStreamWrapper, we are expected to create
1091  // one using the usual trace filename conventions and do a hook WithoutContext
1092  // since there will be one file per context and therefore the context would
1093  // be redundant.
1094  //
1095  if (stream == 0)
1096  {
1097  //
1098  // Set up an output stream object to deal with private ofstream copy
1099  // constructor and lifetime issues. Let the helper decide the actual
1100  // name of the file given the prefix.
1101  //
1102  // We have to create a stream and a mapping from protocol/interface to
1103  // stream irrespective of how many times we want to trace a particular
1104  // protocol.
1105  //
1106  AsciiTraceHelper asciiTraceHelper;
1107 
1108  std::string filename;
1109  if (explicitFilename)
1110  {
1111  filename = prefix;
1112  }
1113  else
1114  {
1115  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv6, interface);
1116  }
1117 
1118  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
1119 
1120  //
1121  // However, we only hook the trace sources once to avoid multiple trace sink
1122  // calls per event (connect is independent of interface).
1123  //
1124  if (!AsciiHooked (ipv6))
1125  {
1126  //
1127  // The drop sink for the Ipv6L3Protocol uses a different signature than
1128  // the default sink, so we have to cook one up for ourselves. We can get
1129  // to the Ptr<Ipv6L3Protocol> through our Ptr<Ipv6> since they must both
1130  // be aggregated to the same node.
1131  //
1132  Ptr<Ipv6L3Protocol> ipv6L3Protocol = ipv6->GetObject<Ipv6L3Protocol> ();
1133  bool result = ipv6L3Protocol->TraceConnectWithoutContext ("Drop",
1135  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1136  "Unable to connect ipv6L3Protocol \"Drop\"");
1137  result = ipv6L3Protocol->TraceConnectWithoutContext ("Tx",
1139  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1140  "Unable to connect ipv6L3Protocol \"Tx\"");
1141  result = ipv6L3Protocol->TraceConnectWithoutContext ("Rx",
1143  NS_ASSERT_MSG (result == true, "InternetStackHelper::EnableAsciiIpv6Internal(): "
1144  "Unable to connect ipv6L3Protocol \"Rx\"");
1145  }
1146 
1147  g_interfaceStreamMapIpv6[std::make_pair (ipv6, interface)] = theStream;
1148  return;
1149  }
1150 
1151  //
1152  // If we are provided an OutputStreamWrapper, we are expected to use it, and
1153  // to provide a context. We are free to come up with our own context if we
1154  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
1155  // compatibility and simplicity, we just use Config::Connect and let it deal
1156  // with the context.
1157  //
1158  // We need to associate the ipv4/interface with a stream to express interest
1159  // in tracing events on that pair, however, we only hook the trace sources
1160  // once to avoid multiple trace sink calls per event (connect is independent
1161  // of interface).
1162  //
1163  if (!AsciiHooked (ipv6))
1164  {
1165  Ptr<Node> node = ipv6->GetObject<Node> ();
1166  std::ostringstream oss;
1167 
1168  oss.str ("");
1169  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Drop";
1171  oss.str ("");
1172  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Tx";
1174  oss.str ("");
1175  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv6L3Protocol/Rx";
1177  }
1178 
1179  g_interfaceStreamMapIpv6[std::make_pair (ipv6, interface)] = stream;
1180 }
1181 
1182 } // namespace ns3