1
.. include:: replace.txt
6
In |ns3| simulations, there are two main aspects to configuration:
8
* the simulation topology and how objects are connected
9
* the values used by the models instantiated in the topology
11
This chapter focuses on the second item above: how the many values in use in
12
|ns3| are organized, documented, and modifiable by |ns3| users. The |ns3|
13
attribute system is also the underpinning of how traces and statistics are
14
gathered in the simulator.
16
Before delving into details of the attribute value system, it will help to
17
review some basic properties of class :cpp:class:`ns3::Object`.
22
|ns3| is fundamentally a C++ object-based system. By this we mean that new C++
23
classes (types) can be declared, defined, and subclassed as usual.
25
Many |ns3| objects inherit from the :cpp:class:`ns3::Object` base class. These
26
objects have some additional properties that we exploit for organizing the
27
system and improving the memory management of our objects:
29
* a "metadata" system that links the class name to a lot of meta-information
30
about the object, including the base class of the subclass, the set of
31
accessible constructors in the subclass, and the set of "attributes" of the
33
* a reference counting smart pointer implementation, for memory management.
35
|ns3| objects that use the attribute system derive from either
36
:cpp:class:`ns3::Object` or :cpp:class:`ns3::ObjectBase`. Most |ns3| objects we
37
will discuss derive from :cpp:class:`ns3::Object`, but a few that are outside
38
the smart pointer memory management framework derive from
39
:cpp:class:`ns3::ObjectBase`.
41
Let's review a couple of properties of these objects.
46
As introduced in the |ns3| tutorial, |ns3| objects are memory managed by a
47
`reference counting smart pointer implementation
48
<http://en.wikipedia.org/wiki/Smart_pointer>`_, class :cpp:class:`ns3::Ptr`.
50
Smart pointers are used extensively in the |ns3| APIs, to avoid passing
51
references to heap-allocated objects that may cause memory leaks.
52
For most basic usage (syntax), treat a smart pointer like a regular pointer:::
54
Ptr<WifiNetDevice> nd = ...;
55
nd->CallSomeFunction ();
61
As we discussed above in :ref:`Memory management and class Ptr`, at the
62
lowest-level API, objects of type :cpp:class:`ns3::Object` are not instantiated
63
using ``operator new`` as usual but instead by a templated function called
64
:cpp:func:`CreateObject()`.
66
A typical way to create such an object is as follows:::
68
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
70
You can think of this as being functionally equivalent to:::
72
WifiNetDevice* nd = new WifiNetDevice ();
74
Objects that derive from :cpp:class:`ns3::Object` must be allocated on the heap
75
using CreateObject(). Those deriving from :cpp:class:`ns3::ObjectBase`, such as
76
|ns3| helper functions and packet headers and trailers, can be allocated on the
79
In some scripts, you may not see a lot of CreateObject() calls in the code; this
80
is because there are some helper objects in effect that are doing the
81
CreateObject()s for you.
86
|ns3| classes that derive from class ns3::Object can include a metadata class
87
called ``TypeId`` that records meta-information about the class, for use in the
88
object aggregation and component manager systems:
90
* a unique string identifying the class
91
* the base class of the subclass, within the metadata system
92
* the set of accessible constructors in the subclass
97
Putting all of these concepts together, let's look at a specific
98
example: class :cpp:class:`ns3::Node`.
100
The public header file node.h has a declaration that includes a static GetTypeId
103
class Node : public Object
106
static TypeId GetTypeId (void);
109
This is defined in the ``node.cc`` file as follows:::
112
Node::GetTypeId (void)
114
static TypeId tid = TypeId ("ns3::Node")
115
.SetParent<Object> ()
116
.AddConstructor<Node> ()
117
.AddAttribute ("DeviceList", "The list of devices associated to this Node.",
118
ObjectVectorValue (),
119
MakeObjectVectorAccessor (&Node::m_devices),
120
MakeObjectVectorChecker<NetDevice> ())
121
.AddAttribute ("ApplicationList", "The list of applications associated to this Node.",
122
ObjectVectorValue (),
123
MakeObjectVectorAccessor (&Node::m_applications),
124
MakeObjectVectorChecker<Application> ())
125
.AddAttribute ("Id", "The id (unique integer) of this Node.",
126
TypeId::ATTR_GET, // allow only getting it.
128
MakeUintegerAccessor (&Node::m_id),
129
MakeUintegerChecker<uint32_t> ())
134
Consider the TypeId of an |ns3| ``Object`` class as an extended form of run time
135
type information (RTTI). The C++ language includes a simple kind of RTTI in
136
order to support ``dynamic_cast`` and ``typeid`` operators.
138
The "``.SetParent<Object> ()``" call in the declaration above is used in
139
conjunction with our object aggregation mechanisms to allow safe up- and
140
down-casting in inheritance trees during ``GetObject``.
142
The "``.AddConstructor<Node> ()``" call is used in conjunction with our abstract
143
object factory mechanisms to allow us to construct C++ objects without forcing a
144
user to know the concrete class of the object she is building.
146
The three calls to "``.AddAttribute``" associate a given string with a strongly
147
typed value in the class. Notice that you must provide a help string which may
148
be displayed, for example, via command line processors. Each ``Attribute`` is
149
associated with mechanisms for accessing the underlying member variable in the
150
object (for example, ``MakeUintegerAccessor`` tells the generic ``Attribute``
151
code how to get to the node ID above). There are also "Checker" methods which
152
are used to validate values.
154
When users want to create Nodes, they will usually call some form of
157
Ptr<Node> n = CreateObject<Node> ();
159
or more abstractly, using an object factory, you can create a ``Node`` object
160
without even knowing the concrete C++ type::
162
ObjectFactory factory;
163
const std::string typeId = "ns3::Node'';
164
factory.SetTypeId (typeId);
165
Ptr<Object> node = factory.Create <Object> ();
167
Both of these methods result in fully initialized attributes being available
168
in the resulting ``Object`` instances.
170
We next discuss how attributes (values associated with member variables or
171
functions of the class) are plumbed into the above TypeId.
176
The goal of the attribute system is to organize the access of
177
internal member objects of a simulation. This goal arises because,
178
typically in simulation, users will cut and paste/modify existing
179
simulation scripts, or will use higher-level simulation constructs,
180
but often will be interested in studying or tracing particular
181
internal variables. For instance, use cases such as:
183
* "I want to trace the packets on the wireless interface only on the first
185
* "I want to trace the value of the TCP congestion window (every time it
186
changes) on a particular TCP socket"
187
* "I want a dump of all values that were used in my simulation."
189
Similarly, users may want fine-grained access to internal variables in the
190
simulation, or may want to broadly change the initial value used for a
191
particular parameter in all subsequently created objects. Finally, users may
192
wish to know what variables are settable and retrievable in a simulation
193
configuration. This is not just for direct simulation interaction on the command
194
line; consider also a (future) graphical user interface that would like to be
195
able to provide a feature whereby a user might right-click on an node on the
196
canvas and see a hierarchical, organized list of parameters that are settable on
197
the node and its constituent member objects, and help text and default values
203
We provide a way for users to access values deep in the system, without having
204
to plumb accessors (pointers) through the system and walk pointer chains to get
205
to them. Consider a class DropTailQueue that has a member variable that is an
206
unsigned integer ``m_maxPackets``; this member variable controls the depth of
209
If we look at the declaration of DropTailQueue, we see the following:::
211
class DropTailQueue : public Queue {
213
static TypeId GetTypeId (void);
217
std::queue<Ptr<Packet> > m_packets;
218
uint32_t m_maxPackets;
221
Let's consider things that a user may want to do with the value of
224
* Set a default value for the system, such that whenever a new DropTailQueue is
225
created, this member is initialized to that default.
226
* Set or get the value on an already instantiated queue.
228
The above things typically require providing Set() and Get() functions, and some
229
type of global default value.
231
In the |ns3| attribute system, these value definitions and accessor functions
232
are moved into the TypeId class; e.g.:::
234
NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);
236
TypeId DropTailQueue::GetTypeId (void)
238
static TypeId tid = TypeId ("ns3::DropTailQueue")
240
.AddConstructor<DropTailQueue> ()
241
.AddAttribute ("MaxPackets",
242
"The maximum number of packets accepted by this DropTailQueue.",
244
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
245
MakeUintegerChecker<uint32_t> ())
251
The AddAttribute() method is performing a number of things with this
254
* Binding the variable m_maxPackets to a string "MaxPackets"
255
* Providing a default value (100 packets)
256
* Providing some help text defining the value
257
* Providing a "checker" (not used in this example) that can be used to set
258
bounds on the allowable range of values
260
The key point is that now the value of this variable and its default value are
261
accessible in the attribute namespace, which is based on strings such as
262
"MaxPackets" and TypeId strings. In the next section, we will provide an example
263
script that shows how users may manipulate these values.
265
Note that initialization of the attribute relies on the macro
266
``NS_OBJECT_ENSURE_REGISTERED`` (DropTailQueue) being called; if you leave this
267
out of your new class implementation, your attributes will not be initialized
270
While we have described how to create attributes, we still haven't described how
271
to access and manage these values. For instance, there is no ``globals.h``
272
header file where these are stored; attributes are stored with their classes.
273
Questions that naturally arise are how do users easily learn about all of the
274
attributes of their models, and how does a user access these attributes, or
275
document their values as part of the record of their simulation?
277
Default values and command-line arguments
278
+++++++++++++++++++++++++++++++++++++++++
280
Let's look at how a user script might access these values.
281
This is based on the script found at ``src/point-to-point/examples/main-attribute-value.cc``,
282
with some details stripped out.::
285
// This is a basic example of how to use the attribute system to
286
// set and get a value in the underlying system; namely, an unsigned
287
// integer of the maximum number of packets in a queue
291
main (int argc, char *argv[])
294
// By default, the MaxPackets attribute has a value of 100 packets
295
// (this default can be observed in the function DropTailQueue::GetTypeId)
297
// Here, we set it to 80 packets. We could use one of two value types:
298
// a string-based value or a Uinteger value
299
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
300
// The below function call is redundant
301
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));
303
// Allow the user to override any of the defaults and the above
304
// SetDefaults() at run-time, via command-line arguments
306
cmd.Parse (argc, argv);
308
The main thing to notice in the above are the two calls to
309
``Config::SetDefault``. This is how we set the default value
310
for all subsequently instantiated DropTailQueues. We illustrate
311
that two types of Value classes, a StringValue and a UintegerValue class,
312
can be used to assign the value to the attribute named by
313
"ns3::DropTailQueue::MaxPackets".
315
Now, we will create a few objects using the low-level API; here,
316
our newly created queues will not have a m_maxPackets initialized to
317
100 packets but to 80 packets, because of what we did above with
320
Ptr<Node> n0 = CreateObject<Node> ();
322
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
323
n0->AddDevice (net0);
325
Ptr<Queue> q = CreateObject<DropTailQueue> ();
328
At this point, we have created a single node (Node 0) and a single
329
PointToPointNetDevice (NetDevice 0) and added a DropTailQueue to it.
331
Now, we can manipulate the MaxPackets value of the already instantiated
332
DropTailQueue. Here are various ways to do that.
337
We assume that a smart pointer (Ptr) to a relevant network device is in hand; in
338
the current example, it is the ``net0`` pointer.
340
One way to change the value is to access a pointer to the underlying queue and
341
modify its attribute.
343
First, we observe that we can get a pointer to the (base class) queue via the
344
PointToPointNetDevice attributes, where it is called TxQueue::
347
net0->GetAttribute ("TxQueue", tmp);
348
Ptr<Object> txQueue = tmp.GetObject ();
350
Using the GetObject function, we can perform a safe downcast to a DropTailQueue,
351
where MaxPackets is a member::
353
Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
354
NS_ASSERT (dtq != 0);
356
Next, we can get the value of an attribute on this queue. We have introduced
357
wrapper "Value" classes for the underlying data types, similar to Java wrappers
358
around these types, since the attribute system stores values and not disparate
359
types. Here, the attribute value is assigned to a UintegerValue, and the Get()
360
method on this value produces the (unwrapped) uint32_t.::
363
dtq->GetAttribute ("MaxPackets", limit);
364
NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
366
Note that the above downcast is not really needed; we could have done the same
367
using the Ptr<Queue> even though the attribute is a member of the subclass::
369
txQueue->GetAttribute ("MaxPackets", limit);
370
NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
372
Now, let's set it to another value (60 packets)::
374
txQueue->SetAttribute("MaxPackets", UintegerValue (60));
375
txQueue->GetAttribute ("MaxPackets", limit);
376
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
378
Namespace-based access
379
++++++++++++++++++++++
381
An alternative way to get at the attribute is to use the configuration
382
namespace. Here, this attribute resides on a known path in this namespace; this
383
approach is useful if one doesn't have access to the underlying pointers and
384
would like to configure a specific attribute with a single statement.::
386
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
387
txQueue->GetAttribute ("MaxPackets", limit);
388
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
389
limit.Get () << " packets");
391
We could have also used wildcards to set this value for all nodes and all net
392
devices (which in this simple example has the same effect as the previous
395
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
396
txQueue->GetAttribute ("MaxPackets", limit);
397
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
398
limit.Get () << " packets");
400
Object Name Service-based access
401
++++++++++++++++++++++++++++++++
403
Another way to get at the attribute is to use the object name service facility.
404
Here, this attribute is found using a name string. This approach is useful if
405
one doesn't have access to the underlying pointers and it is difficult to
406
determine the required concrete configuration namespaced path.::
408
Names::Add ("server", serverNode);
409
Names::Add ("server/eth0", serverDevice);
413
Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
415
:ref:`Object names` for a fuller treatment of the |ns3| configuration namespace.
417
Setting through constructors helper classes
418
+++++++++++++++++++++++++++++++++++++++++++
420
Arbitrary combinations of attributes can be set and fetched from
421
the helper and low-level APIs; either from the constructors themselves:::
423
Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
425
or from the higher-level helper APIs, such as:::
427
mobility.SetPositionAllocator ("GridPositionAllocator",
428
"MinX", DoubleValue (-100.0),
429
"MinY", DoubleValue (-100.0),
430
"DeltaX", DoubleValue (5.0),
431
"DeltaY", DoubleValue (20.0),
432
"GridWidth", UintegerValue (20),
433
"LayoutType", StringValue ("RowFirst"));
435
Implementation details
436
++++++++++++++++++++++
441
Readers will note the new FooValue classes which are subclasses of the
442
AttributeValue base class. These can be thought of as an intermediate class that
443
can be used to convert from raw types to the Values that are used by the
444
attribute system. Recall that this database is holding objects of many types
445
with a single generic type. Conversions to this type can either be done using an
446
intermediate class (IntegerValue, DoubleValue for "floating point") or via
447
strings. Direct implicit conversion of types to Value is not really practical.
448
So in the above, users have a choice of using strings or values:::
450
p->Set ("cwnd", StringValue ("100")); // string-based setter
451
p->Set ("cwnd", IntegerValue (100)); // integer-based setter
453
The system provides some macros that help users declare and define
454
new AttributeValue subclasses for new types that they want to introduce into
455
the attribute system:
457
* ATTRIBUTE_HELPER_HEADER
458
* ATTRIBUTE_HELPER_CPP
463
Attributes in the system must not depend on the state of any other Attribute in
464
this system. This is because an ordering of Attribute initialization is not
465
specified, nor enforced, by the system. A specific example of this can be seen
466
in automated configuration programs such as :cpp:class:`ns3::ConfigStore`.
467
Although a given model may arrange it so that Attributes are initialized in a
468
particular order, another automatic configurator may decide independently to
469
change Attributes in, for example, alphabetic order.
471
Because of this non-specific ordering, no Attribute in the system may have any
472
dependence on any other Attribute. As a corollary, Attribute setters must never
473
fail due to the state of another Attribute. No Attribute setter may change (set)
474
any other Attribute value as a result of changing its value.
476
This is a very strong restriction and there are cases where Attributes must set
477
consistently to allow correct operation. To this end we do allow for consistency
478
checking *when the attribute is used* (cf. NS_ASSERT_MSG or NS_ABORT_MSG).
480
In general, the attribute code to assign values to the underlying class member
481
variables is executed after an object is constructed. But what if you need the
482
values assigned before the constructor body executes, because you need them in
483
the logic of the constructor? There is a way to do this, used for example in the
484
class :cpp:class:`ns3::ConfigStore`: call ``ObjectBase::ConstructSelf ()`` as
487
ConfigStore::ConfigStore ()
489
ObjectBase::ConstructSelf (AttributeList ());
490
// continue on with constructor.
496
The |ns3| system will place a number of internal values under the attribute
497
system, but undoubtedly users will want to extend this to pick up ones we have
498
missed, or to add their own classes to this.
500
Adding an existing internal variable to the metadata system
501
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
503
Consider this variable in class TcpSocket:::
505
uint32_t m_cWnd; // Congestion window
507
Suppose that someone working with TCP wanted to get or set the value of that
508
variable using the metadata system. If it were not already provided by |ns3|,
509
the user could declare the following addition in the runtime metadata system (to
510
the TypeId declaration for TcpSocket):::
512
.AddAttribute ("Congestion window",
513
"Tcp congestion window (bytes)",
515
MakeUintegerAccessor (&TcpSocket::m_cWnd),
516
MakeUintegerChecker<uint16_t> ())
518
Now, the user with a pointer to the TcpSocket can perform operations such as
519
setting and getting the value, without having to add these functions explicitly.
520
Furthermore, access controls can be applied, such as allowing the parameter to
521
be read and not written, or bounds checking on the permissible values can be
527
Here, we discuss the impact on a user who wants to add a new class to |ns3|;
528
what additional things must be done to hook it into this system.
530
We've already introduced what a TypeId definition looks like:::
533
RandomWalk2dMobilityModel::GetTypeId (void)
535
static TypeId tid = TypeId ("ns3::RandomWalk2dMobilityModel")
536
.SetParent<MobilityModel> ()
537
.SetGroupName ("Mobility")
538
.AddConstructor<RandomWalk2dMobilityModel> ()
539
.AddAttribute ("Bounds",
540
"Bounds of the area to cruise.",
541
RectangleValue (Rectangle (0.0, 0.0, 100.0, 100.0)),
542
MakeRectangleAccessor (&RandomWalk2dMobilityModel::m_bounds),
543
MakeRectangleChecker ())
544
.AddAttribute ("Time",
545
"Change current direction and speed after moving for this delay.",
546
TimeValue (Seconds (1.0)),
547
MakeTimeAccessor (&RandomWalk2dMobilityModel::m_modeTime),
549
// etc (more parameters).
554
The declaration for this in the class declaration is one-line public member
558
static TypeId GetTypeId (void);
560
Typical mistakes here involve:
562
* Not calling the SetParent method or calling it with the wrong type
563
* Not calling the AddConstructor method of calling it with the wrong type
564
* Introducing a typographical error in the name of the TypeId in its constructor
565
* Not using the fully-qualified c++ typename of the enclosing c++ class as the
568
None of these mistakes can be detected by the |ns3| codebase so, users
569
are advised to check carefully multiple times that they got these right.
571
Adding new class type to the attribute system
572
*********************************************
574
From the perspective of the user who writes a new class in the system and wants
575
to hook it in to the attribute system, there is mainly the matter of writing the
576
conversions to/from strings and attribute values. Most of this can be
577
copy/pasted with macro-ized code. For instance, consider class declaration for
578
Rectangle in the ``src/mobility/model`` directory:
586
* \brief a 2d rectangle
598
One macro call and two operators, must be added below the class declaration in
599
order to turn a Rectangle into a value usable by the ``Attribute`` system:::
601
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
602
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
604
ATTRIBUTE_HELPER_HEADER (Rectangle);
609
In the class definition (``.cc`` file), the code looks like this:::
611
ATTRIBUTE_HELPER_CPP (Rectangle);
614
operator << (std::ostream &os, const Rectangle &rectangle)
616
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
621
operator >> (std::istream &is, Rectangle &rectangle)
624
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
630
is.setstate (std::ios_base::failbit);
635
These stream operators simply convert from a string representation of the
636
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the modeler
637
must specify these operators and the string syntactical representation of an
638
instance of the new class.
643
The ConfigStore is a specialized database for attribute values and
644
default values. Although it is a separately maintained module in
645
``src/config-store/`` directory, we document it here because of its
646
sole dependency on |ns3| core module and attributes.
648
Values for |ns3| attributes can be stored in an ASCII or XML text file
649
and loaded into a future simulation. This feature is known as the
650
|ns3| ConfigStore. We can explore this system by using an example from
651
``src/config-store/examples/config-store-save.cc``.
653
First, all users must include the following statement:::
655
#include "ns3/config-store-module.h"
657
Next, this program adds a sample object A to show how the system
660
class A : public Object
663
static TypeId GetTypeId (void) {
664
static TypeId tid = TypeId ("ns3::A")
665
.SetParent<Object> ()
666
.AddAttribute ("TestInt16", "help text",
668
MakeIntegerAccessor (&A::m_int16),
669
MakeIntegerChecker<int16_t> ())
676
NS_OBJECT_ENSURE_REGISTERED (A);
678
Next, we use the Config subsystem to override the defaults in a couple of
681
Config::SetDefault ("ns3::A::TestInt16", IntegerValue (-5));
683
Ptr<A> a_obj = CreateObject<A> ();
684
NS_ABORT_MSG_UNLESS (a_obj->m_int16 == -5, "Cannot set A's integer attribute via Config::SetDefault");
686
Ptr<A> a2_obj = CreateObject<A> ();
687
a2_obj->SetAttribute ("TestInt16", IntegerValue (-3));
689
a2_obj->GetAttribute ("TestInt16", iv);
690
NS_ABORT_MSG_UNLESS (iv.Get () == -3, "Cannot set A's integer attribute via SetAttribute");
692
The next statement is necessary to make sure that (one of) the objects
693
created is rooted in the configuration namespace as an object instance.
694
This normally happens when you aggregate objects to ns3::Node or ns3::Channel
695
but here, since we are working at the core level, we need to create a
696
new root namespace object:::
698
Config::RegisterRootNamespaceObject (a2_obj);
700
Next, we want to output the configuration store. The examples show how
701
to do it in two formats, XML and raw text. In practice, one should perform
702
this step just before calling ``Simulator::Run ()``; it will allow the
703
configuration to be saved just before running the simulation.
705
There are three attributes that govern the behavior of the ConfigStore: "Mode",
706
"Filename", and "FileFormat". The Mode (default "None") configures whether
707
|ns3| should load configuration from a previously saved file (specify
708
"Mode=Load") or save it to a file (specify "Mode=Save"). The Filename (default
709
"") is where the ConfigStore should store its output data. The FileFormat
710
(default "RawText") governs whether the ConfigStore format is Xml or RawText
715
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
716
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
717
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
718
ConfigStore outputConfig;
719
outputConfig.ConfigureDefaults ();
720
outputConfig.ConfigureAttributes ();
722
// Output config store to txt format
723
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.txt"));
724
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("RawText"));
725
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
726
ConfigStore outputConfig2;
727
outputConfig2.ConfigureDefaults ();
728
outputConfig2.ConfigureAttributes ();
732
Simulator::Destroy ();
734
After running, you can open the output-attributes.txt file and see:::
736
default ns3::RealtimeSimulatorImpl::SynchronizationMode "BestEffort"
737
default ns3::RealtimeSimulatorImpl::HardLimit "+100000000.0ns"
738
default ns3::PcapFileWrapper::CaptureSize "65535"
739
default ns3::PacketSocket::RcvBufSize "131072"
740
default ns3::ErrorModel::IsEnabled "true"
741
default ns3::RateErrorModel::ErrorUnit "EU_BYTE"
742
default ns3::RateErrorModel::ErrorRate "0"
743
default ns3::RateErrorModel::RanVar "Uniform:0:1"
744
default ns3::DropTailQueue::Mode "Packets"
745
default ns3::DropTailQueue::MaxPackets "100"
746
default ns3::DropTailQueue::MaxBytes "6553500"
747
default ns3::Application::StartTime "+0.0ns"
748
default ns3::Application::StopTime "+0.0ns"
749
default ns3::ConfigStore::Mode "Save"
750
default ns3::ConfigStore::Filename "output-attributes.txt"
751
default ns3::ConfigStore::FileFormat "RawText"
752
default ns3::A::TestInt16 "-5"
755
global SimulatorImplementationType "ns3::DefaultSimulatorImpl"
756
global SchedulerType "ns3::MapScheduler"
757
global ChecksumEnabled "false"
758
value /$ns3::A/TestInt16 "-3"
760
In the above, all of the default values for attributes for the core
761
module are shown. Then, all the values for the |ns3| global values
762
are recorded. Finally, the value of the instance of A that was rooted
763
in the configuration namespace is shown. In a real ns-3 program, many
764
more models, attributes, and defaults would be shown.
766
An XML version also exists in ``output-attributes.xml``:::
768
<?xml version="1.0" encoding="UTF-8"?>
770
<default name="ns3::RealtimeSimulatorImpl::SynchronizationMode" value="BestEffort"/>
771
<default name="ns3::RealtimeSimulatorImpl::HardLimit" value="+100000000.0ns"/>
772
<default name="ns3::PcapFileWrapper::CaptureSize" value="65535"/>
773
<default name="ns3::PacketSocket::RcvBufSize" value="131072"/>
774
<default name="ns3::ErrorModel::IsEnabled" value="true"/>
775
<default name="ns3::RateErrorModel::ErrorUnit" value="EU_BYTE"/>
776
<default name="ns3::RateErrorModel::ErrorRate" value="0"/>
777
<default name="ns3::RateErrorModel::RanVar" value="Uniform:0:1"/>
778
<default name="ns3::DropTailQueue::Mode" value="Packets"/>
779
<default name="ns3::DropTailQueue::MaxPackets" value="100"/>
780
<default name="ns3::DropTailQueue::MaxBytes" value="6553500"/>
781
<default name="ns3::Application::StartTime" value="+0.0ns"/>
782
<default name="ns3::Application::StopTime" value="+0.0ns"/>
783
<default name="ns3::ConfigStore::Mode" value="Save"/>
784
<default name="ns3::ConfigStore::Filename" value="output-attributes.xml"/>
785
<default name="ns3::ConfigStore::FileFormat" value="Xml"/>
786
<default name="ns3::A::TestInt16" value="-5"/>
787
<global name="RngSeed" value="1"/>
788
<global name="RngRun" value="1"/>
789
<global name="SimulatorImplementationType" value="ns3::DefaultSimulatorImpl"/>
790
<global name="SchedulerType" value="ns3::MapScheduler"/>
791
<global name="ChecksumEnabled" value="false"/>
792
<value path="/$ns3::A/TestInt16" value="-3"/>
795
This file can be archived with your simulation script and output data.
797
While it is possible to generate a sample config file and lightly edit it to
798
change a couple of values, there are cases where this process will not work
799
because the same value on the same object can appear multiple times in the same
800
automatically-generated configuration file under different configuration paths.
802
As such, the best way to use this class is to use it to generate an initial
803
configuration file, extract from that configuration file only the strictly
804
necessary elements, and move these minimal elements to a new configuration file
805
which can then safely be edited and loaded in a subsequent simulation run.
807
When the ConfigStore object is instantiated, its attributes Filename, Mode, and
808
FileFormat must be set, either via command-line or via program statements.
810
As a more complicated example, let's assume that we want to read in a
811
configuration of defaults from an input file named "input-defaults.xml", and
812
write out the resulting attributes to a separate file called
813
"output-attributes.xml". (Note-- to get this input xml file to begin with, it
814
is sometimes helpful to run the program to generate an output xml file first,
815
then hand-edit that file and re-input it for the next simulation run).::
817
#include "ns3/config-store-module.h"
822
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
823
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
824
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
825
ConfigStore inputConfig;
826
inputConfig.ConfigureDefaults ();
829
// Allow the user to override any of the defaults and the above Bind() at
830
// run-time, via command-line arguments
833
cmd.Parse (argc, argv);
838
// Invoke just before entering Simulator::Run ()
839
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
840
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
841
ConfigStore outputConfig;
842
outputConfig.ConfigureAttributes ();
846
GTK-based ConfigStore
847
+++++++++++++++++++++
849
There is a GTK-based front end for the ConfigStore. This allows users to use a
850
GUI to access and change variables. Screenshots of this feature are available
851
in the `|ns3| Overview <http://www.nsnam.org/docs/ns-3-overview.pdf>`_
854
To use this feature, one must install libgtk and libgtk-dev; an example
855
Ubuntu installation command is:::
857
sudo apt-get install libgtk2.0-0 libgtk2.0-dev
859
To check whether it is configured or not, check the output of the step:::
860
./waf configure --enable-examples --enable-tests
862
---- Summary of optional NS-3 features:
863
Threading Primitives : enabled
864
Real Time Simulator : enabled
865
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
867
In the above example, it was not enabled, so it cannot be used until a suitable
868
version is installed and ./waf configure --enable-examples --enable-tests; ./waf is rerun.
870
Usage is almost the same as the non-GTK-based version, but there
871
are no ConfigStore attributes involved:::
873
// Invoke just before entering Simulator::Run ()
874
GtkConfigStore config;
875
config.ConfigureDefaults ();
876
config.ConfigureAttributes ();
878
Now, when you run the script, a GUI should pop up, allowing you to open menus of
879
attributes on different nodes/objects, and then launch the simulation execution
884
There are a couple of possible improvements:
885
* save a unique version number with date and time at start of file
886
* save rng initial seed somewhere.
887
* make each RandomVariable serialize its own initial seed and re-read it later