A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
click-internet-stack-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 * Author: Faker Moatamri <faker.moatamri@sophia.inria.fr>
8 * Author: Lalith Suresh <suresh.lalith@gmail.com>
9 */
10
12
13#include "ns3/arp-l3-protocol.h"
14#include "ns3/assert.h"
15#include "ns3/callback.h"
16#include "ns3/config.h"
17#include "ns3/core-config.h"
18#include "ns3/ipv4-click-routing.h"
19#include "ns3/ipv4-l3-click-protocol.h"
20#include "ns3/ipv4.h"
21#include "ns3/log.h"
22#include "ns3/names.h"
23#include "ns3/net-device.h"
24#include "ns3/node.h"
25#include "ns3/object.h"
26#include "ns3/packet-socket-factory.h"
27#include "ns3/simulator.h"
28#include "ns3/string.h"
29#include "ns3/trace-helper.h"
30
31#include <limits>
32#include <map>
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("ClickInternetStackHelper");
38
39#define INTERFACE_CONTEXT
40
41typedef std::pair<Ptr<Ipv4>, uint32_t> InterfacePairIpv4;
42typedef std::map<InterfacePairIpv4, Ptr<PcapFileWrapper>> InterfaceFileMapIpv4;
43typedef std::map<InterfacePairIpv4, Ptr<OutputStreamWrapper>> InterfaceStreamMapIpv4;
44
46 g_interfaceFileMapIpv4; /**< A mapping of Ipv4/interface pairs to pcap files */
48 g_interfaceStreamMapIpv4; /**< A mapping of Ipv4/interface pairs to ascii streams */
49
50/**
51 * IPv4 Rx / Tx packet callback.
52 *
53 * \param p Packet.
54 * \param ipv4 IPv4 stack.
55 * \param interface Interface number.
56 */
57static void
59{
60 NS_LOG_FUNCTION(p << ipv4 << interface);
61
62 //
63 // Since trace sources are independent of interface, if we hook a source
64 // on a particular protocol we will get traces for all of its interfaces.
65 // We need to filter this to only report interfaces for which the user
66 // has expressed interest.
67 //
68 InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
69 if (g_interfaceFileMapIpv4.find(pair) == g_interfaceFileMapIpv4.end())
70 {
71 NS_LOG_INFO("Ignoring packet to/from interface " << interface);
72 return;
73 }
74
76 file->Write(Simulator::Now(), p);
77}
78
79/**
80 * Packet dropped callback without context.
81 *
82 * \param stream Output stream.
83 * \param header IPv4 header.
84 * \param packet Packet.
85 * \param reason Packet drop reason.
86 * \param ipv4 IPv4 stack.
87 * \param interface Interface number.
88 */
89static void
91 const Ipv4Header& header,
92 Ptr<const Packet> packet,
94 Ptr<Ipv4> ipv4,
95 uint32_t interface)
96{
97 //
98 // Since trace sources are independent of interface, if we hook a source
99 // on a particular protocol we will get traces for all of its interfaces.
100 // We need to filter this to only report interfaces for which the user
101 // has expressed interest.
102 //
103 InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
105 {
106 NS_LOG_INFO("Ignoring packet to/from interface " << interface);
107 return;
108 }
109
110 Ptr<Packet> p = packet->Copy();
111 p->AddHeader(header);
112 *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << *p << std::endl;
113}
114
115/**
116 * Packet dropped callback with context.
117 *
118 * \param stream Output stream.
119 * \param context Context.
120 * \param header IPv4 header.
121 * \param packet Packet.
122 * \param reason Packet drop reason.
123 * \param ipv4 IPv4 stack.
124 * \param interface Interface number.
125 */
126static void
128 std::string context,
129 const Ipv4Header& header,
130 Ptr<const Packet> packet,
132 Ptr<Ipv4> ipv4,
133 uint32_t interface)
134{
135 //
136 // Since trace sources are independent of interface, if we hook a source
137 // on a particular protocol we will get traces for all of its interfaces.
138 // We need to filter this to only report interfaces for which the user
139 // has expressed interest.
140 //
141 InterfacePairIpv4 pair = std::make_pair(ipv4, interface);
143 {
144 NS_LOG_INFO("Ignoring packet to/from interface " << interface);
145 return;
146 }
147
148 Ptr<Packet> p = packet->Copy();
149 p->AddHeader(header);
150#ifdef INTERFACE_CONTEXT
151 *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << "("
152 << interface << ") " << *p << std::endl;
153#else
154 *stream->GetStream() << "d " << Simulator::Now().GetSeconds() << " " << context << " " << *p
155 << std::endl;
156#endif
157}
158
160 : m_ipv4Enabled(true)
161{
162 Initialize();
163}
164
165void
169
173
178
181{
182 if (this != &o)
183 {
185 }
186 return *this;
187}
188
189void
195
196void
198{
199 for (auto i = c.Begin(); i != c.End(); ++i)
200 {
201 SetClickFile(*i, clickfile);
202 }
203}
204
205void
207{
208 m_nodeToClickFileMap.insert(std::make_pair(node, clickfile));
209}
210
211void
212ClickInternetStackHelper::SetDefines(NodeContainer c, std::map<std::string, std::string> defines)
213{
214 for (auto i = c.Begin(); i != c.End(); ++i)
215 {
216 SetDefines(*i, defines);
217 }
218}
219
220void
221ClickInternetStackHelper::SetDefines(Ptr<Node> node, std::map<std::string, std::string> defines)
222{
223 m_nodeToDefinesMap.insert(std::make_pair(node, defines));
224}
225
226void
228{
229 for (auto i = c.Begin(); i != c.End(); ++i)
230 {
232 }
233}
234
235void
237{
238 m_nodeToRoutingTableElementMap.insert(std::make_pair(node, rt));
239}
240
241void
243{
244 for (auto i = c.Begin(); i != c.End(); ++i)
245 {
246 Install(*i);
247 }
248}
249
250void
255
256void
258 const std::string typeId)
259{
260 ObjectFactory factory;
261 factory.SetTypeId(typeId);
262 Ptr<Object> protocol = factory.Create<Object>();
263 node->AggregateObject(protocol);
264}
265
266void
268{
269 if (m_ipv4Enabled)
270 {
271 if (node->GetObject<Ipv4>())
272 {
273 NS_FATAL_ERROR("ClickInternetStackHelper::Install (): Aggregating "
274 "an InternetStack to a node with an existing Ipv4 object");
275 return;
276 }
277
278 CreateAndAggregateObjectFromTypeId(node, "ns3::ArpL3Protocol");
279 CreateAndAggregateObjectFromTypeId(node, "ns3::Ipv4L3ClickProtocol");
280 CreateAndAggregateObjectFromTypeId(node, "ns3::Icmpv4L4Protocol");
281 CreateAndAggregateObjectFromTypeId(node, "ns3::UdpL4Protocol");
282 CreateAndAggregateObjectFromTypeId(node, "ns3::TcpL4Protocol");
284 node->AggregateObject(factory);
285 // Set routing
286 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
288 auto it = m_nodeToClickFileMap.find(node);
289
290 if (it != m_nodeToClickFileMap.end())
291 {
292 ipv4Routing->SetClickFile(it->second);
293 }
294
295 auto definesIt = m_nodeToDefinesMap.find(node);
296 if (definesIt != m_nodeToDefinesMap.end())
297 {
298 ipv4Routing->SetDefines(definesIt->second);
299 }
300
301 it = m_nodeToRoutingTableElementMap.find(node);
302 if (it != m_nodeToRoutingTableElementMap.end())
303 {
304 ipv4Routing->SetClickRoutingTableElement(it->second);
305 }
306 ipv4->SetRoutingProtocol(ipv4Routing);
307 node->AggregateObject(ipv4Routing);
308 }
309}
310
311void
312ClickInternetStackHelper::Install(std::string nodeName) const
313{
314 Ptr<Node> node = Names::Find<Node>(nodeName);
315 Install(node);
316}
317
318bool
320{
321 for (auto i = g_interfaceFileMapIpv4.begin(); i != g_interfaceFileMapIpv4.end(); ++i)
322 {
323 if ((*i).first.first == ipv4)
324 {
325 return true;
326 }
327 }
328 return false;
329}
330
331void
333 Ptr<Ipv4> ipv4,
334 uint32_t interface,
335 bool explicitFilename)
336{
337 NS_LOG_FUNCTION(prefix << ipv4 << interface);
338
339 if (!m_ipv4Enabled)
340 {
341 NS_LOG_INFO("Call to enable Ipv4 pcap tracing but Ipv4 not enabled");
342 return;
343 }
344
345 //
346 // We have to create a file and a mapping from protocol/interface to file
347 // irrespective of how many times we want to trace a particular protocol.
348 //
349 PcapHelper pcapHelper;
350
351 std::string filename;
352 if (explicitFilename)
353 {
354 filename = prefix;
355 }
356 else
357 {
358 filename = pcapHelper.GetFilenameFromInterfacePair(prefix, ipv4, interface);
359 }
360
361 Ptr<PcapFileWrapper> file = pcapHelper.CreateFile(filename, std::ios::out, PcapHelper::DLT_RAW);
362
363 //
364 // However, we only hook the trace source once to avoid multiple trace sink
365 // calls per event (connect is independent of interface).
366 //
367 if (!PcapHooked(ipv4))
368 {
369 //
370 // Ptr<Ipv4> is aggregated to node and Ipv4L3Protocol is aggregated to
371 // node so we can get to Ipv4L3Protocol through Ipv4.
372 //
373 Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol>();
374 NS_ASSERT_MSG(ipv4L3Protocol,
375 "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
376 "m_ipv4Enabled and ipv4L3Protocol inconsistent");
377
378 bool result =
379 ipv4L3Protocol->TraceConnectWithoutContext("Tx", MakeCallback(&Ipv4L3ProtocolRxTxSink));
380 NS_ASSERT_MSG(result == true,
381 "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
382 "Unable to connect ipv4L3Protocol \"Tx\"");
383
384 result =
385 ipv4L3Protocol->TraceConnectWithoutContext("Rx", MakeCallback(&Ipv4L3ProtocolRxTxSink));
386 NS_ASSERT_MSG(result == true,
387 "ClickInternetStackHelper::EnablePcapIpv4Internal(): "
388 "Unable to connect ipv4L3Protocol \"Rx\"");
389 }
390
391 g_interfaceFileMapIpv4[std::make_pair(ipv4, interface)] = file;
392}
393
394bool
396{
397 for (auto i = g_interfaceStreamMapIpv4.begin(); i != g_interfaceStreamMapIpv4.end(); ++i)
398 {
399 if ((*i).first.first == ipv4)
400 {
401 return true;
402 }
403 }
404 return false;
405}
406
407void
409 std::string prefix,
410 Ptr<Ipv4> ipv4,
411 uint32_t interface,
412 bool explicitFilename)
413{
414 if (!m_ipv4Enabled)
415 {
416 NS_LOG_INFO("Call to enable Ipv4 ascii tracing but Ipv4 not enabled");
417 return;
418 }
419
420 //
421 // Our trace sinks are going to use packet printing, so we have to
422 // make sure that is turned on.
423 //
425
426 //
427 // If we are not provided an OutputStreamWrapper, we are expected to create
428 // one using the usual trace filename conventions and hook WithoutContext
429 // since there will be one file per context and therefore the context would
430 // be redundant.
431 //
432 if (!stream)
433 {
434 //
435 // Set up an output stream object to deal with private ofstream copy
436 // constructor and lifetime issues. Let the helper decide the actual
437 // name of the file given the prefix.
438 //
439 // We have to create a stream and a mapping from protocol/interface to
440 // stream irrespective of how many times we want to trace a particular
441 // protocol.
442 //
443 AsciiTraceHelper asciiTraceHelper;
444
445 std::string filename;
446 if (explicitFilename)
447 {
448 filename = prefix;
449 }
450 else
451 {
452 filename = asciiTraceHelper.GetFilenameFromInterfacePair(prefix, ipv4, interface);
453 }
454
455 Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream(filename);
456
457 //
458 // However, we only hook the trace sources once to avoid multiple trace sink
459 // calls per event (connect is independent of interface).
460 //
461 if (!AsciiHooked(ipv4))
462 {
463 //
464 // We can use the default drop sink for the ArpL3Protocol since it has
465 // the usual signature. We can get to the Ptr<ArpL3Protocol> through
466 // our Ptr<Ipv4> since they must both be aggregated to the same node.
467 //
468 Ptr<ArpL3Protocol> arpL3Protocol = ipv4->GetObject<ArpL3Protocol>();
469 asciiTraceHelper.HookDefaultDropSinkWithoutContext<ArpL3Protocol>(arpL3Protocol,
470 "Drop",
471 theStream);
472
473 //
474 // The drop sink for the Ipv4L3Protocol uses a different signature than
475 // the default sink, so we have to cook one up for ourselves. We can get
476 // to the Ptr<Ipv4L3Protocol> through our Ptr<Ipv4> since they must both
477 // be aggregated to the same node.
478 //
479 Ptr<Ipv4L3Protocol> ipv4L3Protocol = ipv4->GetObject<Ipv4L3Protocol>();
480 bool result = ipv4L3Protocol->TraceConnectWithoutContext(
481 "Drop",
483 NS_ASSERT_MSG(result == true,
484 "ClickInternetStackHelper::EnableAsciiIpv4Internal(): "
485 "Unable to connect ipv4L3Protocol \"Drop\"");
486 }
487
488 g_interfaceStreamMapIpv4[std::make_pair(ipv4, interface)] = theStream;
489 return;
490 }
491
492 //
493 // If we are provided an OutputStreamWrapper, we are expected to use it, and
494 // to provide a context. We are free to come up with our own context if we
495 // want, and use the AsciiTraceHelper Hook*WithContext functions, but for
496 // compatibility and simplicity, we just use Config::Connect and let it deal
497 // with the context.
498 //
499 // We need to associate the ipv4/interface with a stream to express interest
500 // in tracing events on that pair, however, we only hook the trace sources
501 // once to avoid multiple trace sink calls per event (connect is independent
502 // of interface).
503 //
504 if (!AsciiHooked(ipv4))
505 {
506 Ptr<Node> node = ipv4->GetObject<Node>();
507 std::ostringstream oss;
508
509 //
510 // For the ARP Drop, we are going to use the default trace sink provided by
511 // the ascii trace helper. There is actually no AsciiTraceHelper in sight
512 // here, but the default trace sinks are actually publicly available static
513 // functions that are always there waiting for just such a case.
514 //
515 oss << "/NodeList/" << node->GetId() << "/$ns3::ArpL3Protocol/Drop";
516 Config::Connect(oss.str(),
518
519 //
520 // This has all kinds of parameters coming with, so we have to cook up our
521 // own sink.
522 //
523 oss.str("");
524 oss << "/NodeList/" << node->GetId() << "/$ns3::Ipv4L3Protocol/Drop";
526 }
527
528 g_interfaceStreamMapIpv4[std::make_pair(ipv4, interface)] = stream;
529}
530
531} // namespace ns3
An implementation of the ARP protocol.
Manage ASCII trace files for device models.
void HookDefaultDropSinkWithoutContext(Ptr< T > object, std::string traceName, Ptr< OutputStreamWrapper > stream)
Hook a trace source to the default drop operation trace sink that does not accept nor log a trace con...
static void DefaultDropSinkWithContext(Ptr< OutputStreamWrapper > file, std::string context, Ptr< const Packet > p)
Basic Drop default trace sink.
std::string GetFilenameFromInterfacePair(std::string prefix, Ptr< Object > object, uint32_t interface, bool useObjectNames=true)
Let the ascii trace helper figure out a reasonable filename to use for an ascii trace file associated...
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we'll use to write the traced bits.
aggregate Click/IP/TCP/UDP functionality to existing Nodes.
std::map< Ptr< Node >, std::string > m_nodeToClickFileMap
Node to Click file mapping.
~ClickInternetStackHelper() override
Destroy the ClickInternetStackHelper.
ClickInternetStackHelper & operator=(const ClickInternetStackHelper &o)
Assignment operator.
bool PcapHooked(Ptr< Ipv4 > ipv4)
Check if PCAP is hooked.
void SetDefines(NodeContainer c, std::map< std::string, std::string > defines)
Set defines to be used for a group of nodes.
static void CreateAndAggregateObjectFromTypeId(Ptr< Node > node, const std::string typeId)
Create and aggregate object from type ID.
std::map< Ptr< Node >, std::string > m_nodeToRoutingTableElementMap
Node to Routing Table Element mapping.
void Initialize()
Initialize stack helper.
bool m_ipv4Enabled
IPv4 install state (enabled/disabled) ?
void SetClickFile(NodeContainer c, std::string clickfile)
Set a Click file to be used for a group of nodes.
bool AsciiHooked(Ptr< Ipv4 > ipv4)
Check if ASCII is hooked.
ClickInternetStackHelper()
Create a new ClickInternetStackHelper which uses Ipv4ClickRouting for routing.
void SetRoutingTableElement(NodeContainer c, std::string rt)
Set a Click routing table element for a group of nodes.
void InstallAll() const
Aggregate IPv4, UDP, and TCP stacks to all nodes in the simulation.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4L3ClickProtocol, ns3::ArpL3Protocol, ns3::Udp,...
void EnablePcapIpv4Internal(std::string prefix, Ptr< Ipv4 > ipv4, uint32_t interface, bool explicitFilename) override
Enable pcap output the indicated Ipv4 and interface pair.
void Reset()
Return helper internal state to that of a newly constructed one.
std::map< Ptr< Node >, std::map< std::string, std::string > > m_nodeToDefinesMap
Node to Click defines mapping.
void EnableAsciiIpv4Internal(Ptr< OutputStreamWrapper > stream, std::string prefix, Ptr< Ipv4 > ipv4, uint32_t interface, bool explicitFilename) override
Enable ascii trace output on the indicated Ipv4 and interface pair.
Packet header for IPv4.
Definition ipv4-header.h:23
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
Implement the IPv4 layer.
DropReason
Reason why a packet has been dropped.
static Ptr< T > Find(std::string path)
Given a name path string, look to see if there's an object in the system with that associated to it.
Definition names.h:443
keep track of a set of node pointers.
Iterator End() const
Get an iterator which indicates past-the-last Node in the container.
static NodeContainer GetGlobal()
Create a NodeContainer that contains a list of all nodes created through NodeContainer::Create() and ...
Iterator Begin() const
Get an iterator which refers to the first Node in the container.
A network Node.
Definition node.h:46
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
void SetTypeId(TypeId tid)
Set the TypeId of the Objects to be created by this factory.
A base class which provides memory management and object aggregation.
Definition object.h:78
static void EnablePrinting()
Enable printing packets metadata.
Definition packet.cc:585
Manage pcap files for device models.
Ptr< PcapFileWrapper > CreateFile(std::string filename, std::ios::openmode filemode, DataLinkType dataLinkType, uint32_t snapLen=std::numeric_limits< uint32_t >::max(), int32_t tzCorrection=0)
Create and initialize a pcap file.
std::string GetFilenameFromInterfacePair(std::string prefix, Ptr< Object > object, uint32_t interface, bool useObjectNames=true)
Let the pcap helper figure out a reasonable filename to use for the pcap file associated with a node.
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
#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:75
void Connect(std::string path, const CallbackBase &cb)
Definition config.cc:967
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
auto MakeBoundCallback(R(*fnPtr)(Args...), BArgs &&... bargs)
Make Callbacks with varying number of bound arguments.
Definition callback.h:745
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::pair< Ptr< Ipv4 >, uint32_t > InterfacePairIpv4
Ipv4/interface pair.
std::map< InterfacePairIpv4, Ptr< OutputStreamWrapper > > InterfaceStreamMapIpv4
Ipv4/interface and output stream container.
static void Ipv4L3ProtocolDropSinkWithContext(Ptr< OutputStreamWrapper > stream, std::string context, const Ipv4Header &header, Ptr< const Packet > packet, Ipv4L3Protocol::DropReason reason, Ptr< Ipv4 > ipv4, uint32_t interface)
Packet dropped callback with context.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
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)
IPv4 Rx / Tx packet callback.
static InterfaceFileMapIpv4 g_interfaceFileMapIpv4
A mapping of Ipv4/interface pairs to pcap files.
static InterfaceStreamMapIpv4 g_interfaceStreamMapIpv4
A mapping of Ipv4/interface pairs to ascii streams.
static void Ipv4L3ProtocolDropSinkWithoutContext(Ptr< OutputStreamWrapper > stream, const Ipv4Header &header, Ptr< const Packet > packet, Ipv4L3Protocol::DropReason reason, Ptr< Ipv4 > ipv4, uint32_t interface)
Packet dropped callback without context.