716 lines
26 KiB
Plaintext
716 lines
26 KiB
Plaintext
@node Attributes
|
|
@chapter Attributes
|
|
@anchor{chap:Attributes}
|
|
|
|
@menu
|
|
* Object Overview::::
|
|
* Attribute Overview::
|
|
* Extending attributes::
|
|
* Adding new class type::
|
|
* ConfigStore::
|
|
@end menu
|
|
|
|
|
|
In ns-3 simulations, there are two main aspects to configuration:
|
|
@itemize @bullet
|
|
@item the simulation topology and how objects are connected
|
|
@item the values used by the models instantiated in the topology
|
|
@end itemize
|
|
|
|
This chapter focuses on the second item above: how the many values
|
|
in use in ns-3 are organized, documented, and modifiable by ns-3 users.
|
|
The ns-3 attribute system is also the underpinning of how traces
|
|
and statistics are gathered in the simulator.
|
|
|
|
Before delving into details of the attribute value system,
|
|
it will help to review some basic properties of @code{class ns3::Object}.
|
|
|
|
@node Object Overview
|
|
@section Object Overview
|
|
|
|
ns-3 is fundamentally a C++ object-based system. By this we mean that
|
|
new C++ classes (types) can be declared, defined, and subclassed
|
|
as usual.
|
|
|
|
Many ns-3 objects inherit from the @code{ns3::Object} base class. These
|
|
objects have some additional properties that we exploit for
|
|
organizing the system and improving the memory management
|
|
of our objects:
|
|
|
|
@itemize @bullet
|
|
@item a "metadata" system that links the class name to a lot of
|
|
meta-information about the object, including the base class of the subclass,
|
|
the set of accessible constructors in the subclass, and the set of
|
|
"attributes" of the subclass
|
|
@item a reference counting smart pointer implementation, for memory
|
|
management.
|
|
@end itemize
|
|
|
|
ns-3 objects that use the attribute system derive from either
|
|
@code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects
|
|
we will discuss derive from @code{ns3::Object}, but a few that
|
|
are outside the smart pointer memory management framework derive
|
|
from @code{ns3::ObjectBase}.
|
|
|
|
Let's review a couple of properties of these objects.
|
|
|
|
@subsection Smart pointers
|
|
|
|
As introduced in the ns-3 tutorial, ns-3 objects are memory managed by a
|
|
@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}.
|
|
|
|
Smart pointers are used extensively in the ns-3 APIs, to avoid passing
|
|
references to heap-allocated objects that may cause memory leaks.
|
|
For most basic usage (syntax), treat a smart pointer like a regular pointer:
|
|
@verbatim
|
|
Ptr<WifiNetDevice> nd = ...;
|
|
nd->CallSomeFunction ();
|
|
// etc.
|
|
@end verbatim
|
|
|
|
@subsection CreateObject
|
|
|
|
As we discussed above in @ref{Memory management and class Ptr},
|
|
at the lowest-level API, objects of type @code{ns3::Object} are
|
|
not instantiated using @code{operator new} as usual but instead by
|
|
a templated function called @code{CreateObject()}.
|
|
|
|
A typical way to create such an object is as follows:
|
|
@verbatim
|
|
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
|
|
@end verbatim
|
|
|
|
You can think of this as being functionally equivalent to:
|
|
@verbatim
|
|
WifiNetDevice* nd = new WifiNetDevice ();
|
|
@end verbatim
|
|
|
|
Objects that derive from @code{ns3::Object} must be allocated
|
|
on the heap using CreateObject(). Those deriving from
|
|
@code{ns3::ObjectBase}, such as ns-3 helper functions and packet
|
|
headers and trailers, can be allocated on the stack.
|
|
|
|
In some scripts, you may not see a lot of CreateObject() calls
|
|
in the code;
|
|
this is because there are some helper objects in effect that
|
|
are doing the CreateObject()s for you.
|
|
|
|
@subsection TypeId
|
|
|
|
ns-3 classes that derive from class ns3::Object can include
|
|
a metadata class called @code{TypeId} that records meta-information
|
|
about the class, for use in the object aggregation and component
|
|
manager systems:
|
|
@itemize @bullet
|
|
@item a unique string identifying the class
|
|
@item the base class of the subclass, within the metadata system
|
|
@item the set of accessible constructors in the subclass
|
|
@end itemize
|
|
|
|
@subsection Object Summary
|
|
|
|
Putting all of these concepts together, let's look at a specific
|
|
example: @code{class ns3::Node}.
|
|
|
|
The public header file node.h has a declaration that includes
|
|
a static GetTypeId function call:
|
|
@verbatim
|
|
class Node : public Object
|
|
{
|
|
public:
|
|
static TypeId GetTypeId (void);
|
|
...
|
|
@end verbatim
|
|
|
|
This is defined in the node.cc file as follows:
|
|
@verbatim
|
|
TypeId
|
|
Node::GetTypeId (void)
|
|
{
|
|
static TypeId tid = TypeId ("ns3::Node")
|
|
.SetParent<Object> ()
|
|
;
|
|
return tid;
|
|
}
|
|
@end verbatim
|
|
Finally, when users want to create Nodes, they call:
|
|
@verbatim
|
|
Ptr<Node> n = CreateObject<Node> ();
|
|
@end verbatim
|
|
|
|
We next discuss how attributes (values associated with member variables
|
|
or functions of the class) are plumbed into the above TypeId.
|
|
|
|
@node Attribute Overview
|
|
@section Attribute Overview
|
|
|
|
The goal of the attribute system is to organize the access of
|
|
internal member objects of a simulation. This goal arises because,
|
|
typically in simulation, users will cut and paste/modify existing
|
|
simulation scripts, or will use higher-level simulation constructs,
|
|
but often will be interested in studying or tracing particular
|
|
internal variables. For instance, use cases such as:
|
|
@itemize @bullet
|
|
@item "I want to trace the packets on the wireless interface only on
|
|
the first access point"
|
|
@item "I want to trace the value of the TCP congestion window (every
|
|
time it changes) on a particular TCP socket"
|
|
@item "I want a dump of all values that were used in my simulation."
|
|
@end itemize
|
|
|
|
Similarly, users may want fine-grained access to internal
|
|
variables in the simulation, or may want to broadly change the
|
|
initial value used for a particular parameter in all subsequently
|
|
created objects. Finally, users may wish to know what variables
|
|
are settable and retrievable in a simulation configuration. This
|
|
is not just for direct simulation interaction on the command line;
|
|
consider also a (future) graphical user interface
|
|
that would like to be able to provide a feature whereby a user
|
|
might right-click on an node on the canvas and see a hierarchical,
|
|
organized list of parameters that are settable on the node and its
|
|
constituent member objects, and help text and default values for
|
|
each parameter.
|
|
|
|
@subsection Functional overview
|
|
|
|
We provide a way for users to access values deep in the system, without
|
|
having to plumb accessors (pointers) through the system and walk
|
|
pointer chains to get to them. Consider a class DropTailQueue that
|
|
has a member variable that is an unsigned integer @code{m_maxPackets};
|
|
this member variable controls the depth of the queue.
|
|
|
|
If we look at the declaration of DropTailQueue, we see the following:
|
|
@verbatim
|
|
class DropTailQueue : public Queue {
|
|
public:
|
|
static TypeId GetTypeId (void);
|
|
...
|
|
|
|
private:
|
|
std::queue<Ptr<Packet> > m_packets;
|
|
uint32_t m_maxPackets;
|
|
};
|
|
@end verbatim
|
|
|
|
Let's consider things that a user may want to do with the value of
|
|
m_maxPackets:
|
|
|
|
@itemize @bullet
|
|
@item Set a default value for the system, such that whenever a new
|
|
DropTailQueue is created, this member is initialized to that default.
|
|
@item Set or get the value on an already instantiated queue.
|
|
@end itemize
|
|
|
|
The above things typically require providing Set() and Get() functions,
|
|
and some type of global default value.
|
|
|
|
In the ns-3 attribute system, these value definitions and accessor
|
|
functions are moved into the TypeId class; e.g.:
|
|
@verbatim
|
|
TypeId DropTailQueue::GetTypeId (void)
|
|
{
|
|
static TypeId tid = TypeId ("ns3::DropTailQueue")
|
|
.SetParent<Queue> ()
|
|
.AddConstructor<DropTailQueue> ()
|
|
.AddAttribute ("MaxPackets",
|
|
"The maximum number of packets accepted by this DropTailQueue.",
|
|
UintegerValue (100),
|
|
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
|
|
MakeUintegerChecker<uint32_t> ())
|
|
;
|
|
|
|
return tid;
|
|
}
|
|
@end verbatim
|
|
|
|
The AddAttribute() method is performing a number of things with this
|
|
value:
|
|
@itemize @bullet
|
|
@item Binding the variable m_maxPackets to a string "MaxPackets"
|
|
@item Providing a default value (100 packets)
|
|
@item Providing some help text defining the value
|
|
@item Providing a "checker" (not used in this example) that can be used to set
|
|
bounds on the allowable range of values
|
|
@end itemize
|
|
|
|
The key point is that now the value of this variable and its default
|
|
value are accessible in the attribute namespace, which is based on
|
|
strings such as "MaxPackets" and TypeId strings. In the next
|
|
section, we will provide an example script that shows how users
|
|
may manipulate these values.
|
|
|
|
@subsection Basic usage
|
|
|
|
Let's look at how a user script might access these values.
|
|
This is based on the script found at @code{samples/main-attribute-value.cc},
|
|
with some details stripped out.
|
|
@verbatim
|
|
//
|
|
// This is a basic example of how to use the attribute system to
|
|
// set and get a value in the underlying system; namely, an unsigned
|
|
// integer of the maximum number of packets in a queue
|
|
//
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
|
|
// By default, the MaxPackets attribute has a value of 100 packets
|
|
// (this default can be observed in the function DropTailQueue::GetTypeId)
|
|
//
|
|
// Here, we set it to 80 packets. We could use one of two value types:
|
|
// a string-based value or a Uinteger value
|
|
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
|
|
// The below function call is redundant
|
|
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));
|
|
|
|
// Allow the user to override any of the defaults and the above
|
|
// SetDefaults() at run-time, via command-line arguments
|
|
CommandLine cmd;
|
|
cmd.Parse (argc, argv);
|
|
@end verbatim
|
|
|
|
The main thing to notice in the above are the two calls to
|
|
@code{Config::SetDefault}. This is how we set the default value
|
|
for all subsequently instantiated DropTailQueues. We illustrate
|
|
that two types of Value classes, a StringValue and a UintegerValue class,
|
|
can be used to assign the value to the attribute named by
|
|
"ns3::DropTailQueue::MaxPackets".
|
|
|
|
Now, we will create a few objects using the low-level API; here,
|
|
our newly created queues will not have a m_maxPackets initialized to
|
|
100 packets but to 80 packets, because of what we did above with
|
|
default values.
|
|
@verbatim
|
|
Ptr<Node> n0 = CreateObject<Node> ();
|
|
|
|
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
|
|
n0->AddDevice (net0);
|
|
|
|
Ptr<Queue> q = CreateObject<DropTailQueue> ();
|
|
net0->AddQueue(q);
|
|
@end verbatim
|
|
|
|
At this point, we have created a single node (Node 0) and a
|
|
single PointToPointNetDevice (NetDevice 0) and added a
|
|
DropTailQueue to it.
|
|
|
|
Now, we can manipulate the MaxPackets value of the already
|
|
instantiated DropTailQueue. Here are various ways to do that.
|
|
|
|
@subsubsection Pointer-based access
|
|
|
|
We assume that a smart pointer (Ptr) to a relevant network device is
|
|
in hand; here, it is the net0 pointer.
|
|
|
|
One way to change the value is to access a pointer to the
|
|
underlying queue and modify its attribute.
|
|
|
|
First, we observe that we can get a pointer to the (base class)
|
|
queue via the PointToPointNetDevice attributes, where it is called
|
|
TxQueue
|
|
@verbatim
|
|
PointerValue tmp;
|
|
net0->GetAttribute ("TxQueue", tmp);
|
|
Ptr<Object> txQueue = tmp.GetObject ();
|
|
@end verbatim
|
|
|
|
Using the GetObject function, we can perform a safe downcast
|
|
to a DropTailQueue, where MaxPackets is a member
|
|
@verbatim
|
|
Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
|
|
NS_ASSERT (dtq != 0);
|
|
@end verbatim
|
|
|
|
Next, we can get the value of an attribute on this queue.
|
|
We have introduced wrapper "Value" classes for the underlying
|
|
data types, similar to Java wrappers around these types, since
|
|
the attribute system stores values and not disparate types.
|
|
Here, the attribute value is assigned to a UintegerValue, and
|
|
the Get() method on this value produces the (unwrapped) uint32_t.
|
|
@verbatim
|
|
UintegerValue limit;
|
|
dtq->GetAttribute ("MaxPackets", limit);
|
|
NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
|
|
@end verbatim
|
|
|
|
Note that the above downcast is not really needed; we could have
|
|
done the same using the Ptr<Queue> even though the attribute
|
|
is a member of the subclass
|
|
@verbatim
|
|
txQueue->GetAttribute ("MaxPackets", limit);
|
|
NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
|
|
@end verbatim
|
|
|
|
Now, let's set it to another value (60 packets)
|
|
@verbatim
|
|
txQueue->SetAttribute("MaxPackets", UintegerValue (60));
|
|
txQueue->GetAttribute ("MaxPackets", limit);
|
|
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
|
|
@end verbatim
|
|
|
|
@subsubsection Namespace-based access
|
|
|
|
An alternative way to get at the attribute is to use the configuration
|
|
namespace. Here, this attribute resides on a known path in this
|
|
namespace; this approach is useful if one doesn't have access to
|
|
the underlying pointers and would like to configure a specific
|
|
attribute with a single statement.
|
|
@verbatim
|
|
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
|
|
txQueue->GetAttribute ("MaxPackets", limit);
|
|
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
|
|
limit.Get () << " packets");
|
|
@end verbatim
|
|
|
|
We could have also used wildcards to set this value for all nodes
|
|
and all net devices (which in this simple example has the same
|
|
effect as the previous Set())
|
|
@verbatim
|
|
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
|
|
txQueue->GetAttribute ("MaxPackets", limit);
|
|
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
|
|
limit.Get () << " packets");
|
|
@end verbatim
|
|
|
|
@subsection Setting through constructors helper classes
|
|
|
|
Arbitrary combinations of attributes can be set and fetched from
|
|
the helper and low-level APIs; either from the constructors themselves:
|
|
@verbatim
|
|
Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
|
|
@end verbatim
|
|
or from the higher-level helper APIs, such as:
|
|
@verbatim
|
|
mobility.SetPositionAllocator ("GridPositionAllocator",
|
|
"MinX", DoubleValue (-100.0),
|
|
"MinY", DoubleValue (-100.0),
|
|
"DeltaX", DoubleValue (5.0),
|
|
"DeltaY", DoubleValue (20.0),
|
|
"GridWidth", UintegerValue (20),
|
|
"LayoutType", StringValue ("RowFirst"));
|
|
@end verbatim
|
|
|
|
@subsection Value classes
|
|
Readers will note the new FooValue classes which are subclasses of the
|
|
AttributeValue base class. These can be thought of as
|
|
an intermediate class that can be used to convert from raw types to the
|
|
Values that are used by the attribute system. Recall that this database is holding
|
|
objects of many types with a single generic type. Conversions to this
|
|
type can either be done using an intermediate class (IntegerValue, DoubleValue for
|
|
"floating point") or via strings. Direct implicit conversion of types
|
|
to Value is not really practical. So in the above, users have a choice
|
|
of using strings or values:
|
|
@verbatim
|
|
p->Set ("cwnd", StringValue ("100")); // string-based setter
|
|
p->Set ("cwnd", IntegerValue (100)); // integer-based setter
|
|
@end verbatim
|
|
|
|
The system provides some macros that help users declare and define
|
|
new AttributeValue subclasses for new types that they want to introduce into
|
|
the attribute system:
|
|
@itemize @bullet
|
|
@item ATTRIBUTE_HELPER_HEADER
|
|
@item ATTRIBUTE_HELPER_CPP
|
|
@end itemize
|
|
|
|
@node Extending attributes
|
|
@section Extending attributes
|
|
|
|
The ns-3 system will place a number of internal values under the
|
|
attribute system, but undoubtedly users will want to extend this
|
|
to pick up ones we have missed, or to add their own classes to this.
|
|
|
|
@subsection Adding an existing internal variable to the metadata system
|
|
|
|
Consider this variable in class TcpSocket:
|
|
@verbatim
|
|
uint32_t m_cWnd; // Congestion window
|
|
@end verbatim
|
|
|
|
Suppose that someone working with Tcp wanted to get or set the
|
|
value of that variable using the metadata system. If it were not
|
|
already provided by ns-3, the user could declare the following addition
|
|
in the metadata system (to the TypeId declaration for TcpSocket):
|
|
@verbatim
|
|
.AddParameter ("Congestion window",
|
|
"Tcp congestion window (bytes)",
|
|
Uinteger (1),
|
|
MakeUintegerAccessor (&TcpSocket::m_cWnd),
|
|
MakeUintegerChecker<uint16_t> ());
|
|
|
|
@end verbatim
|
|
|
|
Now, the user with a pointer to the TcpSocket can perform operations
|
|
such as setting and getting the value, without having to add these
|
|
functions explicitly. Furthermore, access controls can be applied, such
|
|
as allowing the parameter to be read and not written, or bounds
|
|
checking on the permissible values can be applied.
|
|
|
|
@subsection Adding a new TypeId
|
|
|
|
Here, we discuss the impact on a user who wants to add a new class to
|
|
ns-3; what additional things must be done to hook it into this system.
|
|
|
|
We've already introduced what a TypeId definition looks like:
|
|
@verbatim
|
|
TypeId
|
|
RandomWalk2dMobilityModel::GetTypeId (void)
|
|
{
|
|
static TypeId tid = TypeId ("ns3::RandomWalk2dMobilityModel")
|
|
.SetParent<MobilityModel> ()
|
|
.SetGroupName ("Mobility")
|
|
.AddConstructor<RandomWalk2dMobilityModel> ()
|
|
.AddAttribute ("Bounds",
|
|
"Bounds of the area to cruise.",
|
|
RectangleValue (Rectangle (0.0, 0.0, 100.0, 100.0)),
|
|
MakeRectangleAccessor (&RandomWalk2dMobilityModel::m_bounds),
|
|
MakeRectangleChecker ())
|
|
.AddAttribute ("Time",
|
|
"Change current direction and speed after moving for this delay.",
|
|
TimeValue (Seconds (1.0)),
|
|
MakeTimeAccessor (&RandomWalk2dMobilityModel::m_modeTime),
|
|
MakeTimeChecker ())
|
|
// etc (more parameters).
|
|
;
|
|
return tid;
|
|
}
|
|
@end verbatim
|
|
|
|
The declaration for this in the class declaration is one-line public
|
|
member method:
|
|
@verbatim
|
|
public:
|
|
static TypeId GetTypeId (void);
|
|
@end verbatim
|
|
|
|
Typical mistakes here involve:
|
|
@itemize @bullet
|
|
@item Not calling the SetParent method or calling it with the wrong type
|
|
@item Not calling the AddConstructor method of calling it with the wrong type
|
|
@item Introducing a typographical error in the name of the TypeId in its constructor
|
|
@item Not using the fully-qualified c++ typename of the enclosing c++ class as the
|
|
name of the TypeId
|
|
@end itemize
|
|
None of these mistakes can be detected by the ns-3 codebase so, users
|
|
are advised to check carefully multiple times that they got these right.
|
|
|
|
|
|
@node Adding new class type
|
|
@section Adding new class type to the attribute system
|
|
|
|
From the perspective of the user who writes a new class in the system and
|
|
wants to hook it in to the attribute system, there is mainly the matter
|
|
of writing
|
|
the conversions to/from strings and attribute values. Most of this can be
|
|
copy/pasted with macro-ized code. For instance, consider class
|
|
Rectangle in the @code{src/mobility/} directory:
|
|
|
|
One line is added to the class declaration:
|
|
@verbatim
|
|
/**
|
|
* \brief a 2d rectangle
|
|
*/
|
|
class Rectangle
|
|
{
|
|
...
|
|
|
|
};
|
|
@end verbatim
|
|
|
|
One macro call and two operators, are added below the class declaration:
|
|
|
|
@verbatim
|
|
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
|
|
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
|
|
|
|
ATTRIBUTE_HELPER_HEADER (Rectangle);
|
|
@end verbatim
|
|
|
|
In the class definition, the code looks like this:
|
|
|
|
@verbatim
|
|
ATTRIBUTE_HELPER_CPP (Rectangle);
|
|
|
|
std::ostream &
|
|
operator << (std::ostream &os, const Rectangle &rectangle)
|
|
{
|
|
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
|
|
return os;
|
|
}
|
|
std::istream &
|
|
operator >> (std::istream &is, Rectangle &rectangle)
|
|
{
|
|
char c1, c2, c3;
|
|
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
|
|
if (c1 != '|' ||
|
|
c2 != '|' ||
|
|
c3 != '|')
|
|
{
|
|
is.setstate (std::ios_base::failbit);
|
|
}
|
|
return is;
|
|
}
|
|
@end verbatim
|
|
|
|
These stream operators simply convert from a string representation of the
|
|
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
|
|
modeler must specify these operators and the string syntactical representation
|
|
of an instance of the new class.
|
|
|
|
@node ConfigStore
|
|
@section ConfigStore
|
|
|
|
@strong{Feedback requested:} This is an experimental feature of ns-3.
|
|
It is not in the main tree. If you like this feature and would like
|
|
to provide feedback on it, please email us.
|
|
|
|
Values for ns-3 attributes can be stored in an ascii text file and
|
|
loaded into a future simulation. This feature is known as the
|
|
ns-3 ConfigStore.
|
|
The ConfigStore code is in @code{src/contrib/}. It is not yet main-tree
|
|
code, because we are seeking some user feedback.
|
|
|
|
We can explore this system by using an example. Copy the @code{csma-bridge.cc}
|
|
file to the scratch directory:
|
|
@verbatim
|
|
cp examples/csma-bridge.cc scratch/
|
|
./waf
|
|
@end verbatim
|
|
|
|
Let's edit it to add the ConfigStore feature. First, add an include statement,
|
|
and then add these lines:
|
|
|
|
@verbatim
|
|
#include "contrib-module.h"
|
|
...
|
|
int main (...)
|
|
{
|
|
// setup topology
|
|
|
|
// Invoke just before entering Simulator::Run ()
|
|
ConfigStore config;
|
|
config.Configure ();
|
|
|
|
Simulator::Run ();
|
|
}
|
|
@end verbatim
|
|
|
|
There is an attribute that governs whether the Configure() call either
|
|
stores a simulation configuration in a file and exits, or whether
|
|
it loads a simulation configuration file annd proceeds. First,
|
|
the @code{LoadFilename} attribute is checked, and if non-empty,
|
|
the program loads the configuration from the filename provided.
|
|
If LoadFilename is empty, and if the @code{StoreFilename} attribute is
|
|
populated, the configuration will be written to the output filename
|
|
specified.
|
|
|
|
While it is possible to generate a sample config file and lightly
|
|
edit it to change a couple of values, there are cases where this
|
|
process will not work because the same value on the same object
|
|
can appear multiple times in the same automatically-generated
|
|
configuration file under different configuration paths.
|
|
|
|
As such, the best way to use this class is to use it to generate
|
|
an initial configuration file, extract from that configuration
|
|
file only the strictly necessary elements, and move these minimal
|
|
elements to a new configuration file which can then safely
|
|
be edited and loaded in a subsequent simulation run.
|
|
|
|
So, let's do that as an example. We'lll run the program once
|
|
to create a configure file, and look at it.
|
|
If you are running bash shell, the below command should work (which illustrates
|
|
how to set an attribute from the command line):
|
|
@verbatim
|
|
./build/debug/scratch/csma-bridge --ns3::ConfigStore::StoreFilename=test.config
|
|
@end verbatim
|
|
or, if the above does not work (the above requires rpath support), try this:
|
|
@verbatim
|
|
./waf --command-template="%s --ns3::ConfigStore::StoreFilename=test.config" --run scratch/csma-bridge
|
|
@end verbatim
|
|
|
|
Running the program should yield a "test.config" output configuration file
|
|
that looks like this:
|
|
@verbatim
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Addre
|
|
ss 00:00:00:00:00:01
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Frame
|
|
Size 1518
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/SendE
|
|
nable true
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Recei
|
|
veEnable true
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/TxQue
|
|
ue/$ns3::DropTailQueue/MaxPackets 100
|
|
/$ns3::NodeListPriv/NodeList/0/$ns3::Node/DeviceList/0/$ns3::CsmaNetDevice/Mtu 1
|
|
500
|
|
...
|
|
@end verbatim
|
|
|
|
The above lists, for each object in the script topology, the value of each
|
|
registered attribute. The syntax of this file is that the unique name
|
|
of the attribute (in the attribute namespace) is specified on each line,
|
|
followed by a value.
|
|
|
|
This file is intended to be a convenient record of the parameters that were
|
|
used in a given simulation run, and can be stored with simulation
|
|
output files. Additionally,
|
|
this file can also be used to parameterize a simulation, instead of
|
|
editing the script or passing in command line arguments. For instance,
|
|
a person wanting to run the simulation can examine and tweak the values
|
|
in a pre-existing configuration file, and pass the file to the
|
|
program. In this case, the relevant commands are:
|
|
@verbatim
|
|
./build/debug/scratch/csma-bridge --ns3::ConfigStore::LoadFilename=test.config
|
|
@end verbatim
|
|
or, if the above does not work (the above requires rpath support), try this:
|
|
@verbatim
|
|
./waf --command-template="%s --ns3::ConfigStore::LoadFilename=test.config" --run scratch/csma-bridge
|
|
@end verbatim
|
|
|
|
@subsection GTK-based ConfigStore
|
|
|
|
There is a GTK-based front end for the ConfigStore. This allows users
|
|
to use a GUI to access and change variables. Screenshots of this
|
|
feature are available in the
|
|
@uref{http://www.nsnam.org/docs/ns-3-overview.pdf,,ns-3 Overview} presentation.
|
|
|
|
To use this feature, one must install libgtk and libgtk-dev; an example
|
|
Ubuntu installation command is:
|
|
@verbatim
|
|
sudo apt-get install libgtk2.0-0 libgtk2.0-dev
|
|
@end verbatim
|
|
To check whether it is configured or not, check the output of the
|
|
./waf configure step:
|
|
@verbatim
|
|
---- Summary of optional NS-3 features:
|
|
Threading Primitives : enabled
|
|
Real Time Simulator : enabled
|
|
GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found)
|
|
@end verbatim
|
|
|
|
In the above example, it was not enabled, so it cannot be used until a
|
|
suitable version is installed and ./waf configure; ./waf is rerun.
|
|
|
|
Usage is almost the same as the non-GTK-based version:
|
|
@verbatim
|
|
// Invoke just before entering Simulator::Run ()
|
|
GtkConfigStore config;
|
|
config.Configure ();
|
|
@end verbatim
|
|
|
|
Now, when you run the script, a GUI should pop up, allowing you to open
|
|
menus of attributes on different nodes/objects, and then launch the
|
|
simulation execution when you are done.
|
|
|
|
@subsection Future work
|
|
There are a couple of possible improvements:
|
|
@itemize @bullet
|
|
@item save a unique version number with date and time at start of file
|
|
@item save rng initial seed somewhere.
|
|
@item make each RandomVariable serialize its own initial seed and re-read
|
|
it later
|
|
@item add the default values
|
|
@end itemize
|
|
|