A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 NS_LOG_COMPONENT_DEFINE ("ClickInternetStackHelper");
47 
48 namespace ns3 {
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 
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::SetRoutingTableElement (NodeContainer c, std::string rt)
129 {
130  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
131  {
132  SetRoutingTableElement (*i, rt);
133  }
134 }
135 
136 void
137 ClickInternetStackHelper::SetRoutingTableElement (Ptr<Node> node, std::string rt)
138 {
139  m_nodeToRoutingTableElementMap.insert (std::make_pair (node, rt));
140 }
141 
142 void
143 ClickInternetStackHelper::Install (NodeContainer c) const
144 {
145  for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
146  {
147  Install (*i);
148  }
149 }
150 
151 void
152 ClickInternetStackHelper::InstallAll (void) const
153 {
154  Install (NodeContainer::GetGlobal ());
155 }
156 
157 void
158 ClickInternetStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
159 {
160  ObjectFactory factory;
161  factory.SetTypeId (typeId);
162  Ptr<Object> protocol = factory.Create <Object> ();
163  node->AggregateObject (protocol);
164 }
165 
166 void
167 ClickInternetStackHelper::Install (Ptr<Node> node) const
168 {
169  if (m_ipv4Enabled)
170  {
171  if (node->GetObject<Ipv4> () != 0)
172  {
173  NS_FATAL_ERROR ("ClickInternetStackHelper::Install (): Aggregating "
174  "an InternetStack to a node with an existing Ipv4 object");
175  return;
176  }
177 
178  CreateAndAggregateObjectFromTypeId (node, "ns3::ArpL3Protocol");
179  CreateAndAggregateObjectFromTypeId (node, "ns3::Ipv4L3ClickProtocol");
180  CreateAndAggregateObjectFromTypeId (node, "ns3::Icmpv4L4Protocol");
181  CreateAndAggregateObjectFromTypeId (node, "ns3::UdpL4Protocol");
182  node->AggregateObject (m_tcpFactory.Create<Object> ());
183  Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory> ();
184  node->AggregateObject (factory);
185  // Set routing
186  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
187  Ptr<Ipv4ClickRouting> ipv4Routing = CreateObject<Ipv4ClickRouting> ();
188  std::map< Ptr<Node>, std::string >::const_iterator it;
189  it = m_nodeToClickFileMap.find (node);
190 
191  if (it != m_nodeToClickFileMap.end ())
192  {
193  ipv4Routing->SetClickFile (it->second);
194  }
195 
196  it = m_nodeToRoutingTableElementMap.find (node);
197  if (it != m_nodeToRoutingTableElementMap.end ())
198  {
199  ipv4Routing->SetClickRoutingTableElement (it->second);
200  }
201  ipv4->SetRoutingProtocol (ipv4Routing);
202  node->AggregateObject (ipv4Routing);
203  }
204 }
205 
206 void
207 ClickInternetStackHelper::Install (std::string nodeName) const
208 {
209  Ptr<Node> node = Names::Find<Node> (nodeName);
210  Install (node);
211 }
212 
213 static void
214 Ipv4L3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ipv4> ipv4, uint32_t interface)
215 {
216  NS_LOG_FUNCTION (p << ipv4 << interface);
217 
218  //
219  // Since trace sources are independent of interface, if we hook a source
220  // on a particular protocol we will get traces for all of its interfaces.
221  // We need to filter this to only report interfaces for which the user
222  // has expressed interest.
223  //
224  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
225  if (g_interfaceFileMapIpv4.find (pair) == g_interfaceFileMapIpv4.end ())
226  {
227  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
228  return;
229  }
230 
231  Ptr<PcapFileWrapper> file = g_interfaceFileMapIpv4[pair];
232  file->Write (Simulator::Now (), p);
233 }
234 
235 bool
236 ClickInternetStackHelper::PcapHooked (Ptr<Ipv4> ipv4)
237 {
238  for ( InterfaceFileMapIpv4::const_iterator i = g_interfaceFileMapIpv4.begin ();
239  i != g_interfaceFileMapIpv4.end ();
240  ++i)
241  {
242  if ((*i).first.first == ipv4)
243  {
244  return true;
245  }
246  }
247  return false;
248 }
249 
250 void
251 ClickInternetStackHelper::EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename)
252 {
253  NS_LOG_FUNCTION (prefix << ipv4 << interface);
254 
255  if (!m_ipv4Enabled)
256  {
257  NS_LOG_INFO ("Call to enable Ipv4 pcap tracing but Ipv4 not enabled");
258  return;
259  }
260 
261  //
262  // We have to create a file and a mapping from protocol/interface to file
263  // irrespective of how many times we want to trace a particular protocol.
264  //
265  PcapHelper pcapHelper;
266 
267  std::string filename;
268  if (explicitFilename)
269  {
270  filename = prefix;
271  }
272  else
273  {
274  filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
275  }
276 
277  Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
278 
279  //
280  // However, we only hook the trace source once to avoid multiple trace sink
281  // calls per event (connect is independent of interface).
282  //
283  if (!PcapHooked (ipv4))
284  {
285  //
286  // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to
287  // node so we can get to Ipv4L3Protocol through Ipv4.
288  //
289  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
290  NS_ASSERT_MSG (ipv4L3Protocol, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
291  "m_ipv4Enabled and ipv4L3Protocol inconsistent");
292 
293  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
294  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
295  "Unable to connect ipv4L3Protocol \"Tx\"");
296 
297  result = ipv4L3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv4L3ProtocolRxTxSink));
298  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
299  "Unable to connect ipv4L3Protocol \"Rx\"");
300  }
301 
302  g_interfaceFileMapIpv4[std::make_pair (ipv4, interface)] = file;
303 }
304 
305 static void
307  Ptr<OutputStreamWrapper> stream,
308  Ipv4Header const &header,
309  Ptr<const Packet> packet,
310  Ipv4L3Protocol::DropReason reason,
311  Ptr<Ipv4> ipv4,
312  uint32_t interface)
313 {
314  //
315  // Since trace sources are independent of interface, if we hook a source
316  // on a particular protocol we will get traces for all of its interfaces.
317  // We need to filter this to only report interfaces for which the user
318  // has expressed interest.
319  //
320  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
321  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
322  {
323  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
324  return;
325  }
326 
327  Ptr<Packet> p = packet->Copy ();
328  p->AddHeader (header);
329  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *p << std::endl;
330 }
331 
332 static void
334  Ptr<OutputStreamWrapper> stream,
335  std::string context,
336  Ipv4Header const &header,
337  Ptr<const Packet> packet,
338  Ipv4L3Protocol::DropReason reason,
339  Ptr<Ipv4> ipv4,
340  uint32_t interface)
341 {
342  //
343  // Since trace sources are independent of interface, if we hook a source
344  // on a particular protocol we will get traces for all of its interfaces.
345  // We need to filter this to only report interfaces for which the user
346  // has expressed interest.
347  //
348  InterfacePairIpv4 pair = std::make_pair (ipv4, interface);
349  if (g_interfaceStreamMapIpv4.find (pair) == g_interfaceStreamMapIpv4.end ())
350  {
351  NS_LOG_INFO ("Ignoring packet to/from interface " << interface);
352  return;
353  }
354 
355  Ptr<Packet> p = packet->Copy ();
356  p->AddHeader (header);
357 #ifdef INTERFACE_CONTEXT
358  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << interface << ") "
359  << *p << std::endl;
360 #else
361  *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << " " << *p << std::endl;
362 #endif
363 }
364 
365 bool
366 ClickInternetStackHelper::AsciiHooked (Ptr<Ipv4> ipv4)
367 {
368  for ( InterfaceStreamMapIpv4::const_iterator i = g_interfaceStreamMapIpv4.begin ();
369  i != g_interfaceStreamMapIpv4.end ();
370  ++i)
371  {
372  if ((*i).first.first == ipv4)
373  {
374  return true;
375  }
376  }
377  return false;
378 }
379 
380 void
381 ClickInternetStackHelper::EnableAsciiIpv4Internal (
382  Ptr<OutputStreamWrapper> stream,
383  std::string prefix,
384  Ptr<Ipv4> ipv4,
385  uint32_t interface,
386  bool explicitFilename)
387 {
388  if (!m_ipv4Enabled)
389  {
390  NS_LOG_INFO ("Call to enable Ipv4 ascii tracing but Ipv4 not enabled");
391  return;
392  }
393 
394  //
395  // Our trace sinks are going to use packet printing, so we have to
396  // make sure that is turned on.
397  //
398  Packet::EnablePrinting ();
399 
400  //
401  // If we are not provided an OutputStreamWrapper, we are expected to create
402  // one using the usual trace filename conventions and hook WithoutContext
403  // since there will be one file per context and therefore the context would
404  // be redundant.
405  //
406  if (stream == 0)
407  {
408  //
409  // Set up an output stream object to deal with private ofstream copy
410  // constructor and lifetime issues. Let the helper decide the actual
411  // name of the file given the prefix.
412  //
413  // We have to create a stream and a mapping from protocol/interface to
414  // stream irrespective of how many times we want to trace a particular
415  // protocol.
416  //
417  AsciiTraceHelper asciiTraceHelper;
418 
419  std::string filename;
420  if (explicitFilename)
421  {
422  filename = prefix;
423  }
424  else
425  {
426  filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ipv4, interface);
427  }
428 
429  Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
430 
431  //
432  // However, we only hook the trace sources once to avoid multiple trace sink
433  // calls per event (connect is independent of interface).
434  //
435  if (!AsciiHooked (ipv4))
436  {
437  //
438  // We can use the default drop sink for the ArpL3Protocol since it has
439  // the usual signature. We can get to the Ptr<ArpL3Protocol> through
440  // our Ptr<Ipv4> since they must both be aggregated to the same node.
441  //
442  Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol> ();
443  asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol> (arpL3Protocol, "Drop", theStream);
444 
445  //
446  // The drop sink for the Ipv4L3Protocol uses a different signature than
447  // the default sink, so we have to cook one up for ourselves. We can get
448  // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must both
449  // be aggregated to the same node.
450  //
451  Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol> ();
452  bool result = ipv4L3Protocol->TraceConnectWithoutContext ("Drop",
454  theStream));
455  NS_ASSERT_MSG (result == true, "ClickInternetStackHelper::EanableAsciiIpv4Internal(): "
456  "Unable to connect ipv4L3Protocol \"Drop\"");
457  }
458 
459  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = theStream;
460  return;
461  }
462 
463  //
464  // If we are provided an OutputStreamWrapper, we are expected to use it, and
465  // to provide a context. We are free to come up with our own context if we
466  // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
467  // compatibility and simplicity, we just use Config::Connect and let it deal
468  // with the context.
469  //
470  // We need to associate the ipv4/interface with a stream to express interest
471  // in tracing events on that pair, however, we only hook the trace sources
472  // once to avoid multiple trace sink calls per event (connect is independent
473  // of interface).
474  //
475  if (!AsciiHooked (ipv4))
476  {
477  Ptr<Node> node = ipv4->GetObject<Node> ();
478  std::ostringstream oss;
479 
480  //
481  // For the ARP Drop, we are going to use the default trace sink provided by
482  // the ascii trace helper. There is actually no AsciiTraceHelper in sight
483  // here, but the default trace sinks are actually publicly available static
484  // functions that are always there waiting for just such a case.
485  //
486  oss << "/NodeList/" << node->GetId () << "/$ns3::ArpL3Protocol/Drop";
487  Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
488 
489  //
490  // This has all kinds of parameters coming with, so we have to cook up our
491  // own sink.
492  //
493  oss.str ("");
494  oss << "/NodeList/" << node->GetId () << "/$ns3::Ipv4L3Protocol/Drop";
496  }
497 
498  g_interfaceStreamMapIpv4[std::make_pair (ipv4, interface)] = stream;
499 }
500 
501 } // namespace ns3
502 
503 #endif // NS3_CLICK