3 @anchor{chap:Attributes}
8 * Extending attributes::
9 * Adding new class type::
14 In ns-3 simulations, there are two main aspects to configuration:
16 @item the simulation topology and how objects are connected
17 @item the values used by the models instantiated in the topology
20 This chapter focuses on the second item above: how the many values
21 in use in ns-3 are organized, documented, and modifiable by ns-3 users.
22 The ns-3 attribute system is also the underpinning of how traces
23 and statistics are gathered in the simulator.
25 Before delving into details of the attribute value system,
26 it will help to review some basic properties of @code{class ns3::Object}.
29 @section Object Overview
31 ns-3 is fundamentally a C++ object-based system. By this we mean that
32 new C++ classes (types) can be declared, defined, and subclassed
35 Many ns-3 objects inherit from the @code{ns3::Object} base class. These
36 objects have some additional properties that we exploit for
37 organizing the system and improving the memory management
41 @item a "metadata" system that links the class name to a lot of
42 meta-information about the object, including the base class of the subclass,
43 the set of accessible constructors in the subclass, and the set of
44 "attributes" of the subclass
45 @item a reference counting smart pointer implementation, for memory
49 ns-3 objects that use the attribute system derive from either
50 @code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects
51 we will discuss derive from @code{ns3::Object}, but a few that
52 are outside the smart pointer memory management framework derive
53 from @code{ns3::ObjectBase}.
55 Let's review a couple of properties of these objects.
57 @subsection Smart pointers
59 As introduced in the ns-3 tutorial, ns-3 objects are memory managed by a
60 @uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}.
62 Smart pointers are used extensively in the ns-3 APIs, to avoid passing
63 references to heap-allocated objects that may cause memory leaks.
64 For most basic usage (syntax), treat a smart pointer like a regular pointer:
66 Ptr<WifiNetDevice> nd = ...;
67 nd->CallSomeFunction ();
71 @subsection CreateObject
73 As we discussed above in @ref{Memory management and class Ptr},
74 at the lowest-level API, objects of type @code{ns3::Object} are
75 not instantiated using @code{operator new} as usual but instead by
76 a templated function called @code{CreateObject()}.
78 A typical way to create such an object is as follows:
80 Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
83 You can think of this as being functionally equivalent to:
85 WifiNetDevice* nd = new WifiNetDevice ();
88 Objects that derive from @code{ns3::Object} must be allocated
89 on the heap using CreateObject(). Those deriving from
90 @code{ns3::ObjectBase}, such as ns-3 helper functions and packet
91 headers and trailers, can be allocated on the stack.
93 In some scripts, you may not see a lot of CreateObject() calls
95 this is because there are some helper objects in effect that
96 are doing the CreateObject()s for you.
100 ns-3 classes that derive from class ns3::Object can include
101 a metadata class called @code{TypeId} that records meta-information
102 about the class, for use in the object aggregation and component
105 @item a unique string identifying the class
106 @item the base class of the subclass, within the metadata system
107 @item the set of accessible constructors in the subclass
110 @subsection Object Summary
112 Putting all of these concepts together, let's look at a specific
113 example: @code{class ns3::Node}.
115 The public header file node.h has a declaration that includes
116 a static GetTypeId function call:
119 class Node : public Object
122 static TypeId GetTypeId (void);
126 This is defined in the node.cc file as follows:
130 Node::GetTypeId (void)
132 static TypeId tid = TypeId ("ns3::Node")
133 .SetParent<Object> ()
134 .AddConstructor<Node> ()
135 .AddAttribute ("DeviceList", "The list of devices associated to this Node.",
136 ObjectVectorValue (),
137 MakeObjectVectorAccessor (&Node::m_devices),
138 MakeObjectVectorChecker<NetDevice> ())
139 .AddAttribute ("ApplicationList", "The list of applications associated to this Node.",
140 ObjectVectorValue (),
141 MakeObjectVectorAccessor (&Node::m_applications),
142 MakeObjectVectorChecker<Application> ())
143 .AddAttribute ("Id", "The id (unique integer) of this Node.",
144 TypeId::ATTR_GET, // allow only getting it.
146 MakeUintegerAccessor (&Node::m_id),
147 MakeUintegerChecker<uint32_t> ())
153 Look at the TypeId of an ns-3 @code{Object} class as an extended form of run
154 time type information (RTTI). The C++ language includes simple kind of RTTI
155 in order to support @code{dynamic_cast} and @code{typeid} operators.
157 The ``@code{.SetParent<Object> ()}'' call in the declaration above is used in
158 conjunction with our object aggregation mechanisms to allow safe up- and
159 down-casing in inheritance trees during @code{GetObject}.
161 The ``@code{.AddConstructor<Node> ()}'' call is used in conjunction with our
162 abstract object factory mechanisms to allow us to construct C++ objects without
163 forcing a user to know the concrete class of the object she is building.
165 The three calls to ``@code{.AddAttribute}'' associate a given string with a
166 strongly typed value in the class. Notice that you must provide a help string
167 which may be displayed, for example, via command line processors. Each
168 @code{Attribute} is associated with mechanisms for accessing the underlying
169 member variable in the object (for example, @code{MakeUintegerAccessor} tells
170 the generic @code{Attribute} code how to get to the node ID above). There are
171 also ``Checker'' methods which are used to validate values.
173 When users want to create Nodes, they will usually call some form of
177 Ptr<Node> n = CreateObject<Node> ();
180 or more abstractly, using an object factory, you can create a @code{Node} object
181 without even knowing the concrete C++ type
184 ObjectFactory factory;
185 const std::string typeId = "ns3::Node'';
186 factory.SetTypeId(typeId);
187 Ptr<Object> node = factory.Create <Object> ();
190 Both of these methods result in fully initialized attributes being available
191 in the resulting @code{Object} instances.
193 We next discuss how attributes (values associated with member variables
194 or functions of the class) are plumbed into the above TypeId.
196 @node Attribute Overview
197 @section Attribute Overview
199 The goal of the attribute system is to organize the access of
200 internal member objects of a simulation. This goal arises because,
201 typically in simulation, users will cut and paste/modify existing
202 simulation scripts, or will use higher-level simulation constructs,
203 but often will be interested in studying or tracing particular
204 internal variables. For instance, use cases such as:
206 @item "I want to trace the packets on the wireless interface only on
207 the first access point"
208 @item "I want to trace the value of the TCP congestion window (every
209 time it changes) on a particular TCP socket"
210 @item "I want a dump of all values that were used in my simulation."
213 Similarly, users may want fine-grained access to internal
214 variables in the simulation, or may want to broadly change the
215 initial value used for a particular parameter in all subsequently
216 created objects. Finally, users may wish to know what variables
217 are settable and retrievable in a simulation configuration. This
218 is not just for direct simulation interaction on the command line;
219 consider also a (future) graphical user interface
220 that would like to be able to provide a feature whereby a user
221 might right-click on an node on the canvas and see a hierarchical,
222 organized list of parameters that are settable on the node and its
223 constituent member objects, and help text and default values for
226 @subsection Functional overview
228 We provide a way for users to access values deep in the system, without
229 having to plumb accessors (pointers) through the system and walk
230 pointer chains to get to them. Consider a class DropTailQueue that
231 has a member variable that is an unsigned integer @code{m_maxPackets};
232 this member variable controls the depth of the queue.
234 If we look at the declaration of DropTailQueue, we see the following:
236 class DropTailQueue : public Queue {
238 static TypeId GetTypeId (void);
242 std::queue<Ptr<Packet> > m_packets;
243 uint32_t m_maxPackets;
247 Let's consider things that a user may want to do with the value of
251 @item Set a default value for the system, such that whenever a new
252 DropTailQueue is created, this member is initialized to that default.
253 @item Set or get the value on an already instantiated queue.
256 The above things typically require providing Set() and Get() functions,
257 and some type of global default value.
259 In the ns-3 attribute system, these value definitions and accessor
260 functions are moved into the TypeId class; e.g.:
263 NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);
265 TypeId DropTailQueue::GetTypeId (void)
267 static TypeId tid = TypeId ("ns3::DropTailQueue")
269 .AddConstructor<DropTailQueue> ()
270 .AddAttribute ("MaxPackets",
271 "The maximum number of packets accepted by this DropTailQueue.",
273 MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
274 MakeUintegerChecker<uint32_t> ())
281 The AddAttribute() method is performing a number of things with this
284 @item Binding the variable m_maxPackets to a string "MaxPackets"
285 @item Providing a default value (100 packets)
286 @item Providing some help text defining the value
287 @item Providing a "checker" (not used in this example) that can be used to set
288 bounds on the allowable range of values
291 The key point is that now the value of this variable and its default
292 value are accessible in the attribute namespace, which is based on
293 strings such as "MaxPackets" and TypeId strings. In the next
294 section, we will provide an example script that shows how users
295 may manipulate these values.
297 Note that initialization of the attribute relies on the macro
298 NS_OBJECT_ENSURE_REGISTERED (DropTailQueue) being called; if you leave
299 this out of your new class implementation, your attributes will not be
300 initialized corretly.
302 @subsection Basic usage
304 Let's look at how a user script might access these values.
305 This is based on the script found at @code{samples/main-attribute-value.cc},
306 with some details stripped out.
309 // This is a basic example of how to use the attribute system to
310 // set and get a value in the underlying system; namely, an unsigned
311 // integer of the maximum number of packets in a queue
315 main (int argc, char *argv[])
318 // By default, the MaxPackets attribute has a value of 100 packets
319 // (this default can be observed in the function DropTailQueue::GetTypeId)
321 // Here, we set it to 80 packets. We could use one of two value types:
322 // a string-based value or a Uinteger value
323 Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
324 // The below function call is redundant
325 Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));
327 // Allow the user to override any of the defaults and the above
328 // SetDefaults() at run-time, via command-line arguments
330 cmd.Parse (argc, argv);
333 The main thing to notice in the above are the two calls to
334 @code{Config::SetDefault}. This is how we set the default value
335 for all subsequently instantiated DropTailQueues. We illustrate
336 that two types of Value classes, a StringValue and a UintegerValue class,
337 can be used to assign the value to the attribute named by
338 "ns3::DropTailQueue::MaxPackets".
340 Now, we will create a few objects using the low-level API; here,
341 our newly created queues will not have a m_maxPackets initialized to
342 100 packets but to 80 packets, because of what we did above with
345 Ptr<Node> n0 = CreateObject<Node> ();
347 Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
348 n0->AddDevice (net0);
350 Ptr<Queue> q = CreateObject<DropTailQueue> ();
354 At this point, we have created a single node (Node 0) and a
355 single PointToPointNetDevice (NetDevice 0) and added a
358 Now, we can manipulate the MaxPackets value of the already
359 instantiated DropTailQueue. Here are various ways to do that.
361 @subsubsection Pointer-based access
363 We assume that a smart pointer (Ptr) to a relevant network device is
364 in hand; here, it is the net0 pointer.
366 One way to change the value is to access a pointer to the
367 underlying queue and modify its attribute.
369 First, we observe that we can get a pointer to the (base class)
370 queue via the PointToPointNetDevice attributes, where it is called
374 net0->GetAttribute ("TxQueue", tmp);
375 Ptr<Object> txQueue = tmp.GetObject ();
378 Using the GetObject function, we can perform a safe downcast
379 to a DropTailQueue, where MaxPackets is a member
381 Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
382 NS_ASSERT (dtq != 0);
385 Next, we can get the value of an attribute on this queue.
386 We have introduced wrapper "Value" classes for the underlying
387 data types, similar to Java wrappers around these types, since
388 the attribute system stores values and not disparate types.
389 Here, the attribute value is assigned to a UintegerValue, and
390 the Get() method on this value produces the (unwrapped) uint32_t.
393 dtq->GetAttribute ("MaxPackets", limit);
394 NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
397 Note that the above downcast is not really needed; we could have
398 done the same using the Ptr<Queue> even though the attribute
399 is a member of the subclass
401 txQueue->GetAttribute ("MaxPackets", limit);
402 NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
405 Now, let's set it to another value (60 packets)
407 txQueue->SetAttribute("MaxPackets", UintegerValue (60));
408 txQueue->GetAttribute ("MaxPackets", limit);
409 NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
412 @subsubsection Namespace-based access
414 An alternative way to get at the attribute is to use the configuration namespace.
415 Here, this attribute resides on a known path in this namespace; this approach
416 is useful if one doesn't have access to the underlying pointers and would like
417 to configure a specific attribute with a single statement.
420 Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
421 txQueue->GetAttribute ("MaxPackets", limit);
422 NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
423 limit.Get () << " packets");
426 We could have also used wildcards to set this value for all nodes and all net
427 devices (which in this simple example has the same effect as the previous Set())
429 Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
430 txQueue->GetAttribute ("MaxPackets", limit);
431 NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
432 limit.Get () << " packets");
435 @subsubsection Object Name Service-based access
437 Another way to get at the attribute is to use the object name service facility.
438 Here, this attribute is found using a name string. This approach is useful if
439 one doesn't have access to the underlying pointers and it is difficult to
440 determine the required concrete configuration namespaced path.
443 Names::Add ("server", serverNode);
444 Names::Add ("server/eth0", serverDevice);
448 Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
451 @subsection Setting through constructors helper classes
453 Arbitrary combinations of attributes can be set and fetched from
454 the helper and low-level APIs; either from the constructors themselves:
456 Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
458 or from the higher-level helper APIs, such as:
460 mobility.SetPositionAllocator ("GridPositionAllocator",
461 "MinX", DoubleValue (-100.0),
462 "MinY", DoubleValue (-100.0),
463 "DeltaX", DoubleValue (5.0),
464 "DeltaY", DoubleValue (20.0),
465 "GridWidth", UintegerValue (20),
466 "LayoutType", StringValue ("RowFirst"));
469 @subsection Value classes
470 Readers will note the new FooValue classes which are subclasses of the
471 AttributeValue base class. These can be thought of as
472 an intermediate class that can be used to convert from raw types to the
473 Values that are used by the attribute system. Recall that this database is holding
474 objects of many types with a single generic type. Conversions to this
475 type can either be done using an intermediate class (IntegerValue, DoubleValue for
476 "floating point") or via strings. Direct implicit conversion of types
477 to Value is not really practical. So in the above, users have a choice
478 of using strings or values:
480 p->Set ("cwnd", StringValue ("100")); // string-based setter
481 p->Set ("cwnd", IntegerValue (100)); // integer-based setter
484 The system provides some macros that help users declare and define
485 new AttributeValue subclasses for new types that they want to introduce into
486 the attribute system:
488 @item ATTRIBUTE_HELPER_HEADER
489 @item ATTRIBUTE_HELPER_CPP
492 @node Extending attributes
493 @section Extending attributes
495 The ns-3 system will place a number of internal values under the
496 attribute system, but undoubtedly users will want to extend this
497 to pick up ones we have missed, or to add their own classes to this.
499 @subsection Adding an existing internal variable to the metadata system
501 Consider this variable in class TcpSocket:
503 uint32_t m_cWnd; // Congestion window
506 Suppose that someone working with Tcp wanted to get or set the
507 value of that variable using the metadata system. If it were not
508 already provided by ns-3, the user could declare the following addition
509 in the runtime metadata system (to the TypeId declaration for TcpSocket):
511 .AddAttribute ("Congestion window",
512 "Tcp congestion window (bytes)",
514 MakeUintegerAccessor (&TcpSocket::m_cWnd),
515 MakeUintegerChecker<uint16_t> ())
519 Now, the user with a pointer to the TcpSocket can perform operations
520 such as setting and getting the value, without having to add these
521 functions explicitly. Furthermore, access controls can be applied, such
522 as allowing the parameter to be read and not written, or bounds
523 checking on the permissible values can be applied.
525 @subsection Adding a new TypeId
527 Here, we discuss the impact on a user who wants to add a new class to
528 ns-3; 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).
555 The declaration for this in the class declaration is one-line public
559 static TypeId GetTypeId (void);
562 Typical mistakes here involve:
564 @item Not calling the SetParent method or calling it with the wrong type
565 @item Not calling the AddConstructor method of calling it with the wrong type
566 @item Introducing a typographical error in the name of the TypeId in its constructor
567 @item Not using the fully-qualified c++ typename of the enclosing c++ class as the
570 None of these mistakes can be detected by the ns-3 codebase so, users
571 are advised to check carefully multiple times that they got these right.
574 @node Adding new class type
575 @section Adding new class type to the attribute system
577 From the perspective of the user who writes a new class in the system and
578 wants to hook it in to the attribute system, there is mainly the matter
580 the conversions to/from strings and attribute values. Most of this can be
581 copy/pasted with macro-ized code. For instance, consider class
582 delcaration for Rectangle in the @code{src/mobility/} directory:
586 * \brief a 2d rectangle
599 One macro call and two operators, must be added below the class declaration
600 in order to turn a Rectangle into a value usable by the @code{Attribute}
604 std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
605 std::istream &operator >> (std::istream &is, Rectangle &rectangle);
607 ATTRIBUTE_HELPER_HEADER (Rectangle);
610 In the class definition (@code{.cc} file), the code looks like this:
613 ATTRIBUTE_HELPER_CPP (Rectangle);
616 operator << (std::ostream &os, const Rectangle &rectangle)
618 os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
622 operator >> (std::istream &is, Rectangle &rectangle)
625 is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
630 is.setstate (std::ios_base::failbit);
636 These stream operators simply convert from a string representation of the
637 Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
638 modeler must specify these operators and the string syntactical representation
639 of an instance of the new class.
644 @strong{Feedback requested:} This is an experimental feature of ns-3. It is
645 found in @code{src/contrib} and not in the main tree. If you like this feature
646 and would like to provide feedback on it, please email us.
648 Values for ns-3 attributes can be stored in an ascii or XML text file and
649 loaded into a future simulation. This feature is known as the
651 The ConfigStore code is in @code{src/contrib/}. It is not yet main-tree
652 code, because we are seeking some user feedback and experience with this.
654 We can explore this system by using an example. Copy the @code{csma-bridge.cc}
655 file to the scratch directory:
657 cp examples/csma-bridge.cc scratch/
661 Let's edit it to add the ConfigStore feature. First, add an include statement
662 to include the contrib module, and then add these lines:
665 #include "contrib-module.h"
671 // Invoke just before entering Simulator::Run ()
673 config.ConfigureDefaults ();
674 config.ConfigureAttributes ();
680 There are three attributes that govern the behavior of the ConfigStore:
681 "Mode", "Filename", and "FileFormat". The Mode (default "None") configures
682 whether ns-3 should load configuration from a previously saved file
683 (specify "Mode=Load") or save it to a file (specify "Mode=Save").
684 The Filename (default "") is where the ConfigStore should store its
685 output data. The FileFormat (default "RawText") governs whether
686 the ConfigStore format is Xml or RawText format.
688 So, using the above modified program, try executing the following
691 ./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge
693 After running, you can open the csma-bridge-config.xml file and it will
694 display the configuration that was applied to your simulation; e.g.
696 <?xml version="1.0" encoding="UTF-8"?>
698 <default name="ns3::V4Ping::Remote" value="102.102.102.102"/>
699 <default name="ns3::MsduStandardAggregator::MaxAmsduSize" value="7935"/>
700 <default name="ns3::EdcaTxopN::MinCw" value="31"/>
701 <default name="ns3::EdcaTxopN::MaxCw" value="1023"/>
702 <default name="ns3::EdcaTxopN::Aifsn" value="3"/>
703 <default name="ns3::QstaWifiMac::ProbeRequestTimeout" value="50000000ns"/>
704 <default name="ns3::QstaWifiMac::AssocRequestTimeout" value="500000000ns"/>
705 <default name="ns3::QstaWifiMac::MaxMissedBeacons" value="10"/>
706 <default name="ns3::QstaWifiMac::ActiveProbing" value="false"/>
709 This file can be archived with your simulation script and output data.
711 While it is possible to generate a sample config file and lightly
712 edit it to change a couple of values, there are cases where this
713 process will not work because the same value on the same object
714 can appear multiple times in the same automatically-generated
715 configuration file under different configuration paths.
717 As such, the best way to use this class is to use it to generate
718 an initial configuration file, extract from that configuration
719 file only the strictly necessary elements, and move these minimal
720 elements to a new configuration file which can then safely
721 be edited and loaded in a subsequent simulation run.
723 When the ConfigStore object is instantiated, its attributes Filename,
724 Mode, and FileFormat must be set, either via command-line or via
727 As a more complicated example, let's assume that we want to
728 read in a configuration of defaults from an input file named
729 "input-defaults.xml", and write out the resulting attributes to a
730 separate file called "output-attributes.xml". (Note-- to get this
731 input xml file to begin with, it is sometimes helpful to run the
732 program to generate an output xml file first, then hand-edit that
733 file and re-input it for the next simulation run).
735 #include "contrib-module.h"
740 Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
741 Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
742 Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
743 ConfigStore inputConfig;
744 inputConfig.ConfigureDefaults ();
747 // Allow the user to override any of the defaults and the above Bind() at
748 // run-time, via command-line arguments
751 cmd.Parse (argc, argv);
756 // Invoke just before entering Simulator::Run ()
757 Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
758 Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
759 ConfigStore outputConfig;
760 outputConfig.ConfigureAttributes ();
765 @subsection GTK-based ConfigStore
767 There is a GTK-based front end for the ConfigStore. This allows users
768 to use a GUI to access and change variables. Screenshots of this
769 feature are available in the
770 @uref{http://www.nsnam.org/docs/ns-3-overview.pdf,,ns-3 Overview} presentation.
772 To use this feature, one must install libgtk and libgtk-dev; an example
773 Ubuntu installation command is:
775 sudo apt-get install libgtk2.0-0 libgtk2.0-dev
777 To check whether it is configured or not, check the output of the
778 ./waf configure step:
780 ---- Summary of optional NS-3 features:
781 Threading Primitives : enabled
782 Real Time Simulator : enabled
783 GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
786 In the above example, it was not enabled, so it cannot be used until a
787 suitable version is installed and ./waf configure; ./waf is rerun.
789 Usage is almost the same as the non-GTK-based version, but there
790 are no ConfigStore attributes involved:
792 // Invoke just before entering Simulator::Run ()
793 GtkConfigStore config;
794 config.ConfigureDefaults ();
795 config.ConfigureAttributes ();
798 Now, when you run the script, a GUI should pop up, allowing you to open
799 menus of attributes on different nodes/objects, and then launch the
800 simulation execution when you are done.
802 @subsection Future work
803 There are a couple of possible improvements:
805 @item save a unique version number with date and time at start of file
806 @item save rng initial seed somewhere.
807 @item make each RandomVariable serialize its own initial seed and re-read
809 @item add the default values