~ubuntu-branches/ubuntu/quantal/ns3/quantal

« back to all changes in this revision

Viewing changes to .pc/manual-man-error.diff/ns-3.13/doc/manual/source/attributes.rst

  • Committer: Package Import Robot
  • Author(s): YunQiang Su, Aron Xu, YunQiang Su, Upstream
  • Date: 2012-01-06 00:35:42 UTC
  • mfrom: (10.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20120106003542-vcn5g03mhapm991h
Tags: 3.13+dfsg-1
[ Aron Xu ]:
        add tag binary and binary-indep, 
  for not build doc when --binary-arch (Closes: #654493).
[ YunQiang Su ]
        add waf 1.5/1.6 source to debian directory, 
  and build waf from there (Closes: #642217).
[ Upstream ]
  Successfully link with --as-needed option (Closes: #642225).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
.. include:: replace.txt
 
2
 
 
3
Attributes
 
4
----------
 
5
 
 
6
In |ns3| simulations, there are two main aspects to configuration:
 
7
 
 
8
* the simulation topology and how objects are connected 
 
9
* the values used by the models instantiated in the topology
 
10
 
 
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. 
 
15
 
 
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`.
 
18
 
 
19
Object Overview
 
20
***************
 
21
 
 
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.
 
24
 
 
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:
 
28
 
 
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
 
32
  subclass
 
33
* a reference counting smart pointer implementation, for memory management.
 
34
 
 
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`.
 
40
 
 
41
Let's review a couple of properties of these objects.
 
42
 
 
43
Smart pointers
 
44
**************
 
45
 
 
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`. 
 
49
 
 
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:::
 
53
 
 
54
  Ptr<WifiNetDevice> nd = ...;
 
55
  nd->CallSomeFunction ();
 
56
  // etc.
 
57
 
 
58
CreateObject
 
59
++++++++++++
 
60
 
 
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()`.
 
65
 
 
66
A typical way to create such an object is as follows:::
 
67
 
 
68
  Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
 
69
 
 
70
You can think of this as being functionally equivalent to:::
 
71
 
 
72
  WifiNetDevice* nd = new WifiNetDevice ();
 
73
 
 
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
 
77
stack.  
 
78
 
 
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.
 
82
 
 
83
TypeId
 
84
++++++
 
85
 
 
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:
 
89
 
 
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
 
93
 
 
94
Object Summary
 
95
++++++++++++++
 
96
 
 
97
Putting all of these concepts together, let's look at a specific
 
98
example: class :cpp:class:`ns3::Node`.
 
99
 
 
100
The public header file node.h has a declaration that includes a static GetTypeId
 
101
function call:::
 
102
 
 
103
    class Node : public Object
 
104
    {
 
105
    public:
 
106
      static TypeId GetTypeId (void);
 
107
      ...
 
108
 
 
109
This is defined in the ``node.cc`` file as follows:::
 
110
 
 
111
    TypeId 
 
112
    Node::GetTypeId (void)
 
113
    {
 
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.
 
127
                       UintegerValue (0),
 
128
                       MakeUintegerAccessor (&Node::m_id),
 
129
                       MakeUintegerChecker<uint32_t> ())
 
130
        ;
 
131
      return tid;
 
132
    }
 
133
 
 
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.
 
137
 
 
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``.
 
141
 
 
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.
 
145
 
 
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.
 
153
 
 
154
When users want to create Nodes, they will usually call some form of 
 
155
``CreateObject``,::
 
156
 
 
157
    Ptr<Node> n = CreateObject<Node> ();
 
158
 
 
159
or more abstractly, using an object factory, you can create a ``Node`` object
 
160
without even knowing the concrete C++ type::
 
161
 
 
162
    ObjectFactory factory;
 
163
    const std::string typeId = "ns3::Node'';
 
164
    factory.SetTypeId (typeId);
 
165
    Ptr<Object> node = factory.Create <Object> ();
 
166
 
 
167
Both of these methods result in fully initialized attributes being available 
 
168
in the resulting ``Object`` instances.
 
169
 
 
170
We next discuss how attributes (values associated with member variables or
 
171
functions of the class) are plumbed into the above TypeId.
 
172
 
 
173
Attribute Overview
 
174
******************
 
175
 
 
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:
 
182
 
 
183
* "I want to trace the packets on the wireless interface only on the first
 
184
  access point"
 
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."
 
188
 
 
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
 
198
for each parameter.
 
199
 
 
200
Functional overview
 
201
+++++++++++++++++++
 
202
 
 
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
 
207
the queue.  
 
208
 
 
209
If we look at the declaration of DropTailQueue, we see the following:::
 
210
 
 
211
    class DropTailQueue : public Queue {
 
212
    public:
 
213
      static TypeId GetTypeId (void);
 
214
      ...
 
215
 
 
216
    private:
 
217
      std::queue<Ptr<Packet> > m_packets;
 
218
      uint32_t m_maxPackets;
 
219
    };
 
220
 
 
221
Let's consider things that a user may want to do with the value of
 
222
m_maxPackets:
 
223
 
 
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.
 
227
 
 
228
The above things typically require providing Set() and Get() functions, and some
 
229
type of global default value.
 
230
 
 
231
In the |ns3| attribute system, these value definitions and accessor functions
 
232
are moved into the TypeId class; e.g.:::
 
233
 
 
234
    NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);
 
235
 
 
236
    TypeId DropTailQueue::GetTypeId (void) 
 
237
    {
 
238
      static TypeId tid = TypeId ("ns3::DropTailQueue")
 
239
        .SetParent<Queue> ()
 
240
        .AddConstructor<DropTailQueue> ()
 
241
        .AddAttribute ("MaxPackets", 
 
242
                       "The maximum number of packets accepted by this DropTailQueue.",
 
243
                       UintegerValue (100),
 
244
                       MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
 
245
                       MakeUintegerChecker<uint32_t> ())
 
246
        ;
 
247
      
 
248
      return tid;
 
249
    }
 
250
 
 
251
The AddAttribute() method is performing a number of things with this
 
252
value:
 
253
 
 
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
 
259
 
 
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.
 
264
 
 
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
 
268
correctly.
 
269
 
 
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?
 
276
 
 
277
Default values and command-line arguments
 
278
+++++++++++++++++++++++++++++++++++++++++
 
279
 
 
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.::
 
283
 
 
284
    //
 
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
 
288
    //
 
289
 
 
290
    int 
 
291
    main (int argc, char *argv[])
 
292
    {
 
293
 
 
294
      // By default, the MaxPackets attribute has a value of 100 packets
 
295
      // (this default can be observed in the function DropTailQueue::GetTypeId)
 
296
      // 
 
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));
 
302
 
 
303
      // Allow the user to override any of the defaults and the above
 
304
      // SetDefaults() at run-time, via command-line arguments
 
305
      CommandLine cmd;
 
306
      cmd.Parse (argc, argv);
 
307
 
 
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".
 
314
 
 
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
 
318
default values.::
 
319
 
 
320
    Ptr<Node> n0 = CreateObject<Node> ();
 
321
 
 
322
    Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
 
323
    n0->AddDevice (net0);
 
324
 
 
325
    Ptr<Queue> q = CreateObject<DropTailQueue> ();
 
326
    net0->AddQueue(q);
 
327
 
 
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.
 
330
 
 
331
Now, we can manipulate the MaxPackets value of the already instantiated
 
332
DropTailQueue. Here are various ways to do that.
 
333
 
 
334
Pointer-based access
 
335
++++++++++++++++++++
 
336
 
 
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. 
 
339
 
 
340
One way to change the value is to access a pointer to the underlying queue and
 
341
modify its attribute.
 
342
 
 
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::
 
345
 
 
346
    PointerValue tmp;
 
347
    net0->GetAttribute ("TxQueue", tmp);
 
348
    Ptr<Object> txQueue = tmp.GetObject ();
 
349
 
 
350
Using the GetObject function, we can perform a safe downcast to a DropTailQueue,
 
351
where MaxPackets is a member::
 
352
 
 
353
    Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
 
354
    NS_ASSERT (dtq != 0);
 
355
 
 
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.::
 
361
 
 
362
    UintegerValue limit;
 
363
    dtq->GetAttribute ("MaxPackets", limit);
 
364
    NS_LOG_INFO ("1.  dtq limit: " << limit.Get () << " packets");
 
365
  
 
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::
 
368
 
 
369
    txQueue->GetAttribute ("MaxPackets", limit);
 
370
    NS_LOG_INFO ("2.  txQueue limit: " << limit.Get () << " packets");
 
371
 
 
372
Now, let's set it to another value (60 packets)::
 
373
 
 
374
    txQueue->SetAttribute("MaxPackets", UintegerValue (60));
 
375
    txQueue->GetAttribute ("MaxPackets", limit);
 
376
    NS_LOG_INFO ("3.  txQueue limit changed: " << limit.Get () << " packets");
 
377
 
 
378
Namespace-based access
 
379
++++++++++++++++++++++
 
380
 
 
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.::
 
385
 
 
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");
 
390
 
 
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
 
393
Set())::
 
394
 
 
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");
 
399
 
 
400
Object Name Service-based access
 
401
++++++++++++++++++++++++++++++++
 
402
 
 
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.::
 
407
 
 
408
    Names::Add ("server", serverNode);
 
409
    Names::Add ("server/eth0", serverDevice);
 
410
 
 
411
    ...
 
412
 
 
413
    Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
 
414
 
 
415
:ref:`Object names` for a fuller treatment of the |ns3| configuration namespace.
 
416
 
 
417
Setting through constructors helper classes
 
418
+++++++++++++++++++++++++++++++++++++++++++
 
419
 
 
420
Arbitrary combinations of attributes can be set and fetched from
 
421
the helper and low-level APIs; either from the constructors themselves:::
 
422
 
 
423
    Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
 
424
 
 
425
or from the higher-level helper APIs, such as:::
 
426
 
 
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"));
 
434
 
 
435
Implementation details
 
436
++++++++++++++++++++++
 
437
 
 
438
Value classes
 
439
~~~~~~~~~~~~~
 
440
 
 
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:::
 
449
 
 
450
    p->Set ("cwnd", StringValue ("100")); // string-based setter
 
451
    p->Set ("cwnd", IntegerValue (100)); // integer-based setter
 
452
 
 
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: 
 
456
 
 
457
* ATTRIBUTE_HELPER_HEADER
 
458
* ATTRIBUTE_HELPER_CPP
 
459
 
 
460
Initialization order
 
461
~~~~~~~~~~~~~~~~~~~~
 
462
 
 
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.  
 
470
 
 
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.
 
475
 
 
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).
 
479
 
 
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
 
485
follows:::
 
486
 
 
487
    ConfigStore::ConfigStore ()
 
488
    {
 
489
      ObjectBase::ConstructSelf (AttributeList ());
 
490
      // continue on with constructor.
 
491
    }
 
492
 
 
493
Extending attributes
 
494
********************
 
495
 
 
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.
 
499
 
 
500
Adding an existing internal variable to the metadata system 
 
501
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
502
 
 
503
Consider this variable in class TcpSocket:::
 
504
 
 
505
    uint32_t m_cWnd;   // Congestion window
 
506
 
 
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):::
 
511
 
 
512
    .AddAttribute ("Congestion window", 
 
513
                   "Tcp congestion window (bytes)",
 
514
                   UintegerValue (1),
 
515
                   MakeUintegerAccessor (&TcpSocket::m_cWnd),
 
516
                   MakeUintegerChecker<uint16_t> ())
 
517
 
 
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
 
522
applied.
 
523
 
 
524
Adding a new TypeId
 
525
+++++++++++++++++++
 
526
 
 
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.
 
529
 
 
530
We've already introduced what a TypeId definition looks like:::
 
531
 
 
532
    TypeId
 
533
    RandomWalk2dMobilityModel::GetTypeId (void)
 
534
    {
 
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),
 
548
                       MakeTimeChecker ())
 
549
        // etc (more parameters).
 
550
        ;
 
551
      return tid;
 
552
    }
 
553
 
 
554
The declaration for this in the class declaration is one-line public member
 
555
method:::
 
556
 
 
557
    public:
 
558
      static TypeId GetTypeId (void);
 
559
 
 
560
Typical mistakes here involve:
 
561
 
 
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
 
566
  name of the TypeId
 
567
 
 
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.
 
570
 
 
571
Adding new class type to the attribute system
 
572
*********************************************
 
573
 
 
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:
 
579
 
 
580
Header file
 
581
+++++++++++
 
582
 
 
583
::
 
584
 
 
585
    /**
 
586
     * \brief a 2d rectangle
 
587
     */
 
588
    class Rectangle
 
589
    {
 
590
      ...
 
591
 
 
592
      double xMin;
 
593
      double xMax;
 
594
      double yMin;
 
595
      double yMax;
 
596
    };
 
597
 
 
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:::
 
600
 
 
601
    std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
 
602
    std::istream &operator >> (std::istream &is, Rectangle &rectangle);
 
603
 
 
604
    ATTRIBUTE_HELPER_HEADER (Rectangle);
 
605
 
 
606
Implementation file
 
607
+++++++++++++++++++
 
608
 
 
609
In the class definition (``.cc`` file), the code looks like this:::
 
610
 
 
611
    ATTRIBUTE_HELPER_CPP (Rectangle);
 
612
 
 
613
    std::ostream &
 
614
    operator << (std::ostream &os, const Rectangle &rectangle)
 
615
    {
 
616
      os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
 
617
         << rectangle.yMax;
 
618
      return os;
 
619
    }
 
620
    std::istream &
 
621
    operator >> (std::istream &is, Rectangle &rectangle)
 
622
     {
 
623
      char c1, c2, c3;
 
624
      is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 
 
625
         >> rectangle.yMax;
 
626
      if (c1 != '|' ||
 
627
          c2 != '|' ||
 
628
          c3 != '|')
 
629
        {
 
630
          is.setstate (std::ios_base::failbit);
 
631
        }
 
632
      return is;
 
633
    }
 
634
 
 
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.
 
639
 
 
640
ConfigStore
 
641
***********
 
642
 
 
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.
 
647
 
 
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``.
 
652
 
 
653
First, all users must include the following statement:::
 
654
 
 
655
    #include "ns3/config-store-module.h"
 
656
 
 
657
Next, this program adds a sample object A to show how the system
 
658
is extended:::
 
659
 
 
660
    class A : public Object
 
661
    {
 
662
    public:
 
663
      static TypeId GetTypeId (void) {
 
664
        static TypeId tid = TypeId ("ns3::A")
 
665
          .SetParent<Object> ()
 
666
          .AddAttribute ("TestInt16", "help text",
 
667
                         IntegerValue (-2),
 
668
                         MakeIntegerAccessor (&A::m_int16),
 
669
                         MakeIntegerChecker<int16_t> ())
 
670
          ;
 
671
          return tid;
 
672
        }
 
673
      int16_t m_int16;
 
674
    };
 
675
    
 
676
    NS_OBJECT_ENSURE_REGISTERED (A);
 
677
 
 
678
Next, we use the Config subsystem to override the defaults in a couple of
 
679
ways:::
 
680
     
 
681
      Config::SetDefault ("ns3::A::TestInt16", IntegerValue (-5));
 
682
    
 
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");
 
685
    
 
686
      Ptr<A> a2_obj = CreateObject<A> ();
 
687
      a2_obj->SetAttribute ("TestInt16", IntegerValue (-3));
 
688
      IntegerValue iv;
 
689
      a2_obj->GetAttribute ("TestInt16", iv);
 
690
      NS_ABORT_MSG_UNLESS (iv.Get () == -3, "Cannot set A's integer attribute via SetAttribute");
 
691
    
 
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:::
 
697
 
 
698
      Config::RegisterRootNamespaceObject (a2_obj);
 
699
 
 
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.
 
704
 
 
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
 
711
format.
 
712
 
 
713
The example shows:::
 
714
 
 
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 ();
 
721
    
 
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 ();
 
729
    
 
730
      Simulator::Run ();
 
731
    
 
732
      Simulator::Destroy ();
 
733
    
 
734
After running, you can open the output-attributes.txt file and see:::
 
735
 
 
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"
 
753
    global RngSeed "1"
 
754
    global RngRun "1"
 
755
    global SimulatorImplementationType "ns3::DefaultSimulatorImpl"
 
756
    global SchedulerType "ns3::MapScheduler"
 
757
    global ChecksumEnabled "false"
 
758
    value /$ns3::A/TestInt16 "-3"
 
759
 
 
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.
 
765
 
 
766
An XML version also exists in ``output-attributes.xml``:::
 
767
 
 
768
    <?xml version="1.0" encoding="UTF-8"?>
 
769
    <ns3>
 
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"/>
 
793
    </ns3>
 
794
    
 
795
This file can be archived with your simulation script and output data.
 
796
 
 
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.
 
801
 
 
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. 
 
806
 
 
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.  
 
809
 
 
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).::
 
816
 
 
817
    #include "ns3/config-store-module.h"
 
818
    ...
 
819
    int main (...)
 
820
    {
 
821
 
 
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 ();
 
827
      
 
828
      //
 
829
      // Allow the user to override any of the defaults and the above Bind() at
 
830
      // run-time, via command-line arguments
 
831
      //
 
832
      CommandLine cmd;
 
833
      cmd.Parse (argc, argv);
 
834
 
 
835
      // setup topology
 
836
      ...
 
837
 
 
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 ();
 
843
      Simulator::Run ();
 
844
    }
 
845
 
 
846
GTK-based ConfigStore
 
847
+++++++++++++++++++++
 
848
 
 
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>`_
 
852
presentation.
 
853
 
 
854
To use this feature, one must install libgtk and libgtk-dev; an example
 
855
Ubuntu installation command is:::
 
856
 
 
857
    sudo apt-get install libgtk2.0-0 libgtk2.0-dev
 
858
 
 
859
To check whether it is configured or not, check the output of the step:::
 
860
./waf configure --enable-examples --enable-tests 
 
861
 
 
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)
 
866
 
 
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.
 
869
 
 
870
Usage is almost the same as the non-GTK-based version, but there
 
871
are no ConfigStore attributes involved:::
 
872
 
 
873
  // Invoke just before entering Simulator::Run ()
 
874
  GtkConfigStore config;
 
875
  config.ConfigureDefaults ();
 
876
  config.ConfigureAttributes ();
 
877
 
 
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
 
880
when you are done.  
 
881
 
 
882
Future work
 
883
+++++++++++
 
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