A Discrete-Event Network Simulator
API
click-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  * Author: Lalith Suresh <suresh.lalith@gmail.com>
21  */
22 
23 #ifdef NS3_CLICK
24 
25 #include "ns3/assert.h"
26 #include "ns3/log.h"
27 #include "ns3/object.h"
28 #include "ns3/names.h"
29 #include "ns3/ipv4.h"
30 #include "ns3/packet-socket-factory.h"
31 #include "ns3/config.h"
32 #include "ns3/simulator.h"
33 #include "ns3/string.h"
34 #include "ns3/net-device.h"
35 #include "ns3/callback.h"
36 #include "ns3/node.h"
37 #include "ns3/core-config.h"
38 #include "ns3/arp-l3-protocol.h"
39 #include "ns3/ipv4-click-routing.h"
40 #include "ns3/ipv4-l3-click-protocol.h"
41 #include "ns3/trace-helper.h"
43 #include <limits>
44 #include <map>
45 
46 namespace ns3 {
47 
48 NS_LOG_COMPONENT_DEFINE ("ClickInternetStackHelper");
49 
50 #define INTERFACE_CONTEXT
51 
52 typedef std::pair<Ptr<Ipv4>, uint32_t> InterfacePairIpv4;
53 typedef std::map<InterfacePairIpv4, Ptr<PcapFileWrapper> > InterfaceFileMapIpv4;
54 typedef std::map<InterfacePairIpv4, Ptr<OutputStreamWrapper> > InterfaceStreamMapIpv4;
55 
56 static InterfaceFileMapIpv4 g_interfaceFileMapIpv4;
57 static InterfaceStreamMapIpv4 g_interfaceStreamMapIpv4;
59 ClickInternetStackHelper::ClickInternetStackHelper ()
60  : m_ipv4Enabled (true)
61 {
62  Initialize ();
63 }
64 
65 // private method called by both constructor and Reset ()
66 void
67 ClickInternetStackHelper::Initialize ()
68 {
69  SetTcp ("ns3::TcpL4Protocol");
70 }
71 
72 ClickInternetStackHelper::~ClickInternetStackHelper ()
73 {
74 }
75 
76 ClickInternetStackHelper::ClickInternetStackHelper (const ClickInternetStackHelper &o)
77 {
78  m_ipv4Enabled = o.m_ipv4Enabled;
79  m_tcpFactory = o.m_tcpFactory;
80 }
81 
82 ClickInternetStackHelper &
83 ClickInternetStackHelper::operator = (const ClickInternetStackHelper &o)
84 {
85  if (this == &o)
86  {
87  return *this;
88  }
89  return *this;
90 }
91 
92 void
94 {
95  m_ipv4Enabled = true;
96  Initialize ();
97 }
98 
99 void
100 ClickInternetStackHelper::SetTcp (const std::string tid)
101 {
102  m_tcpFactory.SetTypeId (tid);
103 }
104 
105 void
106 ClickInternetStackHelper::SetTcp (std::string tid, std::string n0, const AttributeValue &v0)
107 {
108  m_tcpFactory.SetTypeId (tid);
109  m_tcpFactory.Set (n0,v0);
110 }
111 
112 void
113 ClickInternetStackHelper::SetClickFile (NodeContainer c, std::string clickfile)
114 {
115  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
116  {
117  SetClickFile (*i, clickfile);
118  }
119 }
120 
121 void
122 ClickInternetStackHelper::SetClickFile (Ptr<Node> node, std::string clickfile)
123 {
124  m_nodeToClickFileMap.insert (std::make_pair (node, clickfile));
125 }
126 
127 void
128 ClickInternetStackHelper::SetDefines (NodeContainer c, std::map<std::string, std::string> defines)
129 {
130  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
131  {
132  SetDefines (*i, defines);
133  }
134 }
135 
136 void
137 ClickInternetStackHelper::SetDefines (Ptr<Node> node, std::map<std::string, std::string> defines)
138 {
139  m_nodeToDefinesMap.insert (std::make_pair (node, defines));
140 }
141 
142 void
143 ClickInternetStackHelper::SetRoutingTableElement (NodeContainer c, std::string rt)
144 {
145  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
146  {
147  SetRoutingTableElement (*i, rt);
148  }
149 }
150 
151 void
152 ClickInternetStackHelper::SetRoutingTableElement (Ptr<Node> node, std::string rt)
153 {
154  m_nodeToRoutingTableElementMap.insert (std::make_pair (node, rt));
155 }
156 
157 void
158 ClickInternetStackHelper::Install (NodeContainer c) const
159 {
160  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
161  {
162  Install (*i);
163  }
164 }
165 
166 void
167 ClickInternetStackHelper::InstallAll (void) const
168 {
169  Install (NodeContainer::GetGlobal ());
170 }
171 
172 void
173 ClickInternetStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
174 {
175  ObjectFactory factory;
176  factory.SetTypeId (typeId);
177  Ptr<Object> protocol = factory.Create <Object> ();
178  node->AggregateObject (protocol);
179 }
180 
181 void
182 ClickInternetStackHelper::Install (Ptr<Node> node) const
183 {
184  if (m_ipv4Enabled)
185  {
186  if (node->GetObject<Ipv4> () != 0)
187  {
188  NS_FATAL_ERROR ("ClickInternetStackHelper::Install (): Aggregating "
189  "an InternetStack to a node with an existing Ipv4 object");
190  return;
191  }
192 
193  CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
194  CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3ClickProtocol");
195  CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
196  CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
197  node->AggregateObject (m_tcpFactory.Create<Object> ());
198  Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
199  node->AggregateObject (factory);
200  // Set routing
201  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
202  Ptr<Ipv4ClickRouting> ipv4Routing = CreateObject<Ipv4ClickRouting> ();
203  std::map< Ptr<Node>, std::string >::const_iterator it;
204  it = m_nodeToClickFileMap.find (node);
205 
206  if (it != m_nodeToClickFileMap.end ())
207  {
208  ipv4Routing->SetClickFile (it->second);
209  }
210 
211  std::map<Ptr<Node>, std::map<std::string, std::string> >::const_iterator definesIt;
212  definesIt = m_nodeToDefinesMap.find (node);
213  if (definesIt != m_nodeToDefinesMap.end ())
214  {
215  ipv4Routing->SetDefines (definesIt->second);
216  }
217 
218  it = m_nodeToRoutingTableElementMap.find (node);
219  if (it != m_nodeToRoutingTableElementMap.end ())
220  {
221  ipv4Routing->SetClickRoutingTableElement (it->second);
222  }
223  ipv4->SetRoutingProtocol (ipv4Routing);
224  node->AggregateObject (ipv4Routing);
225  }
226 }
227 
228 void
229 ClickInternetStackHelper::Install (std::string nodeName) const
230 {
231  Ptr<Node> node = Names::Find<Node> (nodeName);
232  Install (node);
233 }
234 
235 static void
236 Ipv4L3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ipv4> ipv4, uint32_t interface)
237 {
238  NS_LOG_FUNCTION (p << ipv4 << interface);
239 
240  //
241  // Since trace sources are independent of interface, if we hook a source
242  // on a particular protocol we will get traces for all of its interfaces.
243  // We need to filter this to only report interfaces for which the user
244  // has expressed interest.
245  //
246  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
247  if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ())
248  {
249  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
250  return;
251  }
252 
253  Ptr<PcapFileWrapper> file = g_interfaceFileMapIpv4[pair];
254  file->Write (Simulator::Now (), p);
255 }
256 
257 bool
258 ClickInternetStackHelper::PcapHooked (Ptr<Ipv4> ipv4)
259 {
260  for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin ();
261  i != g_interfaceFileMapIpv4.end ();
262  ++i)
263  {
264  if ((*i).first.first == ipv4)
265  {
266  return true;
267  }
268  }
269  return false;
270 }
271 
272 void
273 ClickInternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename)
274 {
275  NS_LOG_FUNCTION (prefix << ipv4 << interface);
276 
277  if (!m_ipv4Enabled)
278  {
279  NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled");
280  return;
281  }
282 
283  //
284  // We have to create a file and a mapping from protocol/interface to file
285  // irrespective of how many times we want to trace a particular protocol.
286  //
287  PcapHelper pcapHelper;
288 
289  std::string filename;
290  if (explicitFilename)
291  {
292  filename = prefix;
293  }
294  else
295  {
296  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
297  }
298 
299  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
300 
301  //
302  // However, we only hook the trace source once to avoid multiple trace sink
303  // calls per event (connect is independent of interface).
304  //
305  if (!PcapHooked (ipv4))
306  {
307  //
308  // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to
309  // node so we can get to Ipv4L3Protocol through Ipv4.
310  //
311  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
312  NS_ASSERT_MSG (ipv4L3Protocol, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
313  "m_ipv4Enabled and ipv4L3Protocol inconsistent");
314 
315  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
316  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
317  "Unable to connect ipv4L3Protocol \"Tx\"");
318 
319  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
320  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
321  "Unable to connect ipv4L3Protocol \"Rx\"");
322  }
323 
324  g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file;
325 }
326 
327 static void
329  Ptr<OutputStreamWrapper> stream,
330  Ipv4Header const &header,
331  Ptr<const Packet> packet,
332  Ipv4L3Protocol::DropReason reason,
333  Ptr<Ipv4> ipv4,
334  uint32_t interface)
335 {
336  //
337  // Since trace sources are independent of interface, if we hook a source
338  // on a particular protocol we will get traces for all of its interfaces.
339  // We need to filter this to only report interfaces for which the user
340  // has expressed interest.
341  //
342  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
343  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
344  {
345  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
346  return;
347  }
348 
349  Ptr<Packet> p = packet->Copy ();
350  p->AddHeader (header);
351  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
352 }
353 
354 static void
356  Ptr<OutputStreamWrapper> stream,
357  std::string context,
358  Ipv4Header const &header,
359  Ptr<const Packet> packet,
360  Ipv4L3Protocol::DropReason reason,
361  Ptr<Ipv4> ipv4,
362  uint32_t interface)
363 {
364  //
365  // Since trace sources are independent of interface, if we hook a source
366  // on a particular protocol we will get traces for all of its interfaces.
367  // We need to filter this to only report interfaces for which the user
368  // has expressed interest.
369  //
370  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
371  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
372  {
373  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
374  return;
375  }
376 
377  Ptr<Packet> p = packet->Copy ();
378  p->AddHeader (header);
379 #ifdef INTERFACE_CONTEXT
380  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
381  << *p << std::endl;
382 #else
383  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
384 #endif
385 }
386 
387 bool
388 ClickInternetStackHelper::AsciiHooked (Ptr<Ipv4> ipv4)
389 {
390  for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin ();
391  i != g_interfaceStreamMapIpv4.end ();
392  ++i)
393  {
394  if ((*i).first.first == ipv4)
395  {
396  return true;
397  }
398  }
399  return false;
400 }
401 
402 void
403 ClickInternetStackHelper::EnableAsciiIpv4Internal (
404  Ptr<OutputStreamWrapper> stream,
405  std::string prefix,
406  Ptr<Ipv4> ipv4,
407  uint32_t interface,
408  bool explicitFilename)
409 {
410  if (!m_ipv4Enabled)
411  {
412  NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled");
413  return;
414  }
415 
416  //
417  // Our trace sinks are going to use packet printing, so we have to
418  // make sure that is turned on.
419  //
420  Packet::EnablePrinting ();
421 
422  //
423  // If we are not provided an OutputStreamWrapper, we are expected to create
424  // one using the usual trace filename conventions and hook WithoutContext
425  // since there will be one file per context and therefore the context would
426  // be redundant.
427  //
428  if (stream == 0)
429  {
430  //
431  // Set up an output stream object to deal with private ofstream copy
432  // constructor and lifetime issues. Let the helper decide the actual
433  // name of the file given the prefix.
434  //
435  // We have to create a stream and a mapping from protocol/interface to
436  // stream irrespective of how many times we want to trace a particular
437  // protocol.
438  //
439  AsciiTraceHelper asciiTraceHelper;
440 
441  std::string filename;
442  if (explicitFilename)
443  {
444  filename = prefix;
445  }
446  else
447  {
448  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
449  }
450 
451  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
452 
453  //
454  // However, we only hook the trace sources once to avoid multiple trace sink
455  // calls per event (connect is independent of interface).
456  //
457  if (!AsciiHooked (ipv4))
458  {
459  //
460  // We can use the default drop sink for the ArpL3Protocol since it has
461  // the usual signature. We can get to the Ptr<ArpL3Protocol> through
462  // our Ptr<Ipv4> since they must both be aggregated to the same node.
463  //
464  Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol> ();
465  asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol> (arpL3Protocol, "Drop", theStream);
466 
467  //
468  // The drop sink for the Ipv4L3Protocol uses a different signature than
469  // the default sink, so we have to cook one up for ourselves. We can get
470  // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must both
471  // be aggregated to the same node.
472  //
473  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
474  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Drop",
476  theStream));
477  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EanableAsciiIpv4Internal(): "
478  "Unable to connect ipv4L3Protocol \"Drop\"");
479  }
480 
481  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = theStream;
482  return;
483  }
484 
485  //
486  // If we are provided an OutputStreamWrapper, we are expected to use it, and
487  // to provide a context. We are free to come up with our own context if we
488  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
489  // compatibility and simplicity, we just use Config::Connect and let it deal
490  // with the context.
491  //
492  // We need to associate the ipv4/interface with a stream to express interest
493  // in tracing events on that pair, however, we only hook the trace sources
494  // once to avoid multiple trace sink calls per event (connect is independent
495  // of interface).
496  //
497  if (!AsciiHooked (ipv4))
498  {
499  Ptr<Node> node = ipv4->GetObject<Node> ();
500  std::ostringstream oss;
501 
502  //
503  // For the ARP Drop, we are going to use the default trace sink provided by
504  // the ascii trace helper. There is actually no AsciiTraceHelper in sight
505  // here, but the default trace sinks are actually publicly available static
506  // functions that are always there waiting for just such a case.
507  //
508  oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop";
509  Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
510 
511  //
512  // This has all kinds of parameters coming with, so we have to cook up our
513  // own sink.
514  //
515  oss.str ("");
516  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop";
518  }
519 
520  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream;
521 }
522 
523 } // namespace ns3
524 
525 #endif // NS3_CLICK
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
static void Ipv4L3ProtocolDropSinkWithoutContext(Ptr< OutputStreamWrapper > stream, Ipv4Header const &header, Ptr< const Packet > packet, Ipv4L3Protocol::DropReason reason, Ptr< Ipv4 > ipv4, uint32_t interface)
Sync function for IPv4 dropped packet - Ascii output.
Callback< R > MakeBoundCallback(R(*fnPtr)(TX), ARG a1)
Make Callbacks with one bound argument.
Definition: callback.h:1686
static InterfaceFileMapIpv4 g_interfaceFileMapIpv4
A mapping of Ipv4/interface pairs to pcap files.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:244
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
static InterfaceStreamMapIpv4 g_interfaceStreamMapIpv4
A mapping of Ipv4/interface pairs to ascii streams.
std::map< InterfacePairIpv4, Ptr< OutputStreamWrapper > > InterfaceStreamMapIpv4
Ipv4/interface and output stream container.
double GetSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:341
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:835
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void Reset(void)
Reset the initial value of every attribute as well as the value of every global to what they were bef...
Definition: config.cc:749
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:90
std::pair< Ptr< Ipv4 >, uint32_t > InterfacePairIpv4
Ipv4/interface pair.
static void Ipv4L3ProtocolDropSinkWithContext(Ptr< OutputStreamWrapper > stream, std::string context, Ipv4Header const &header, Ptr< const Packet > packet, Ipv4L3Protocol::DropReason reason, Ptr< Ipv4 > ipv4, uint32_t interface)
Sync function for IPv4 dropped packet - Ascii output.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:340
std::map< InterfacePairIpv4, Ptr< PcapFileWrapper > > InterfaceFileMapIpv4
Ipv4/interface and Pcap file wrapper container.
static void Ipv4L3ProtocolRxTxSink(Ptr< const Packet > p, Ptr< Ipv4 > ipv4, uint32_t interface)
Sync function for IPv4 packet - Pcap output.