A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ipv4-global-routing.cc
Go to the documentation of this file.
1//
2// Copyright (c) 2008 University of Washington
3//
4// SPDX-License-Identifier: GPL-2.0-only
5//
6
8
10#include "ipv4-route.h"
12
13#include "ns3/boolean.h"
14#include "ns3/log.h"
15#include "ns3/names.h"
16#include "ns3/net-device.h"
17#include "ns3/node.h"
18#include "ns3/object.h"
19#include "ns3/packet.h"
20#include "ns3/simulator.h"
21
22#include <iomanip>
23#include <vector>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("Ipv4GlobalRouting");
29
30NS_OBJECT_ENSURE_REGISTERED(Ipv4GlobalRouting);
31
32TypeId
34{
35 static TypeId tid =
36 TypeId("ns3::Ipv4GlobalRouting")
38 .SetGroupName("Internet")
39 .AddAttribute("RandomEcmpRouting",
40 "Set to true if packets are randomly routed among ECMP; set to false for "
41 "using only one route consistently",
42 BooleanValue(false),
45 .AddAttribute("RespondToInterfaceEvents",
46 "Set to true if you want to dynamically recompute the global routes upon "
47 "Interface notification events (up/down, or add/remove address)",
48 BooleanValue(false),
51 return tid;
52}
53
55 : m_randomEcmpRouting(false),
56 m_respondToInterfaceEvents(false)
57{
58 NS_LOG_FUNCTION(this);
59
61}
62
67
68void
70{
71 NS_LOG_FUNCTION(this << dest << nextHop << interface);
72 auto route = new Ipv4RoutingTableEntry();
73 *route = Ipv4RoutingTableEntry::CreateHostRouteTo(dest, nextHop, interface);
74 for (auto routePointer : m_hostRoutes)
75 {
76 if (*routePointer == *route)
77 {
78 NS_LOG_LOGIC("Route already exists");
79 delete route;
80 return;
81 }
82 }
83 m_hostRoutes.push_back(route);
84}
85
86void
88{
89 NS_LOG_FUNCTION(this << dest << interface);
90 auto route = new Ipv4RoutingTableEntry();
91 *route = Ipv4RoutingTableEntry::CreateHostRouteTo(dest, interface);
92 for (auto routePointer : m_hostRoutes)
93 {
94 if (*routePointer == *route)
95 {
96 NS_LOG_LOGIC("Route already exists");
97 delete route;
98 return;
99 }
100 }
101 m_hostRoutes.push_back(route);
102}
103
104void
106 Ipv4Mask networkMask,
107 Ipv4Address nextHop,
108 uint32_t interface)
109{
110 NS_LOG_FUNCTION(this << network << networkMask << nextHop << interface);
111 auto route = new Ipv4RoutingTableEntry();
112 *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, nextHop, interface);
113 for (auto routePointer : m_networkRoutes)
114 {
115 if (*routePointer == *route)
116 {
117 NS_LOG_LOGIC("Route already exists");
118 delete route;
119 return;
120 }
121 }
122 m_networkRoutes.push_back(route);
123}
124
125void
127{
128 NS_LOG_FUNCTION(this << network << networkMask << interface);
129 auto route = new Ipv4RoutingTableEntry();
130 *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, interface);
131 for (auto routePointer : m_networkRoutes)
132 {
133 if (*routePointer == *route)
134 {
135 NS_LOG_LOGIC("Route already exists");
136 delete route;
137 return;
138 }
139 }
140 m_networkRoutes.push_back(route);
141}
142
143void
145 Ipv4Mask networkMask,
146 Ipv4Address nextHop,
147 uint32_t interface)
148{
149 NS_LOG_FUNCTION(this << network << networkMask << nextHop << interface);
150 auto route = new Ipv4RoutingTableEntry();
151 *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, nextHop, interface);
152 for (auto routePointer : m_ASexternalRoutes)
153 {
154 if (*routePointer == *route)
155 {
156 NS_LOG_LOGIC("Route already exists");
157 delete route;
158 return;
159 }
160 }
161 m_ASexternalRoutes.push_back(route);
162}
163
166{
167 NS_LOG_FUNCTION(this << dest << oif);
168 NS_LOG_LOGIC("Looking for route for destination " << dest);
169 Ptr<Ipv4Route> rtentry = nullptr;
170 // store all available routes that bring packets to their destination
171 typedef std::vector<Ipv4RoutingTableEntry*> RouteVec_t;
172 RouteVec_t allRoutes;
173
174 NS_LOG_LOGIC("Number of m_hostRoutes = " << m_hostRoutes.size());
175 for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
176 {
177 NS_ASSERT((*i)->IsHost());
178 if ((*i)->GetDest() == dest)
179 {
180 if (oif)
181 {
182 if (oif != m_ipv4->GetNetDevice((*i)->GetInterface()))
183 {
184 NS_LOG_LOGIC("Not on requested interface, skipping");
185 continue;
186 }
187 }
188 allRoutes.push_back(*i);
189 NS_LOG_LOGIC(allRoutes.size() << "Found global host route" << *i);
190 }
191 }
192 if (allRoutes.empty()) // if no host route is found
193 {
194 NS_LOG_LOGIC("Number of m_networkRoutes" << m_networkRoutes.size());
195 // store the length of the longest mask.
196 uint16_t longest_mask = 0;
197 for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
198 {
199 Ipv4Mask mask = (*j)->GetDestNetworkMask();
200 uint16_t masklen = mask.GetPrefixLength();
201
202 Ipv4Address entry = (*j)->GetDestNetwork();
203 if (mask.IsMatch(dest, entry))
204 {
205 if (oif)
206 {
207 if (oif != m_ipv4->GetNetDevice((*j)->GetInterface()))
208 {
209 NS_LOG_LOGIC("Not on requested interface, skipping");
210 continue;
211 }
212 }
213 NS_LOG_LOGIC(allRoutes.size() << "Found global network route" << *j);
214 if (masklen < longest_mask) // Not interested if got shorter mask
215 {
216 NS_LOG_LOGIC("Previous match longer, skipping");
217 continue;
218 }
219 else if (masklen == longest_mask)
220 {
221 NS_LOG_LOGIC("Equal mask length, adding this to the list");
222 allRoutes.push_back(*j);
223 }
224 else
225 {
226 NS_LOG_LOGIC("Longer mask length found, clearing the list and adding");
227 allRoutes.clear();
228 allRoutes.push_back(*j);
229 }
230 }
231 }
232 }
233 if (allRoutes.empty()) // consider external if no host/network found
234 {
235 for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
236 {
237 Ipv4Mask mask = (*k)->GetDestNetworkMask();
238 Ipv4Address entry = (*k)->GetDestNetwork();
239 if (mask.IsMatch(dest, entry))
240 {
241 NS_LOG_LOGIC("Found external route" << *k);
242 if (oif)
243 {
244 if (oif != m_ipv4->GetNetDevice((*k)->GetInterface()))
245 {
246 NS_LOG_LOGIC("Not on requested interface, skipping");
247 continue;
248 }
249 }
250 allRoutes.push_back(*k);
251 break;
252 }
253 }
254 }
255 if (!allRoutes.empty()) // if route(s) is found
256 {
257 // pick up one of the routes uniformly at random if random
258 // ECMP routing is enabled, or always select the first route
259 // consistently if random ECMP routing is disabled
260 uint32_t selectIndex;
262 {
263 selectIndex = m_rand->GetInteger(0, allRoutes.size() - 1);
264 }
265 else
266 {
267 selectIndex = 0;
268 }
269 Ipv4RoutingTableEntry* route = allRoutes.at(selectIndex);
270 // create a Ipv4Route object from the selected routing table entry
271 rtentry = Create<Ipv4Route>();
272 rtentry->SetDestination(route->GetDest());
273 /// @todo handle multi-address case
274 rtentry->SetSource(m_ipv4->GetAddress(route->GetInterface(), 0).GetLocal());
275 rtentry->SetGateway(route->GetGateway());
276 uint32_t interfaceIdx = route->GetInterface();
277 rtentry->SetOutputDevice(m_ipv4->GetNetDevice(interfaceIdx));
278 return rtentry;
279 }
280 else
281 {
282 return nullptr;
283 }
284}
285
288{
289 NS_LOG_FUNCTION(this);
290 uint32_t n = 0;
291 n += m_hostRoutes.size();
292 n += m_networkRoutes.size();
293 n += m_ASexternalRoutes.size();
294 return n;
295}
296
299{
300 NS_LOG_FUNCTION(this << index);
301 if (index < m_hostRoutes.size())
302 {
303 uint32_t tmp = 0;
304 for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
305 {
306 if (tmp == index)
307 {
308 return *i;
309 }
310 tmp++;
311 }
312 }
313 index -= m_hostRoutes.size();
314 uint32_t tmp = 0;
315 if (index < m_networkRoutes.size())
316 {
317 for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
318 {
319 if (tmp == index)
320 {
321 return *j;
322 }
323 tmp++;
324 }
325 }
326 index -= m_networkRoutes.size();
327 tmp = 0;
328 for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
329 {
330 if (tmp == index)
331 {
332 return *k;
333 }
334 tmp++;
335 }
336 NS_ASSERT(false);
337 // quiet compiler.
338 return nullptr;
339}
340
341void
343{
344 NS_LOG_FUNCTION(this << index);
345 if (index < m_hostRoutes.size())
346 {
347 uint32_t tmp = 0;
348 for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i++)
349 {
350 if (tmp == index)
351 {
352 NS_LOG_LOGIC("Removing route " << index << "; size = " << m_hostRoutes.size());
353 delete *i;
354 m_hostRoutes.erase(i);
355 NS_LOG_LOGIC("Done removing host route "
356 << index << "; host route remaining size = " << m_hostRoutes.size());
357 return;
358 }
359 tmp++;
360 }
361 }
362 index -= m_hostRoutes.size();
363 uint32_t tmp = 0;
364 for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j++)
365 {
366 if (tmp == index)
367 {
368 NS_LOG_LOGIC("Removing route " << index << "; size = " << m_networkRoutes.size());
369 delete *j;
370 m_networkRoutes.erase(j);
371 NS_LOG_LOGIC("Done removing network route "
372 << index << "; network route remaining size = " << m_networkRoutes.size());
373 return;
374 }
375 tmp++;
376 }
377 index -= m_networkRoutes.size();
378 tmp = 0;
379 for (auto k = m_ASexternalRoutes.begin(); k != m_ASexternalRoutes.end(); k++)
380 {
381 if (tmp == index)
382 {
383 NS_LOG_LOGIC("Removing route " << index << "; size = " << m_ASexternalRoutes.size());
384 delete *k;
385 m_ASexternalRoutes.erase(k);
386 NS_LOG_LOGIC("Done removing network route "
387 << index << "; network route remaining size = " << m_networkRoutes.size());
388 return;
389 }
390 tmp++;
391 }
392 NS_ASSERT(false);
393}
394
395int64_t
397{
398 NS_LOG_FUNCTION(this << stream);
399 m_rand->SetStream(stream);
400 return 1;
401}
402
403void
405{
406 NS_LOG_FUNCTION(this);
407 for (auto i = m_hostRoutes.begin(); i != m_hostRoutes.end(); i = m_hostRoutes.erase(i))
408 {
409 delete (*i);
410 }
411 for (auto j = m_networkRoutes.begin(); j != m_networkRoutes.end(); j = m_networkRoutes.erase(j))
412 {
413 delete (*j);
414 }
415 for (auto l = m_ASexternalRoutes.begin(); l != m_ASexternalRoutes.end();
416 l = m_ASexternalRoutes.erase(l))
417 {
418 delete (*l);
419 }
420
422}
423
424// Formatted like output of "route -n" command
425void
427{
428 NS_LOG_FUNCTION(this << stream);
429 std::ostream* os = stream->GetStream();
430 // Copy the current ostream state
431 std::ios oldState(nullptr);
432 oldState.copyfmt(*os);
433
434 *os << std::resetiosflags(std::ios::adjustfield) << std::setiosflags(std::ios::left);
435
436 *os << "Node: " << m_ipv4->GetObject<Node>()->GetId() << ", Time: " << Now().As(unit)
437 << ", Local time: " << m_ipv4->GetObject<Node>()->GetLocalTime().As(unit)
438 << ", Ipv4GlobalRouting table" << std::endl;
439
440 if (GetNRoutes() > 0)
441 {
442 *os << "Destination Gateway Genmask Flags Metric Ref Use Iface"
443 << std::endl;
444 for (uint32_t j = 0; j < GetNRoutes(); j++)
445 {
446 std::ostringstream dest;
447 std::ostringstream gw;
448 std::ostringstream mask;
449 std::ostringstream flags;
451 dest << route.GetDest();
452 *os << std::setw(16) << dest.str();
453 gw << route.GetGateway();
454 *os << std::setw(16) << gw.str();
455 mask << route.GetDestNetworkMask();
456 *os << std::setw(16) << mask.str();
457 flags << "U";
458 if (route.IsHost())
459 {
460 flags << "H";
461 }
462 else if (route.IsGateway())
463 {
464 flags << "G";
465 }
466 *os << std::setw(6) << flags.str();
467 // Metric not implemented
468 *os << "-"
469 << " ";
470 // Ref ct not implemented
471 *os << "-"
472 << " ";
473 // Use not implemented
474 *os << "-"
475 << " ";
476 if (!Names::FindName(m_ipv4->GetNetDevice(route.GetInterface())).empty())
477 {
479 }
480 else
481 {
482 *os << route.GetInterface();
483 }
484 *os << std::endl;
485 }
486 }
487 *os << std::endl;
488 // Restore the previous ostream state
489 (*os).copyfmt(oldState);
490}
491
494 const Ipv4Header& header,
495 Ptr<NetDevice> oif,
496 Socket::SocketErrno& sockerr)
497{
498 NS_LOG_FUNCTION(this << p << &header << oif << &sockerr);
499 //
500 // First, see if this is a multicast packet we have a route for. If we
501 // have a route, then send the packet down each of the specified interfaces.
502 //
503 if (header.GetDestination().IsMulticast())
504 {
505 NS_LOG_LOGIC("Multicast destination-- returning false");
506 return nullptr; // Let other routing protocols try to handle this
507 }
508 //
509 // See if this is a unicast packet we have a route for.
510 //
511 NS_LOG_LOGIC("Unicast destination- looking up");
512 Ptr<Ipv4Route> rtentry = LookupGlobal(header.GetDestination(), oif);
513 if (rtentry)
514 {
515 sockerr = Socket::ERROR_NOTERROR;
516 }
517 else
518 {
520 }
521 return rtentry;
522}
523
524bool
526 const Ipv4Header& header,
528 const UnicastForwardCallback& ucb,
529 const MulticastForwardCallback& mcb,
530 const LocalDeliverCallback& lcb,
531 const ErrorCallback& ecb)
532{
533 NS_LOG_FUNCTION(this << p << header << header.GetSource() << header.GetDestination() << idev
534 << &lcb << &ecb);
535 // Check if input device supports IP
538
539 if (m_ipv4->IsDestinationAddress(header.GetDestination(), iif))
540 {
541 if (!lcb.IsNull())
542 {
543 NS_LOG_LOGIC("Local delivery to " << header.GetDestination());
544 lcb(p, header, iif);
545 return true;
546 }
547 else
548 {
549 // The local delivery callback is null. This may be a multicast
550 // or broadcast packet, so return false so that another
551 // multicast routing protocol can handle it. It should be possible
552 // to extend this to explicitly check whether it is a unicast
553 // packet, and invoke the error callback if so
554 return false;
555 }
556 }
557
558 // Check if input device supports IP forwarding
559 if (!m_ipv4->IsForwarding(iif))
560 {
561 NS_LOG_LOGIC("Forwarding disabled for this interface");
562 ecb(p, header, Socket::ERROR_NOROUTETOHOST);
563 return true;
564 }
565 // Next, try to find a route
566 NS_LOG_LOGIC("Unicast destination- looking up global route");
567 Ptr<Ipv4Route> rtentry = LookupGlobal(header.GetDestination());
568 if (rtentry)
569 {
570 NS_LOG_LOGIC("Found unicast destination- calling unicast callback");
571 ucb(rtentry, p, header);
572 return true;
573 }
574 else
575 {
576 NS_LOG_LOGIC("Did not find unicast destination- returning false");
577 return false; // Let other routing protocols try to handle this
578 // route request.
579 }
580}
581
582void
593
594void
605
606void
608{
609 NS_LOG_FUNCTION(this << interface << address);
610 if (m_respondToInterfaceEvents && Simulator::Now().GetSeconds() > 0) // avoid startup events
611 {
615 }
616}
617
618void
629
630void
632{
633 NS_LOG_FUNCTION(this << ipv4);
634 NS_ASSERT(!m_ipv4 && ipv4);
635 m_ipv4 = ipv4;
636}
637
638} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
bool IsNull() const
Check for null implementation.
Definition callback.h:555
static void DeleteGlobalRoutes()
Delete all static routes on all nodes that have a GlobalRouterInterface.
static void InitializeRoutes()
Compute routes using a Dijkstra SPF computation and populate per-node forwarding tables.
static void BuildGlobalRoutingDatabase()
Build the routing database by gathering Link State Advertisements from each node exporting a GlobalRo...
Ipv4 addresses are stored in host order in this class.
bool IsMulticast() const
void AddHostRouteTo(Ipv4Address dest, Ipv4Address nextHop, uint32_t interface)
Add a host route to the global routing table.
bool RouteInput(Ptr< const Packet > p, const Ipv4Header &header, Ptr< const NetDevice > idev, const UnicastForwardCallback &ucb, const MulticastForwardCallback &mcb, const LocalDeliverCallback &lcb, const ErrorCallback &ecb) override
Route an input packet (to be forwarded or locally delivered)
void AddASExternalRouteTo(Ipv4Address network, Ipv4Mask networkMask, Ipv4Address nextHop, uint32_t interface)
Add an external route to the global routing table.
Ipv4RoutingTableEntry * GetRoute(uint32_t i) const
Get a route from the global unicast routing table.
static TypeId GetTypeId()
Get the type ID.
void DoDispose() override
Destructor implementation.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Ptr< UniformRandomVariable > m_rand
A uniform random number generator for randomly routing packets among ECMP.
void RemoveRoute(uint32_t i)
Remove a route from the global unicast routing table.
void NotifyInterfaceDown(uint32_t interface) override
void NotifyInterfaceUp(uint32_t interface) override
void SetIpv4(Ptr< Ipv4 > ipv4) override
void PrintRoutingTable(Ptr< OutputStreamWrapper > stream, Time::Unit unit=Time::S) const override
Print the Routing Table entries.
uint32_t GetNRoutes() const
Get the number of individual unicast routes that have been added to the routing table.
Ipv4GlobalRouting()
Construct an empty Ipv4GlobalRouting routing protocol,.
Ptr< Ipv4 > m_ipv4
associated IPv4 instance
Ptr< Ipv4Route > RouteOutput(Ptr< Packet > p, const Ipv4Header &header, Ptr< NetDevice > oif, Socket::SocketErrno &sockerr) override
Query routing cache for an existing route, for an outbound packet.
void AddNetworkRouteTo(Ipv4Address network, Ipv4Mask networkMask, Ipv4Address nextHop, uint32_t interface)
Add a network route to the global routing table.
void NotifyRemoveAddress(uint32_t interface, Ipv4InterfaceAddress address) override
ASExternalRoutes m_ASexternalRoutes
External routes imported.
HostRoutes m_hostRoutes
Routes to hosts.
bool m_respondToInterfaceEvents
Set to true if this interface should respond to interface events by globally recomputing routes.
void NotifyAddAddress(uint32_t interface, Ipv4InterfaceAddress address) override
bool m_randomEcmpRouting
Set to true if packets are randomly routed among ECMP; set to false for using only one route consiste...
NetworkRoutes m_networkRoutes
Routes to networks.
Ptr< Ipv4Route > LookupGlobal(Ipv4Address dest, Ptr< NetDevice > oif=nullptr)
Lookup in the forwarding table for destination.
Packet header for IPv4.
Definition ipv4-header.h:23
Ipv4Address GetSource() const
Ipv4Address GetDestination() const
virtual bool IsForwarding(uint32_t interface) const =0
virtual Ipv4InterfaceAddress GetAddress(uint32_t interface, uint32_t addressIndex) const =0
Because addresses can be removed, the addressIndex is not guaranteed to be static across calls to thi...
virtual Ptr< NetDevice > GetNetDevice(uint32_t interface)=0
virtual bool IsDestinationAddress(Ipv4Address address, uint32_t iif) const =0
Determine whether address and interface corresponding to received packet can be accepted for local de...
virtual int32_t GetInterfaceForDevice(Ptr< const NetDevice > device) const =0
a class to store IPv4 address information on an interface
Ipv4Address GetLocal() const
Get the local address.
a class to represent an Ipv4 address mask
uint16_t GetPrefixLength() const
bool IsMatch(Ipv4Address a, Ipv4Address b) const
A record of an IPv4 routing table entry for Ipv4GlobalRouting and Ipv4StaticRouting.
Ipv4Address GetDest() const
Ipv4Address GetGateway() const
bool IsHost() const
bool IsGateway() const
uint32_t GetInterface() const
static Ipv4RoutingTableEntry CreateNetworkRouteTo(Ipv4Address network, Ipv4Mask networkMask, Ipv4Address nextHop, uint32_t interface)
static Ipv4RoutingTableEntry CreateHostRouteTo(Ipv4Address dest, Ipv4Address nextHop, uint32_t interface)
Ipv4Mask GetDestNetworkMask() const
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and,...
Definition names.cc:818
A network Node.
Definition node.h:46
A base class which provides memory management and object aggregation.
Definition object.h:78
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition socket.h:73
@ ERROR_NOROUTETOHOST
Definition socket.h:84
@ ERROR_NOTERROR
Definition socket.h:74
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:409
Unit
The unit to use to interpret a number representing time.
Definition nstime.h:102
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:439
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
Every class exported by the ns3 library is enclosed in the ns3 namespace.