--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/in-process/attributes.texi Sat Jun 28 19:46:55 2008 -0700
@@ -0,0 +1,535 @@
+@node ns-3 Attributes
+@chapter ns-3 Attributes
+@anchor{chap:Attributes}
+
+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.
+
+@node Smart pointers
+@subsection Smart pointers
+
+As introduced above in @ref{Smart Pointers 101}, 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
+
+@node CreateObject
+@subsection CreateObject
+
+As we discussed above in @ref{Object Creation},
+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.
+
+@node TypeId
+@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
+
+@node Object Summary
+@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> n;
+@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.
+
+@node Functional overview
+@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.",
+ Uinteger (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.
+
+@node Basic usage
+@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", String ("80"));
+ // The below function call is redundant
+ Config::SetDefault ("ns3::DropTailQueue::MaxPackets", Uinteger(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 String and a Uinteger 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
+ Ptr<Queue> txQueue = net0->GetAttribute ("TxQueue");
+@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);
+@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 Uinteger, and
+the Get() method on this value produces the (unwrapped) uint32_t.
+@verbatim
+ Uinteger limit = dtq->GetAttribute ("MaxPackets");
+ 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
+ limit = txQueue->GetAttribute ("MaxPackets");
+ 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", Uinteger (60));
+ limit = txQueue->GetAttribute ("MaxPackets");
+ 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", Uinteger (25));
+ limit = txQueue->GetAttribute ("MaxPackets");
+ 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", Uinteger (15));
+ limit = txQueue->GetAttribute ("MaxPackets");
+ NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
+ limit.Get () << " packets");
+@end verbatim
+
+@node Setting through constructors and helper classes
+@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", FpValue (-100.0),
+ "MinY", FpValue (-100.0),
+ "DeltaX", FpValue (5.0),
+ "DeltaY", FpValue (20.0),
+ "GridWidth", UintValue (20),
+ "LayoutType", "RowFirst");
+@end verbatim
+
+@node Value classes
+@subsection Value classes
+Readers will note the new Value classes. 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 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 (IntValue, FpValue 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", "100"); // string-based setter
+p->Set ("cwnd", IntValue(100)); // value-based setter
+@end verbatim
+
+The system provides some macros that help users declare and define
+new Value subclasses for new types that they want to introduce into
+the attribute system.
+
+@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
+
+// XXX revise me
+
+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)",
+ MakeUIntParamSpec (&TcpSocket::m_cWnd, 1));
+
+@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 ("RandomWalkMobilityModel")
+ .SetParent<MobilityModel> ()
+ .SetGroupName ("Mobility")
+ .AddConstructor<RandomWalk2dMobilityModel> ()
+ // followed by a number of Parameters
+ .AddParameter ("bounds",
+ "Bounds of the area to cruise.",
+ MakeRectangleParamSpec (&RandomWalk2dMobilityModel::m_bounds, Rectangle (0.0, 0.0, 100.0, 100.0)))
+ .AddParameter ("time",
+ "Change current direction and speed after moving for this delay.",
+ MakeTimeParamSpec (&RandomWalk2dMobilityModel::m_modeTime,
+ Seconds (1.0)))
+
+ // etc (more parameters).
+@end verbatim
+
+The declaration for this in the class declaration is one-line public
+member method:
+@verbatim
+ public:
+ static TypeId GetTypeId (void);
+@end verbatim
+
+@section Adding new class type to the Value 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 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
+{
+...
+
+ VALUE_HELPER_HEADER_1 (Rectangle);
+};
+@end verbatim
+
+One templatized declaration, 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);
+
+VALUE_HELPER_HEADER_2 (Rectangle);
+@end verbatim
+
+In the class definition, the code looks like this:
+
+@verbatim
+VALUE_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.
+