--- a/doc/tutorial/tracing.texi Sun Jan 02 22:57:04 2011 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3174 +0,0 @@
-@c ============================================================================
-@c Begin document body here
-@c ============================================================================
-
-@c ============================================================================
-@c PART: The Tracing System
-@c ============================================================================
-@c The below chapters are under the major heading "The Tracing System"
-@c This is similar to the Latex \part command
-@c
-@c ============================================================================
-@c The Tracing System
-@c ============================================================================
-@node The Tracing System
-@chapter The Tracing System
-
-@menu
-* Background::
-* Overview::
-* A Real Example::
-* Using Mid-Level Trace Helpers::
-@end menu
-
-@c ============================================================================
-@c Background
-@c ============================================================================
-@node Background
-@section Background
-
-As mentioned in the Using the Tracing System section, the whole point of running
-an @code{ns-3} simulation is to generate output for study. You have two basic
-strategies to work with in @code{ns-3}: using generic pre-defined bulk output
-mechanisms and parsing their content to extract interesting information; or
-somehow developing an output mechanism that conveys exactly (and perhaps only)
-the information wanted.
-
-Using pre-defined bulk output mechanisms has the advantage of not requiring any
-changes to @code{ns-3}, but it does require programming. Often, pcap or NS_LOG
-output messages are gathered during simulation runs and separately run through
-scripts that use grep, sed or awk to parse the messages and reduce and transform
-the data to a manageable form. Programs must be written to do the
-transformation, so this does not come for free. Of course, if the information
-of interest in does not exist in any of the pre-defined output mechanisms,
-this approach fails.
-
-If you need to add some tidbit of information to the pre-defined bulk mechanisms,
-this can certainly be done; and if you use one of the @code{ns-3} mechanisms,
-you may get your code added as a contribution.
-
-@code{ns-3} provides another mechanism, called Tracing, that avoids some of the
-problems inherent in the bulk output mechanisms. It has several important
-advantages. First, you can reduce the amount of data you have to manage by only
-tracing the events of interest to you (for large simulations, dumping everything
-to disk for post-processing can create I/O bottlenecks). Second, if you use this
-method, you can control the format of the output directly so you avoid the
-postprocessing step with sed or awk script. If you desire, your output can be
-formatted directly into a form acceptable by gnuplot, for example. You can add
-hooks in the core which can then be accessed by other users, but which will
-produce no information unless explicitly asked to do so. For these reasons, we
-believe that the @code{ns-3} tracing system is the best way to get information
-out of a simulation and is also therefore one of the most important mechanisms
-to understand in @command{ns-3}.
-
-@subsection Blunt Instruments
-There are many ways to get information out of a program. The most
-straightforward way is to just directly print the information to the standard
-output, as in,
-
-@verbatim
- #include <iostream>
- ...
- void
- SomeFunction (void)
- {
- uint32_t x = SOME_INTERESTING_VALUE;
- ...
- std::cout << "The value of x is " << x << std::endl;
- ...
- }
-@end verbatim
-
-Nobody is going to prevent you from going deep into the core of @code{ns-3} and
-adding print statements. This is insanely easy to do and, after all, you have
-complete control of your own @code{ns-3} branch. This will probably not turn
-out to be very satisfactory in the long term, though.
-
-As the number of print statements increases in your programs, the task of
-dealing with the large number of outputs will become more and more complicated.
-Eventually, you may feel the need to control what information is being printed
-in some way; perhaps by turning on and off certain categories of prints, or
-increasing or decreasing the amount of information you want. If you continue
-down this path you may discover that you have re-implemented the @code{NS_LOG}
-mechanism. In order to avoid that, one of the first things you might consider
-is using @code{NS_LOG} itself.
-
-We mentioned above that one way to get information out of @code{ns-3} is to
-parse existing NS_LOG output for interesting information. If you discover that
-some tidbit of information you need is not present in existing log output, you
-could edit the core of @code{ns-3} and simply add your interesting information
-to the output stream. Now, this is certainly better than adding your own
-print statements since it follows @code{ns-3} coding conventions and could
-potentially be useful to other people as a patch to the existing core.
-
-Let's pick a random example. If you wanted to add more logging to the
-@code{ns-3} TCP socket (@code{tcp-socket-impl.cc}) you could just add a new
-message down in the implementation. Notice that in TcpSocketImpl::ProcessAction()
-there is no log message for the @code{ACK_TX} case. You could simply add one,
-changing the code from:
-
-@verbatim
- bool TcpSocketImpl::ProcessAction (Actions_t a)
- { // These actions do not require a packet or any TCP Headers
- NS_LOG_FUNCTION (this << a);
- switch (a)
- {
- case NO_ACT:
- NS_LOG_LOGIC ("TcpSocketImpl " << this <<" Action: NO_ACT");
- break;
- case ACK_TX:
- SendEmptyPacket (TcpHeader::ACK);
- break;
- ...
-@end verbatim
-
-to add a new @code{NS_LOG_LOGIC} in the appropriate @code{case} statement:
-
-@verbatim
- bool TcpSocketImpl::ProcessAction (Actions_t a)
- { // These actions do not require a packet or any TCP Headers
- NS_LOG_FUNCTION (this << a);
- switch (a)
- {
- case NO_ACT:
- NS_LOG_LOGIC ("TcpSocketImpl " << this << " Action: NO_ACT");
- break;
- case ACK_TX:
- NS_LOG_LOGIC ("TcpSocketImpl " << this << " Action: ACK_TX");
- SendEmptyPacket (TcpHeader::ACK);
- break;
- ...
-@end verbatim
-
-This may seem fairly simple and satisfying at first glance, but something to
-consider is that you will be writing code to add the @code{NS_LOG} statement
-and you will also have to write code (as in grep, sed or awk scripts) to parse
-the log output in order to isolate your information. This is because even
-though you have some control over what is output by the logging system, you
-only have control down to the log component level.
-
-If you are adding code to an existing module, you will also have to live with the
-output that every other developer has found interesting. You may find that in
-order to get the small amount of information you need, you may have to wade
-through huge amounts of extraneous messages that are of no interest to you. You
-may be forced to save huge log files to disk and process them down to a few lines
-whenever you want to do anything.
-
-Since there are no guarantees in @code{ns-3} about the stability of @code{NS_LOG}
-output, you may also discover that pieces of log output on which you depend
-disappear or change between releases. If you depend on the structure of the
-output, you may find other messages being added or deleted which may affect your
-parsing code.
-
-For these reasons, we consider prints to @code{std::cout} and NS_LOG messages
-to be quick and dirty ways to get more information out of @code{ns-3}.
-
-It is desirable to have a stable facility using stable APIs that allow one to
-reach into the core system and only get the information required. It is
-desirable to be able to do this without having to change and recompile the
-core system. Even better would be a system that notified the user when an item
-of interest changed or an interesting event happened so the user doesn't have
-to actively poke around in the system looking for things.
-
-The @command{ns-3} tracing system is designed to work along those lines and is
-well-integrated with the Attribute and Config subsystems allowing for relatively
-simple use scenarios.
-
-@node Overview
-@section Overview
-
-The ns-3 tracing system is built on the concepts of independent tracing sources
-and tracing sinks; along with a uniform mechanism for connecting sources to sinks.
-
-Trace sources are entities that can signal events that happen in a simulation and
-provide access to interesting underlying data. For example, a trace source could
-indicate when a packet is received by a net device and provide access to the
-packet contents for interested trace sinks. A trace source might also indicate
-when an interesting state change happens in a model. For example, the congestion
-window of a TCP model is a prime candidate for a trace source.
-
-Trace sources are not useful by themselves; they must be connected to other pieces
-of code that actually do something useful with the information provided by the source.
-The entities that consume trace information are called trace sinks. Trace sources
-are generators of events and trace sinks are consumers. This explicit division
-allows for large numbers of trace sources to be scattered around the system in
-places which model authors believe might be useful.
-
-There can be zero or more consumers of trace events generated by a trace source.
-One can think of a trace source as a kind of point-to-multipoint information link.
-Your code looking for trace events from a particular piece of core code could
-happily coexist with other code doing something entirely different from the same
-information.
-
-Unless a user connects a trace sink to one of these sources, nothing is output. By
-using the tracing system, both you and other people at the same trace source are
-getting exactly what they want and only what they want out of the system. Neither
-of you are impacting any other user by changing what information is output by the
-system. If you happen to add a trace source, your work as a good open-source
-citizen may allow other users to provide new utilities that are perhaps very useful
-overall, without making any changes to the @code{ns-3} core.
-
-@node A Simple Low-Level Example
-@subsection A Simple Low-Level Example
-
-Let's take a few minutes and walk through a simple tracing example. We are going
-to need a little background on Callbacks to understand what is happening in the
-example, so we have to take a small detour right away.
-
-@node Callbacks
-@subsubsection Callbacks
-
-The goal of the Callback system in @code{ns-3} is to allow one piece of code to
-call a function (or method in C++) without any specific inter-module dependency.
-This ultimately means you need some kind of indirection -- you treat the address
-of the called function as a variable. This variable is called a pointer-to-function
-variable. The relationship between function and pointer-to-function pointer is
-really no different that that of object and pointer-to-object.
-
-In C the canonical example of a pointer-to-function is a
-pointer-to-function-returning-integer (PFI). For a PFI taking one int parameter,
-this could be declared like,
-
-@verbatim
- int (*pfi)(int arg) = 0;
-@end verbatim
-
-What you get from this is a variable named simply ``pfi'' that is initialized
-to the value 0. If you want to initialize this pointer to something meaningful,
-you have to have a function with a matching signature. In this case, you could
-provide a function that looks like,
-
-@verbatim
- int MyFunction (int arg) {}
-@end verbatim
-
-If you have this target, you can initialize the variable to point to your
-function:
-
-@verbatim
- pfi = MyFunction;
-@end verbatim
-
-You can then call MyFunction indirectly using the more suggestive form of
-the call,
-
-@verbatim
- int result = (*pfi) (1234);
-@end verbatim
-
-This is suggestive since it looks like you are dereferencing the function
-pointer just like you would dereference any pointer. Typically, however,
-people take advantage of the fact that the compiler knows what is going on
-and will just use a shorter form,
-
-@verbatim
- int result = pfi (1234);
-@end verbatim
-
-This looks like you are calling a function named ``pfi,'' but the compiler is
-smart enough to know to call through the variable @code{pfi} indirectly to
-the function @code{MyFunction}.
-
-Conceptually, this is almost exactly how the tracing system will work.
-Basically, a trace source @emph{is} a callback. When a trace sink expresses
-interest in receiving trace events, it adds a Callback to a list of Callbacks
-internally held by the trace source. When an interesting event happens, the
-trace source invokes its @code{operator()} providing zero or more parameters.
-The @code{operator()} eventually wanders down into the system and does something
-remarkably like the indirect call you just saw. It provides zero or more
-parameters (the call to ``pfi'' above passed one parameter to the target function
-@code{MyFunction}.
-
-The important difference that the tracing system adds is that for each trace
-source there is an internal list of Callbacks. Instead of just making one
-indirect call, a trace source may invoke any number of Callbacks. When a trace
-sink expresses interest in notifications from a trace source, it basically just
-arranges to add its own function to the callback list.
-
-If you are interested in more details about how this is actually arranged in
-@code{ns-3}, feel free to peruse the Callback section of the manual.
-
-@node Example Code
-@subsubsection Example Code
-
-We have provided some code to implement what is really the simplest example
-of tracing that can be assembled. You can find this code in the tutorial
-directory as @code{fourth.cc}. Let's walk through it.
-
-@verbatim
- /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
- /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include "ns3/object.h"
- #include "ns3/uinteger.h"
- #include "ns3/traced-value.h"
- #include "ns3/trace-source-accessor.h"
-
- #include <iostream>
-
- using namespace ns3;
-@end verbatim
-
-Most of this code should be quite familiar to you. As mentioned above, the
-trace system makes heavy use of the Object and Attribute systems, so you will
-need to include them. The first two includes above bring in the declarations
-for those systems explicitly. You could use the core module header, but this
-illustrates how simple this all really is.
-
-The file, @code{traced-value.h} brings in the required declarations for tracing
-of data that obeys value semantics. In general, value semantics just means that
-you can pass the object around, not an address. In order to use value semantics
-at all you have to have an object with an associated copy constructor and
-assignment operator available. We extend the requirements to talk about the set
-of operators that are pre-defined for plain-old-data (POD) types. Operator=,
-operator++, operator---, operator+, operator==, etc.
-
-What this all really means is that you will be able to trace changes to a C++
-object made using those operators.
-
-Since the tracing system is integrated with Attributes, and Attributes work
-with Objects, there must be an @command{ns-3} @code{Object} for the trace source
-to live in. The next code snippet declares and defines a simple Object we can
-work with.
-
-@verbatim
- class MyObject : public Object
- {
- public:
- static TypeId GetTypeId (void)
- {
- static TypeId tid = TypeId ("MyObject")
- .SetParent (Object::GetTypeId ())
- .AddConstructor<MyObject> ()
- .AddTraceSource ("MyInteger",
- "An integer value to trace.",
- MakeTraceSourceAccessor (&MyObject::m_myInt))
- ;
- return tid;
- }
-
- MyObject () {}
- TracedValue<int32_t> m_myInt;
- };
-@end verbatim
-
-The two important lines of code, above, with respect to tracing are the
-@code{.AddTraceSource} and the @code{TracedValue} declaration of @code{m_myInt}.
-
-The @code{.AddTraceSource} provides the ``hooks'' used for connecting the trace
-source to the outside world through the config system. The @code{TracedValue}
-declaration provides the infrastructure that overloads the operators mentioned
-above and drives the callback process.
-
-@verbatim
- void
- IntTrace (int32_t oldValue, int32_t newValue)
- {
- std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
- }
-@end verbatim
-
-This is the definition of the trace sink. It corresponds directly to a callback
-function. Once it is connected, this function will be called whenever one of the
-overloaded operators of the @code{TracedValue} is executed.
-
-We have now seen the trace source and the trace sink. What remains is code to
-connect the source to the sink.
-
-@verbatim
- int
- main (int argc, char *argv[])
- {
- Ptr<MyObject> myObject = CreateObject<MyObject> ();
- myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
-
- myObject->m_myInt = 1234;
- }
-@end verbatim
-
-Here we first create the Object in which the trace source lives.
-
-The next step, the @code{TraceConnectWithoutContext}, forms the connection
-between the trace source and the trace sink. Notice the @code{MakeCallback}
-template function. This function does the magic required to create the
-underlying @code{ns-3} Callback object and associate it with the function
-@code{IntTrace}. TraceConnect makes the association between your provided
-function and the overloaded @code{operator()} in the traced variable referred
-to by the ``MyInteger'' Attribute. After this association is made, the trace
-source will ``fire'' your provided callback function.
-
-The code to make all of this happen is, of course, non-trivial, but the essence
-is that you are arranging for something that looks just like the @code{pfi()}
-example above to be called by the trace source. The declaration of the
-@code{TracedValue<int32_t> m_myInt;} in the Object itself performs the magic
-needed to provide the overloaded operators (++, ---, etc.) that will use the
-@code{operator()} to actually invoke the Callback with the desired parameters.
-The @code{.AddTraceSource} performs the magic to connect the Callback to the
-Config system, and @code{TraceConnectWithoutContext} performs the magic to
-connect your function to the trace source, which is specified by Attribute
-name.
-
-Let's ignore the bit about context for now.
-
-Finally, the line,
-
-@verbatim
- myObject->m_myInt = 1234;
-@end verbatim
-
-should be interpreted as an invocation of @code{operator=} on the member
-variable @code{m_myInt} with the integer @code{1234} passed as a parameter.
-
-It turns out that this operator is defined (by @code{TracedValue}) to execute
-a callback that returns void and takes two integer values as parameters ---
-an old value and a new value for the integer in question. That is exactly
-the function signature for the callback function we provided --- @code{IntTrace}.
-
-To summarize, a trace source is, in essence, a variable that holds a list of
-callbacks. A trace sink is a function used as the target of a callback. The
-Attribute and object type information systems are used to provide a way to
-connect trace sources to trace sinks. The act of ``hitting'' a trace source
-is executing an operator on the trace source which fires callbacks. This
-results in the trace sink callbacks registering interest in the source being
-called with the parameters provided by the source.
-
-If you now build and run this example,
-
-@verbatim
- ./waf --run fourth
-@end verbatim
-
-you will see the output from the @code{IntTrace} function execute as soon as the
-trace source is hit:
-
-@verbatim
- Traced 0 to 1234
-@end verbatim
-
-When we executed the code, @code{myObject->m_myInt = 1234;}, the trace source
-fired and automatically provided the before and after values to the trace sink.
-The function @code{IntTrace} then printed this to the standard output. No
-problem.
-
-@subsection Using the Config Subsystem to Connect to Trace Sources
-
-The @code{TraceConnectWithoutContext} call shown above in the simple example is
-actually very rarely used in the system. More typically, the @code{Config}
-subsystem is used to allow selecting a trace source in the system using what is
-called a @emph{config path}. We saw an example of this in the previous section
-where we hooked the ``CourseChange'' event when we were playing with
-@code{third.cc}.
-
-Recall that we defined a trace sink to print course change information from the
-mobility models of our simulation. It should now be a lot more clear to you
-what this function is doing.
-
-@verbatim
- void
- CourseChange (std::string context, Ptr<const MobilityModel> model)
- {
- Vector position = model->GetPosition ();
- NS_LOG_UNCOND (context <<
- " x = " << position.x << ", y = " << position.y);
- }
-@end verbatim
-
-When we connected the ``CourseChange'' trace source to the above trace sink,
-we used what is called a ``Config Path'' to specify the source when we
-arranged a connection between the pre-defined trace source and the new trace
-sink:
-
-@verbatim
- std::ostringstream oss;
- oss <<
- "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
- "/$ns3::MobilityModel/CourseChange";
-
- Config::Connect (oss.str (), MakeCallback (&CourseChange));
-@end verbatim
-
-Let's try and make some sense of what is sometimes considered relatively
-mysterious code. For the purposes of discussion, assume that the node
-number returned by the @code{GetId()} is ``7''. In this case, the path
-above turns out to be,
-
-@verbatim
- "/NodeList/7/$ns3::MobilityModel/CourseChange"
-@end verbatim
-
-The last segment of a config path must be an @code{Attribute} of an
-@code{Object}. In fact, if you had a pointer to the @code{Object} that has the
-``CourseChange'' @code{Attribute} handy, you could write this just like we did
-in the previous example. You know by now that we typically store pointers to
-our nodes in a NodeContainer. In the @code{third.cc} example, the Nodes of
-interest are stored in the @code{wifiStaNodes} NodeContainer. In fact, while
-putting the path together, we used this container to get a Ptr<Node> which we
-used to call GetId() on. We could have used this Ptr<Node> directly to call
-a connect method directly:
-
-@verbatim
- Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1);
- theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));
-@end verbatim
-
-In the @code{third.cc} example, we actually want an additional ``context'' to
-be delivered along with the Callback parameters (which will be explained below) so we
-could actually use the following equivalent code,
-
-@verbatim
- Ptr<Object> theObject = wifiStaNodes.Get (nWifi - 1);
- theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));
-@end verbatim
-
-It turns out that the internal code for @code{Config::ConnectWithoutContext} and
-@code{Config::Connect} actually do find a Ptr<Object> and call the appropriate
-TraceConnect method at the lowest level.
-
-The @code{Config} functions take a path that represents a chain of @code{Object}
-pointers. Each segment of a path corresponds to an Object Attribute. The last
-segment is the Attribute of interest, and prior segments must be typed to contain
-or find Objects. The @code{Config} code parses and ``walks'' this path until it
-gets to the final segment of the path. It then interprets the last segment as
-an @code{Attribute} on the last Object it found while walking the path. The
-@code{Config} functions then call the appropriate @code{TraceConnect} or
-@code{TraceConnectWithoutContext} method on the final Object. Let's see what
-happens in a bit more detail when the above path is walked.
-
-The leading ``/'' character in the path refers to a so-called namespace. One
-of the predefined namespaces in the config system is ``NodeList'' which is a
-list of all of the nodes in the simulation. Items in the list are referred to
-by indices into the list, so ``/NodeList/7'' refers to the eighth node in the
-list of nodes created during the simulation. This reference is actually a
-@code{Ptr<Node>} and so is a subclass of an @code{ns3::Object}.
-
-As described in the Object Model section of the @code{ns-3} manual, we support
-Object Aggregation. This allows us to form an association between different
-Objects without any programming. Each Object in an Aggregation can be reached
-from the other Objects.
-
-The next path segment being walked begins with the ``$'' character. This
-indicates to the config system that a @code{GetObject} call should be made
-looking for the type that follows. It turns out that the MobilityHelper used in
-@code{third.cc} arranges to Aggregate, or associate, a mobility model to each of
-the wireless Nodes. When you add the ``$'' you are asking for another Object that
-has presumably been previously aggregated. You can think of this as switching
-pointers from the original Ptr<Node> as specified by ``/NodeList/7'' to its
-associated mobility model --- which is of type ``$ns3::MobilityModel''. If you
-are familiar with @code{GetObject}, we have asked the system to do the following:
-
-@verbatim
- Ptr<MobilityModel> mobilityModel = node->GetObject<MobilityModel> ()
-@end verbatim
-
-We are now at the last Object in the path, so we turn our attention to the
-Attributes of that Object. The @code{MobilityModel} class defines an Attribute
-called ``CourseChange''. You can see this by looking at the source code in
-@code{src/mobility/mobility-model.cc} and searching for ``CourseChange'' in your
-favorite editor. You should find,
-
-@verbatim
- .AddTraceSource (``CourseChange'',
- ``The value of the position and/or velocity vector changed'',
- MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace))
-@end verbatim
-
-which should look very familiar at this point.
-
-If you look for the corresponding declaration of the underlying traced variable
-in @code{mobility-model.h} you will find
-
-@verbatim
- TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
-@end verbatim
-
-The type declaration @code{TracedCallback} identifies @code{m_courseChangeTrace}
-as a special list of Callbacks that can be hooked using the Config functions
-described above.
-
-The @code{MobilityModel} class is designed to be a base class providing a common
-interface for all of the specific subclasses. If you search down to the end of
-the file, you will see a method defined called @code{NotifyCourseChange()}:
-
-@verbatim
- void
- MobilityModel::NotifyCourseChange (void) const
- {
- m_courseChangeTrace(this);
- }
-@end verbatim
-
-Derived classes will call into this method whenever they do a course change to
-support tracing. This method invokes @code{operator()} on the underlying
-@code{m_courseChangeTrace}, which will, in turn, invoke all of the registered
-Callbacks, calling all of the trace sinks that have registered interest in the
-trace source by calling a Config function.
-
-So, in the @code{third.cc} example we looked at, whenever a course change is
-made in one of the @code{RandomWalk2dMobilityModel} instances installed, there
-will be a @code{NotifyCourseChange()} call which calls up into the
-@code{MobilityModel} base class. As seen above, this invokes @code{operator()}
-on @code{m_courseChangeTrace}, which in turn, calls any registered trace sinks.
-In the example, the only code registering an interest was the code that provided
-the config path. Therefore, the @code{CourseChange} function that was hooked
-from Node number seven will be the only Callback called.
-
-The final piece of the puzzle is the ``context''. Recall that we saw an output
-looking something like the following from @code{third.cc}:
-
-@verbatim
- /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677
-@end verbatim
-
-The first part of the output is the context. It is simply the path through
-which the config code located the trace source. In the case we have been looking at
-there can be any number of trace sources in the system corresponding to any number
-of nodes with mobility models. There needs to be some way to identify which trace
-source is actually the one that fired the Callback. An easy way is to request a
-trace context when you @code{Config::Connect}.
-
-@subsection How to Find and Connect Trace Sources, and Discover Callback Signatures
-
-The first question that inevitably comes up for new users of the Tracing system is,
-``okay, I know that there must be trace sources in the simulation core, but how do
-I find out what trace sources are available to me''?
-
-The second question is, ``okay, I found a trace source, how do I figure out the
-config path to use when I connect to it''?
-
-The third question is, ``okay, I found a trace source, how do I figure out what
-the return type and formal arguments of my callback function need to be''?
-
-The fourth question is, ``okay, I typed that all in and got this incredibly bizarre
-error message, what in the world does it mean''?
-
-@subsection What Trace Sources are Available?
-
-The answer to this question is found in the @code{ns-3} Doxygen. Go to the
-@code{ns-3} web site @uref{http://www.nsnam.org/getting_started.html,,``here''}
-and select the ``Doxygen (stable)'' link ``Documentation'' on the navigation
-bar to the left side of the page. Expand the ``Modules'' book in the NS-3
-documentation tree a the upper left by clicking the ``+'' box. Now, expand
-the ``Core'' book in the tree by clicking its ``+'' box. You should now
-see three extremely useful links:
-
-@itemize @bullet
-@item The list of all trace sources
-@item The list of all attributes
-@item The list of all global values
-@end itemize
-
-The list of interest to us here is ``the list of all trace sources''. Go
-ahead and select that link. You will see, perhaps not too surprisingly, a
-list of all of the trace sources available in the @code{ns-3} core.
-
-As an example, scroll down to @code{ns3::MobilityModel}. You will find
-an entry for
-
-@verbatim
- CourseChange: The value of the position and/or velocity vector changed
-@end verbatim
-
-You should recognize this as the trace source we used in the @code{third.cc}
-example. Perusing this list will be helpful.
-
-@subsection What String do I use to Connect?
-
-The easiest way to do this is to grep around in the @code{ns-3} codebase for someone
-who has already figured it out, You should always try to copy someone else's
-working code before you start to write your own. Try something like:
-
-@verbatim
- find . -name '*.cc' | xargs grep CourseChange | grep Connect
-@end verbatim
-
-and you may find your answer along with working code. For example, in this
-case, @code{./ns-3-dev/examples/wireless/mixed-wireless.cc} has something
-just waiting for you to use:
-
-@verbatim
- Config::Connect (``/NodeList/*/$ns3::MobilityModel/CourseChange'',
- MakeCallback (&CourseChangeCallback));
-@end verbatim
-
-If you cannot find any examples in the distribution, you can find this out
-from the @code{ns-3} Doxygen. It will probably be simplest just to walk
-through the ``CourseChanged'' example.
-
-Let's assume that you have just found the ``CourseChanged'' trace source in
-``The list of all trace sources'' and you want to figure out how to connect to
-it. You know that you are using (again, from the @code{third.cc} example) an
-@code{ns3::RandomWalk2dMobilityModel}. So open the ``Class List'' book in
-the NS-3 documentation tree by clicking its ``+'' box. You will now see a
-list of all of the classes in @code{ns-3}. Scroll down until you see the
-entry for @code{ns3::RandomWalk2dMobilityModel} and follow that link.
-You should now be looking at the ``ns3::RandomWalk2dMobilityModel Class
-Reference''.
-
-If you now scroll down to the ``Member Function Documentation'' section, you
-will see documentation for the @code{GetTypeId} function. You constructed one
-of these in the simple tracing example above:
-
-@verbatim
- static TypeId GetTypeId (void)
- {
- static TypeId tid = TypeId ("MyObject")
- .SetParent (Object::GetTypeId ())
- .AddConstructor<MyObject> ()
- .AddTraceSource ("MyInteger",
- "An integer value to trace.",
- MakeTraceSourceAccessor (&MyObject::m_myInt))
- ;
- return tid;
- }
-@end verbatim
-
-As mentioned above, this is the bit of code that connected the Config
-and Attribute systems to the underlying trace source. This is also the
-place where you should start looking for information about the way to
-connect.
-
-You are looking at the same information for the RandomWalk2dMobilityModel; and
-the information you want is now right there in front of you in the Doxygen:
-
-@verbatim
- This object is accessible through the following paths with Config::Set and Config::Connect:
-
- /NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel
-@end verbatim
-
-The documentation tells you how to get to the @code{RandomWalk2dMobilityModel}
-Object. Compare the string above with the string we actually used in the
-example code:
-
-@verbatim
- "/NodeList/7/$ns3::MobilityModel"
-@end verbatim
-
-The difference is due to the fact that two @code{GetObject} calls are implied
-in the string found in the documentation. The first, for @code{$ns3::MobilityModel}
-will query the aggregation for the base class. The second implied
-@code{GetObject} call, for @code{$ns3::RandomWalk2dMobilityModel}, is used to ``cast''
-the base class to the concrete implementation class. The documentation shows
-both of these operations for you. It turns out that the actual Attribute you are
-going to be looking for is found in the base class as we have seen.
-
-Look further down in the @code{GetTypeId} doxygen. You will find,
-
-@verbatim
- No TraceSources defined for this type.
- TraceSources defined in parent class ns3::MobilityModel:
-
- CourseChange: The value of the position and/or velocity vector changed
- Reimplemented from ns3::MobilityModel
-@end verbatim
-
-This is exactly what you need to know. The trace source of interest is found in
-@code{ns3::MobilityModel} (which you knew anyway). The interesting thing this
-bit of Doxygen tells you is that you don't need that extra cast in the config
-path above to get to the concrete class, since the trace source is actually in
-the base class. Therefore the additional @code{GetObject} is not required and
-you simply use the path:
-
-@verbatim
- /NodeList/[i]/$ns3::MobilityModel
-@end verbatim
-
-which perfectly matches the example path:
-
-@verbatim
- /NodeList/7/$ns3::MobilityModel
-@end verbatim
-
-@subsection What Return Value and Formal Arguments?
-
-The easiest way to do this is to grep around in the @code{ns-3} codebase for someone
-who has already figured it out, You should always try to copy someone else's
-working code. Try something like:
-
-@verbatim
- find . -name '*.cc' | xargs grep CourseChange | grep Connect
-@end verbatim
-
-and you may find your answer along with working code. For example, in this
-case, @code{./ns-3-dev/examples/wireless/mixed-wireless.cc} has something
-just waiting for you to use. You will find
-
-@verbatim
- Config::Connect (``/NodeList/*/$ns3::MobilityModel/CourseChange'',
- MakeCallback (&CourseChangeCallback));
-@end verbatim
-
-as a result of your grep. The @code{MakeCallback} should indicate to you that
-there is a callback function there which you can use. Sure enough, there is:
-
-@verbatim
- static void
- CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-@subsubsection Take my Word for It
-
-If there are no examples to work from, this can be, well, challenging to
-actually figure out from the source code.
-
-Before embarking on a walkthrough of the code, I'll be kind and just tell you
-a simple way to figure this out: The return value of your callback will always
-be void. The formal parameter list for a @code{TracedCallback} can be found
-from the template parameter list in the declaration. Recall that for our
-current example, this is in @code{mobility-model.h}, where we have previously
-found:
-
-@verbatim
- TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
-@end verbatim
-
-There is a one-to-one correspondence between the template parameter list in
-the declaration and the formal arguments of the callback function. Here,
-there is one template parameter, which is a @code{Ptr<const MobilityModel>}.
-This tells you that you need a function that returns void and takes a
-a @code{Ptr<const MobilityModel>}. For example,
-
-@verbatim
- void
- CourseChangeCallback (Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-That's all you need if you want to @code{Config::ConnectWithoutContext}. If
-you want a context, you need to @code{Config::Connect} and use a Callback
-function that takes a string context, then the required argument.
-
-@verbatim
- void
- CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-If you want to ensure that your @code{CourseChangeCallback} is only visible
-in your local file, you can add the keyword @code{static} and come up with:
-
-@verbatim
- static void
- CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-which is exactly what we used in the @code{third.cc} example.
-
-@subsubsection The Hard Way
-
-This section is entirely optional. It is going to be a bumpy ride, especially
-for those unfamiliar with the details of templates. However, if you get through
-this, you will have a very good handle on a lot of the @code{ns-3} low level
-idioms.
-
-So, again, let's figure out what signature of callback function is required for
-the ``CourseChange'' Attribute. This is going to be painful, but you only need
-to do this once. After you get through this, you will be able to just look at
-a @code{TracedCallback} and understand it.
-
-The first thing we need to look at is the declaration of the trace source.
-Recall that this is in @code{mobility-model.h}, where we have previously
-found:
-
-@verbatim
- TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
-@end verbatim
-
-This declaration is for a template. The template parameter is inside the
-angle-brackets, so we are really interested in finding out what that
-@code{TracedCallback<>} is. If you have absolutely no idea where this might
-be found, grep is your friend.
-
-We are probably going to be interested in some kind of declaration in the
-@code{ns-3} source, so first change into the @code{src} directory. Then,
-we know this declaration is going to have to be in some kind of header file,
-so just grep for it using:
-
-@verbatim
- find . -name '*.h' | xargs grep TracedCallback
-@end verbatim
-
-You'll see 124 lines fly by (I piped this through wc to see how bad it was).
-Although that may seem like it, that's not really a lot. Just pipe the output
-through more and start scanning through it. On the first page, you will see
-some very suspiciously template-looking stuff.
-
-@verbatim
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::TracedCallback ()
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext (c ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Connect (const CallbackB ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::DisconnectWithoutContext ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Disconnect (const Callba ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (void) const ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1) const ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
-@end verbatim
-
-It turns out that all of this comes from the header file
-@code{traced-callback.h} which sounds very promising. You can then take a
-look at @code{mobility-model.h} and see that there is a line which confirms
-this hunch:
-
-@verbatim
- #include "ns3/traced-callback.h"
-@end verbatim
-
-Of course, you could have gone at this from the other direction and started
-by looking at the includes in @code{mobility-model.h} and noticing the
-include of @code{traced-callback.h} and inferring that this must be the file
-you want.
-
-In either case, the next step is to take a look at @code{src/core/traced-callback.h}
-in your favorite editor to see what is happening.
-
-You will see a comment at the top of the file that should be comforting:
-
-@verbatim
- An ns3::TracedCallback has almost exactly the same API as a normal ns3::Callback but
- instead of forwarding calls to a single function (as an ns3::Callback normally does),
- it forwards calls to a chain of ns3::Callback.
-@end verbatim
-
-This should sound very familiar and let you know you are on the right track.
-
-Just after this comment, you will find,
-
-@verbatim
- template<typename T1 = empty, typename T2 = empty,
- typename T3 = empty, typename T4 = empty,
- typename T5 = empty, typename T6 = empty,
- typename T7 = empty, typename T8 = empty>
- class TracedCallback
- {
- ...
-@end verbatim
-
-This tells you that TracedCallback is a templated class. It has eight possible
-type parameters with default values. Go back and compare this with the
-declaration you are trying to understand:
-
-@verbatim
- TracedCallback<Ptr<const MobilityModel> > m_courseChangeTrace;
-@end verbatim
-
-The @code{typename T1} in the templated class declaration corresponds to the
-@code{Ptr<const MobilityModel>} in the declaration above. All of the other
-type parameters are left as defaults. Looking at the constructor really
-doesn't tell you much. The one place where you have seen a connection made
-between your Callback function and the tracing system is in the @code{Connect}
-and @code{ConnectWithoutContext} functions. If you scroll down, you will see
-a @code{ConnectWithoutContext} method here:
-
-@verbatim
- template<typename T1, typename T2,
- typename T3, typename T4,
- typename T5, typename T6,
- typename T7, typename T8>
- void
- TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
- {
- Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
- cb.Assign (callback);
- m_callbackList.push_back (cb);
- }
-@end verbatim
-
-You are now in the belly of the beast. When the template is instantiated for
-the declaration above, the compiler will replace @code{T1} with
-@code{Ptr<const MobilityModel>}.
-
-@verbatim
- void
- TracedCallback<Ptr<const MobilityModel>::ConnectWithoutContext ... cb
- {
- Callback<void, Ptr<const MobilityModel> > cb;
- cb.Assign (callback);
- m_callbackList.push_back (cb);
- }
-@end verbatim
-
-You can now see the implementation of everything we've been talking about. The
-code creates a Callback of the right type and assigns your function to it. This
-is the equivalent of the @code{pfi = MyFunction} we discussed at the start of
-this section. The code then adds the Callback to the list of Callbacks for
-this source. The only thing left is to look at the definition of Callback.
-Using the same grep trick as we used to find @code{TracedCallback}, you will be
-able to find that the file @code{./core/callback.h} is the one we need to look at.
-
-If you look down through the file, you will see a lot of probably almost
-incomprehensible template code. You will eventually come to some Doxygen for
-the Callback template class, though. Fortunately, there is some English:
-
-@verbatim
- This class template implements the Functor Design Pattern.
- It is used to declare the type of a Callback:
- - the first non-optional template argument represents
- the return type of the callback.
- - the second optional template argument represents
- the type of the first argument to the callback.
- - the third optional template argument represents
- the type of the second argument to the callback.
- - the fourth optional template argument represents
- the type of the third argument to the callback.
- - the fifth optional template argument represents
- the type of the fourth argument to the callback.
- - the sixth optional template argument represents
- the type of the fifth argument to the callback.
-@end verbatim
-
-We are trying to figure out what the
-
-@verbatim
- Callback<void, Ptr<const MobilityModel> > cb;
-@end verbatim
-
-declaration means. Now we are in a position to understand that the first
-(non-optional) parameter, @code{void}, represents the return type of the
-Callback. The second (non-optional) parameter, @code{Ptr<const MobilityModel>}
-represents the first argument to the callback.
-
-The Callback in question is your function to receive the trace events. From
-this you can infer that you need a function that returns @code{void} and takes
-a @code{Ptr<const MobilityModel>}. For example,
-
-@verbatim
- void
- CourseChangeCallback (Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-That's all you need if you want to @code{Config::ConnectWithoutContext}. If
-you want a context, you need to @code{Config::Connect} and use a Callback
-function that takes a string context. This is because the @code{Connect}
-function will provide the context for you. You'll need:
-
-@verbatim
- void
- CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-If you want to ensure that your @code{CourseChangeCallback} is only visible
-in your local file, you can add the keyword @code{static} and come up with:
-
-@verbatim
- static void
- CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
- {
- ...
- }
-@end verbatim
-
-which is exactly what we used in the @code{third.cc} example. Perhaps you
-should now go back and reread the previous section (Take My Word for It).
-
-If you are interested in more details regarding the implementation of
-Callbacks, feel free to take a look at the @code{ns-3} manual. They are one
-of the most frequently used constructs in the low-level parts of @code{ns-3}.
-It is, in my opinion, a quite elegant thing.
-
-@subsection What About TracedValue?
-
-Earlier in this section, we presented a simple piece of code that used a
-@code{TracedValue<int32_t>} to demonstrate the basics of the tracing code.
-We just glossed over the way to find the return type and formal arguments
-for the @code{TracedValue}. Rather than go through the whole exercise, we
-will just point you at the correct file, @code{src/core/traced-value.h} and
-to the important piece of code:
-
-@verbatim
- template <typename T>
- class TracedValue
- {
- public:
- ...
- void Set (const T &v) {
- if (m_v != v)
- {
- m_cb (m_v, v);
- m_v = v;
- }
- }
- ...
- private:
- T m_v;
- TracedCallback<T,T> m_cb;
- };
-@end verbatim
-
-Here you see that the @code{TracedValue} is templated, of course. In the simple
-example case at the start of the section, the typename is int32_t. This means
-that the member variable being traced (@code{m_v} in the private section of the
-class) will be an @code{int32_t m_v}. The @code{Set} method will take a
-@code{const int32_t &v} as a parameter. You should now be able to understand
-that the @code{Set} code will fire the @code{m_cb} callback with two parameters:
-the first being the current value of the @code{TracedValue}; and the second
-being the new value being set.
-
-The callback, @code{m_cb} is declared as a @code{TracedCallback<T, T>} which
-will correspond to a @code{TracedCallback<int32_t, int32_t>} when the class is
-instantiated.
-
-Recall that the callback target of a TracedCallback always returns @code{void}.
-Further recall that there is a one-to-one correspondence between the template
-parameter list in the declaration and the formal arguments of the callback
-function. Therefore the callback will need to have a function signature that
-looks like:
-
-@verbatim
- void
- MyCallback (int32_t oldValue, int32_t newValue)
- {
- ...
- }
-@end verbatim
-
-It probably won't surprise you that this is exactly what we provided in that
-simple example we covered so long ago:
-
-@verbatim
- void
- IntTrace (int32_t oldValue, int32_t newValue)
- {
- std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
- }
-@end verbatim
-
-@c ============================================================================
-@c A Real Example
-@c ============================================================================
-@node A Real Example
-@section A Real Example
-
-Let's do an example taken from one of the best-known books on TCP around.
-``TCP/IP Illustrated, Volume 1: The Protocols,'' by W. Richard Stevens is a
-classic. I just flipped the book open and ran across a nice plot of both the
-congestion window and sequence numbers versus time on page 366. Stevens calls
-this, ``Figure 21.10. Value of cwnd and send sequence number while data is being
-transmitted.'' Let's just recreate the cwnd part of that plot in @command{ns-3}
-using the tracing system and @code{gnuplot}.
-
-@subsection Are There Trace Sources Available?
-
-The first thing to think about is how we want to get the data out. What is it
-that we need to trace? The first thing to do is to consult ``The list of all
-trace sources'' to see what we have to work with. Recall that this is found
-in the @command{ns-3} Doxygen in the ``Core'' Module section. If you scroll
-through the list, you will eventually find:
-
-@verbatim
- ns3::TcpSocketImpl
- CongestionWindow: The TCP connection's congestion window
-@end verbatim
-
-It turns out that the @command{ns-3} TCP implementation lives (mostly) in the
-file @code{src/internet-stack/tcp-socket-impl.cc}. If you don't know this a
-priori, you can use the recursive grep trick:
-
-@verbatim
- find . -name '*.cc' | xargs grep -i tcp
-@end verbatim
-
-You will find page after page of instances of tcp pointing you to that file.
-
-If you open @code{src/internet-stack/tcp-socket-impl.cc} in your favorite
-editor, you will see right up at the top of the file, the following declarations:
-
-@verbatim
- TypeId
- TcpSocketImpl::GetTypeId ()
- {
- static TypeId tid = TypeId(``ns3::TcpSocketImpl'')
- .SetParent<TcpSocket> ()
- .AddTraceSource (``CongestionWindow'',
- ``The TCP connection's congestion window'',
- MakeTraceSourceAccessor (&TcpSocketImpl::m_cWnd))
- ;
- return tid;
- }
-@end verbatim
-
-This should tell you to look for the declaration of @code{m_cWnd} in the header
-file @code{src/internet-stack/tcp-socket-impl.h}. If you open this file in your
-favorite editor, you will find:
-
-@verbatim
- TracedValue<uint32_t> m_cWnd; //Congestion window
-@end verbatim
-
-You should now understand this code completely. If we have a pointer to the
-@code{TcpSocketImpl}, we can @code{TraceConnect} to the ``CongestionWindow'' trace
-source if we provide an appropriate callback target. This is the same kind of
-trace source that we saw in the simple example at the start of this section,
-except that we are talking about @code{uint32_t} instead of @code{int32_t}.
-
-We now know that we need to provide a callback that returns void and takes
-two @code{uint32_t} parameters, the first being the old value and the second
-being the new value:
-
-@verbatim
- void
- CwndTrace (uint32_t oldValue, uint32_t newValue)
- {
- ...
- }
-@end verbatim
-
-@subsection What Script to Use?
-
-It's always best to try and find working code laying around that you can
-modify, rather than starting from scratch. So the first order of business now
-is to find some code that already hooks the ``CongestionWindow'' trace source
-and see if we can modify it. As usual, grep is your friend:
-
-@verbatim
- find . -name '*.cc' | xargs grep CongestionWindow
-@end verbatim
-
-This will point out a couple of promising candidates:
-@code{examples/tcp/tcp-large-transfer.cc} and
-@code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc}.
-
-We haven't visited any of the test code yet, so let's take a look there. You
-will typically find that test code is fairly minimal, so this is probably a
-very good bet. Open @code{src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc} in your
-favorite editor and search for ``CongestionWindow''. You will find,
-
-@verbatim
- ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
- MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
-@end verbatim
-
-This should look very familiar to you. We mentioned above that if we had a
-pointer to the @code{TcpSocketImpl}, we could @code{TraceConnect} to the
-``CongestionWindow'' trace source. That's exactly what we have here; so it
-turns out that this line of code does exactly what we want. Let's go ahead
-and extract the code we need from this function
-(@code{Ns3TcpCwndTestCase1::DoRun (void)}). If you look at this function,
-you will find that it looks just like an @code{ns-3} script. It turns out that
-is exactly what it is. It is a script run by the test framework, so we can just
-pull it out and wrap it in @code{main} instead of in @code{DoRun}. Rather than
-walk through this, step, by step, we have provided the file that results from
-porting this test back to a native @code{ns-3} script --
-@code{examples/tutorial/fifth.cc}.
-
-@subsection A Common Problem and Solution
-
-The @code{fifth.cc} example demonstrates an extremely important rule that you
-must understand before using any kind of @code{Attribute}: you must ensure
-that the target of a @code{Config} command exists before trying to use it.
-This is no different than saying an object must be instantiated before trying
-to call it. Although this may seem obvious when stated this way, it does
-trip up many people trying to use the system for the first time.
-
-Let's return to basics for a moment. There are three basic time periods that
-exist in any @command{ns-3} script. The first time period is sometimes called
-``Configuration Time'' or ``Setup Time,'' and is in force during the period
-when the @code{main} function of your script is running, but before
-@code{Simulator::Run} is called. The second time period is sometimes called
-``Simulation Time'' and is in force during the time period when
-@code{Simulator::Run} is actively executing its events. After it completes
-executing the simulation, @code{Simulator::Run} will return control back to
-the @code{main} function. When this happens, the script enters what can be
-called ``Teardown Time,'' which is when the structures and objects created
-during setup and taken apart and released.
-
-Perhaps the most common mistake made in trying to use the tracing system is
-assuming that entities constructed dynamically during simulation time are
-available during configuration time. In particular, an @command{ns-3}
-@code{Socket} is a dynamic object often created by @code{Applications} to
-communicate between @code{Nodes}. An @command{ns-3} @code{Application}
-always has a ``Start Time'' and a ``Stop Time'' associated with it. In the
-vast majority of cases, an @code{Application} will not attempt to create
-a dynamic object until its @code{StartApplication} method is called at some
-``Start Time''. This is to ensure that the simulation is completely
-configured before the app tries to do anything (what would happen if it tried
-to connect to a node that didn't exist yet during configuration time). The
-answer to this issue is to 1) create a simulator event that is run after the
-dynamic object is created and hook the trace when that event is executed; or
-2) create the dynamic object at configuration time, hook it then, and give
-the object to the system to use during simulation time. We took the second
-approach in the @code{fifth.cc} example. This decision required us to create
-the @code{MyApp} @code{Application}, the entire purpose of which is to take
-a @code{Socket} as a parameter.
-
-@subsection A fifth.cc Walkthrough
-
-Now, let's take a look at the example program we constructed by dissecting
-the congestion window test. Open @code{examples/tutorial/fifth.cc} in your
-favorite editor. You should see some familiar looking code:
-
-@verbatim
- /* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */
- /*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <fstream>
- #include "ns3/core-module.h"
- #include "ns3/common-module.h"
- #include "ns3/simulator-module.h"
- #include "ns3/node-module.h"
- #include "ns3/helper-module.h"
-
- using namespace ns3;
-
- NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
-@end verbatim
-
-This has all been covered, so we won't rehash it. The next lines of source are
-the network illustration and a comment addressing the problem described above
-with @code{Socket}.
-
-@verbatim
- // ===========================================================================
- //
- // node 0 node 1
- // +----------------+ +----------------+
- // | ns-3 TCP | | ns-3 TCP |
- // +----------------+ +----------------+
- // | 10.1.1.1 | | 10.1.1.2 |
- // +----------------+ +----------------+
- // | point-to-point | | point-to-point |
- // +----------------+ +----------------+
- // | |
- // +---------------------+
- // 5 Mbps, 2 ms
- //
- //
- // We want to look at changes in the ns-3 TCP congestion window. We need
- // to crank up a flow and hook the CongestionWindow attribute on the socket
- // of the sender. Normally one would use an on-off application to generate a
- // flow, but this has a couple of problems. First, the socket of the on-off
- // application is not created until Application Start time, so we wouldn't be
- // able to hook the socket (now) at configuration time. Second, even if we
- // could arrange a call after start time, the socket is not public so we
- // couldn't get at it.
- //
- // So, we can cook up a simple version of the on-off application that does what
- // we want. On the plus side we don't need all of the complexity of the on-off
- // application. On the minus side, we don't have a helper, so we have to get
- // a little more involved in the details, but this is trivial.
- //
- // So first, we create a socket and do the trace connect on it; then we pass
- // this socket into the constructor of our simple application which we then
- // install in the source node.
- // ===========================================================================
- //
-@end verbatim
-
-This should also be self-explanatory.
-
-The next part is the declaration of the @code{MyApp} @code{Application} that
-we put together to allow the @code{Socket} to be created at configuration time.
-
-@verbatim
- class MyApp : public Application
- {
- public:
-
- MyApp ();
- virtual ~MyApp();
-
- void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize,
- uint32_t nPackets, DataRate dataRate);
-
- private:
- virtual void StartApplication (void);
- virtual void StopApplication (void);
-
- void ScheduleTx (void);
- void SendPacket (void);
-
- Ptr<Socket> m_socket;
- Address m_peer;
- uint32_t m_packetSize;
- uint32_t m_nPackets;
- DataRate m_dataRate;
- EventId m_sendEvent;
- bool m_running;
- uint32_t m_packetsSent;
- };
-@end verbatim
-
-You can see that this class inherits from the @command{ns-3} @code{Application}
-class. Take a look at @code{src/node/application.h} if you are interested in
-what is inherited. The @code{MyApp} class is obligated to override the
-@code{StartApplication} and @code{StopApplication} methods. These methods are
-automatically called when @code{MyApp} is required to start and stop sending
-data during the simulation.
-
-@subsubsection How Applications are Started and Stopped (optional)
-
-It is worthwhile to spend a bit of time explaining how events actually get
-started in the system. This is another fairly deep explanation, and can be
-ignored if you aren't planning on venturing down into the guts of the system.
-It is useful, however, in that the discussion touches on how some very important
-parts of @code{ns-3} work and exposes some important idioms. If you are
-planning on implementing new models, you probably want to understand this
-section.
-
-The most common way to start pumping events is to start an @code{Application}.
-This is done as the result of the following (hopefully) familar lines of an
-@command{ns-3} script:
-
-@verbatim
- ApplicationContainer apps = ...
- apps.Start (Seconds (1.0));
- apps.Stop (Seconds (10.0));
-@end verbatim
-
-The application container code (see @code{src/helper/application-container.h} if
-you are interested) loops through its contained applications and calls,
-
-@verbatim
- app->SetStartTime (startTime);
-@end verbatim
-
-as a result of the @code{apps.Start} call and
-
-@verbatim
- app->SetStopTime (stopTime);
-@end verbatim
-
-as a result of the @code{apps.Stop} call.
-
-The ultimate result of these calls is that we want to have the simulator
-automatically make calls into our @code{Applications} to tell them when to
-start and stop. In the case of @code{MyApp}, it inherits from class
-@code{Application} and overrides @code{StartApplication}, and
-@code{StopApplication}. These are the functions that will be called by
-the simulator at the appropriate time. In the case of @code{MyApp} you
-will find that @code{MyApp::StartApplication} does the initial @code{Bind},
-and @code{Connect} on the socket, and then starts data flowing by calling
-@code{MyApp::SendPacket}. @code{MyApp::StopApplication} stops generating
-packets by cancelling any pending send events and closing the socket.
-
-One of the nice things about @command{ns-3} is that you can completely
-ignore the implementation details of how your @code{Application} is
-``automagically'' called by the simulator at the correct time. But since
-we have already ventured deep into @command{ns-3} already, let's go for it.
-
-If you look at @code{src/node/application.cc} you will find that the
-@code{SetStartTime} method of an @code{Application} just sets the member
-variable @code{m_startTime} and the @code{SetStopTime} method just sets
-@code{m_stopTime}. From there, without some hints, the trail will probably
-end.
-
-The key to picking up the trail again is to know that there is a global
-list of all of the nodes in the system. Whenever you create a node in
-a simulation, a pointer to that node is added to the global @code{NodeList}.
-
-Take a look at @code{src/node/node-list.cc} and search for
-@code{NodeList::Add}. The public static implementation calls into a private
-implementation called @code{NodeListPriv::Add}. This is a relatively common
-idom in @command{ns-3}. So, take a look at @code{NodeListPriv::Add}. There
-you will find,
-
-@verbatim
- Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Start, node);
-@end verbatim
-
-This tells you that whenever a @code{Node} is created in a simulation, as
-a side-effect, a call to that node's @code{Start} method is scheduled for
-you that happens at time zero. Don't read too much into that name, yet.
-It doesn't mean that the node is going to start doing anything, it can be
-interpreted as an informational call into the @code{Node} telling it that
-the simulation has started, not a call for action telling the @code{Node}
-to start doing something.
-
-So, @code{NodeList::Add} indirectly schedules a call to @code{Node::Start}
-at time zero to advise a new node that the simulation has started. If you
-look in @code{src/node/node.h} you will, however, not find a method called
-@code{Node::Start}. It turns out that the @code{Start} method is inherited
-from class @code{Object}. All objects in the system can be notified when
-the simulation starts, and objects of class @code{Node} are just one kind
-of those objects.
-
-Take a look at @code{src/core/object.cc} next and search for @code{Object::Start}.
-This code is not as straightforward as you might have expected since
-@command{ns-3} @code{Objects} support aggregation. The code in
-@code{Object::Start} then loops through all of the objects that have been
-aggregated together and calls their @code{DoStart} method. This is another
-idiom that is very common in @command{ns-3}. There is a public API method,
-that stays constant across implementations, that calls a private implementation
-method that is inherited and implemented by subclasses. The names are typically
-something like @code{MethodName} for the public API and @code{DoMethodName} for
-the private API.
-
-This tells us that we should look for a @code{Node::DoStart} method in
-@code{src/node/node.cc} for the method that will continue our trail. If you
-locate the code, you will find a method that loops through all of the devices
-in the node and then all of the applications in the node calling
-@code{device->Start} and @code{application->Start} respectively.
-
-You may already know that classes @code{Device} and @code{Application} both
-inherit from class @code{Object} and so the next step will be to look at
-what happens when @code{Application::DoStart} is called. Take a look at
-@code{src/node/application.cc} and you will find:
-
-@verbatim
- void
- Application::DoStart (void)
- {
- m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, this);
- if (m_stopTime != TimeStep (0))
- {
- m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, this);
- }
- Object::DoStart ();
- }
-@end verbatim
-
-Here, we finally come to the end of the trail. If you have kept it all straight,
-when you implement an @command{ns-3} @code{Application}, your new application
-inherits from class @code{Application}. You override the @code{StartApplication}
-and @code{StopApplication} methods and provide mechanisms for starting and
-stopping the flow of data out of your new @code{Application}. When a @code{Node}
-is created in the simulation, it is added to a global @code{NodeList}. The act
-of adding a node to this @code{NodeList} causes a simulator event to be scheduled
-for time zero which calls the @code{Node::Start} method of the newly added
-@code{Node} to be called when the simulation starts. Since a @code{Node} inherits
-from @code{Object}, this calls the @code{Object::Start} method on the @code{Node}
-which, in turn, calls the @code{DoStart} methods on all of the @code{Objects}
-aggregated to the @code{Node} (think mobility models). Since the @code{Node}
-@code{Object} has overridden @code{DoStart}, that method is called when the
-simulation starts. The @code{Node::DoStart} method calls the @code{Start} methods
-of all of the @code{Applications} on the node. Since @code{Applications} are
-also @code{Objects}, this causes @code{Application::DoStart} to be called. When
-@code{Application::DoStart} is called, it schedules events for the
-@code{StartApplication} and @code{StopApplication} calls on the @code{Application}.
-These calls are designed to start and stop the flow of data from the
-@code{Application}
-
-This has been another fairly long journey, but it only has to be made once, and
-you now understand another very deep piece of @command{ns-3}.
-
-@subsubsection The MyApp Application
-
-The @code{MyApp} @code{Application} needs a constructor and a destructor,
-of course:
-
-@verbatim
- MyApp::MyApp ()
- : m_socket (0),
- m_peer (),
- m_packetSize (0),
- m_nPackets (0),
- m_dataRate (0),
- m_sendEvent (),
- m_running (false),
- m_packetsSent (0)
- {
- }
-
- MyApp::~MyApp()
- {
- m_socket = 0;
- }
-@end verbatim
-
-The existence of the next bit of code is the whole reason why we wrote this
-@code{Application} in the first place.
-
-@verbatim
-void
-MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize,
- uint32_t nPackets, DataRate dataRate)
-{
- m_socket = socket;
- m_peer = address;
- m_packetSize = packetSize;
- m_nPackets = nPackets;
- m_dataRate = dataRate;
-}
-@end verbatim
-
-This code should be pretty self-explanatory. We are just initializing member
-variables. The important one from the perspective of tracing is the
-@code{Ptr<Socket> socket} which we needed to provide to the application
-during configuration time. Recall that we are going to create the @code{Socket}
-as a @code{TcpSocket} (which is implemented by @code{TcpSocketImpl}) and hook
-its ``CongestionWindow'' trace source before passing it to the @code{Setup}
-method.
-
-@verbatim
- void
- MyApp::StartApplication (void)
- {
- m_running = true;
- m_packetsSent = 0;
- m_socket->Bind ();
- m_socket->Connect (m_peer);
- SendPacket ();
- }
-@end verbatim
-
-The above code is the overridden implementation @code{Application::StartApplication}
-that will be automatically called by the simulator to start our @code{Application}
-running at the appropriate time. You can see that it does a @code{Socket} @code{Bind}
-operation. If you are familiar with Berkeley Sockets this shouldn't be a surprise.
-It performs the required work on the local side of the connection just as you might
-expect. The following @code{Connect} will do what is required to establish a connection
-with the TCP at @code{Address} m_peer. It should now be clear why we need to defer
-a lot of this to simulation time, since the @code{Connect} is going to need a fully
-functioning network to complete. After the @code{Connect}, the @code{Application}
-then starts creating simulation events by calling @code{SendPacket}.
-
-The next bit of code explains to the @code{Application} how to stop creating
-simulation events.
-
-@verbatim
- void
- MyApp::StopApplication (void)
- {
- m_running = false;
-
- if (m_sendEvent.IsRunning ())
- {
- Simulator::Cancel (m_sendEvent);
- }
-
- if (m_socket)
- {
- m_socket->Close ();
- }
- }
-@end verbatim
-
-Every time a simulation event is scheduled, an @code{Event} is created. If the
-@code{Event} is pending execution or executing, its method @code{IsRunning} will
-return @code{true}. In this code, if @code{IsRunning()} returns true, we
-@code{Cancel} the event which removes it from the simulator event queue. By
-doing this, we break the chain of events that the @code{Application} is using to
-keep sending its @code{Packets} and the @code{Application} goes quiet. After we
-quiet the @code{Application} we @code{Close} the socket which tears down the TCP
-connection.
-
-The socket is actually deleted in the destructor when the @code{m_socket = 0} is
-executed. This removes the last reference to the underlying Ptr<Socket> which
-causes the destructor of that Object to be called.
-
-Recall that @code{StartApplication} called @code{SendPacket} to start the
-chain of events that describes the @code{Application} behavior.
-
-@verbatim
- void
- MyApp::SendPacket (void)
- {
- Ptr<Packet> packet = Create<Packet> (m_packetSize);
- m_socket->Send (packet);
-
- if (++m_packetsSent < m_nPackets)
- {
- ScheduleTx ();
- }
- }
-@end verbatim
-
-Here, you see that @code{SendPacket} does just that. It creates a @code{Packet}
-and then does a @code{Send} which, if you know Berkeley Sockets, is probably
-just what you expected to see.
-
-It is the responsibility of the @code{Application} to keep scheduling the
-chain of events, so the next lines call @code{ScheduleTx} to schedule another
-transmit event (a @code{SendPacket}) until the @code{Application} decides it
-has sent enough.
-
-@verbatim
- void
- MyApp::ScheduleTx (void)
- {
- if (m_running)
- {
- Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
- m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
- }
- }
-@end verbatim
-
-Here, you see that @code{ScheduleTx} does exactly that. If the @code{Application}
-is running (if @code{StopApplication} has not been called) it will schedule a
-new event, which calls @code{SendPacket} again. The alert reader will spot
-something that also trips up new users. The data rate of an @code{Application} is
-just that. It has nothing to do with the data rate of an underlying @code{Channel}.
-This is the rate at which the @code{Application} produces bits. It does not take
-into account any overhead for the various protocols or channels that it uses to
-transport the data. If you set the data rate of an @code{Application} to the same
-data rate as your underlying @code{Channel} you will eventually get a buffer overflow.
-
-@subsubsection The Trace Sinks
-
-The whole point of this exercise is to get trace callbacks from TCP indicating the
-congestion window has been updated. The next piece of code implements the
-corresponding trace sink:
-
-@verbatim
- static void
- CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
- {
- NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << ``\t'' << newCwnd);
- }
-@end verbatim
-
-This should be very familiar to you now, so we won't dwell on the details. This
-function just logs the current simulation time and the new value of the
-congestion window every time it is changed. You can probably imagine that you
-could load the resulting output into a graphics program (gnuplot or Excel) and
-immediately see a nice graph of the congestion window behavior over time.
-
-We added a new trace sink to show where packets are dropped. We are going to
-add an error model to this code also, so we wanted to demonstrate this working.
-
-@verbatim
- static void
- RxDrop (Ptr<const Packet> p)
- {
- NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
- }
-@end verbatim
-
-This trace sink will be connected to the ``PhyRxDrop'' trace source of the
-point-to-point NetDevice. This trace source fires when a packet is dropped
-by the physical layer of a @code{NetDevice}. If you take a small detour to the
-source (@code{src/devices/point-to-point/point-to-point-net-device.cc}) you will
-see that this trace source refers to @code{PointToPointNetDevice::m_phyRxDropTrace}.
-If you then look in @code{src/devices/point-to-point/point-to-point-net-device.h}
-for this member variable, you will find that it is declared as a
-@code{TracedCallback<Ptr<const Packet> >}. This should tell you that the
-callback target should be a function that returns void and takes a single
-parameter which is a @code{Ptr<const Packet>} -- just what we have above.
-
-@subsubsection The Main Program
-
-The following code should be very familiar to you by now:
-
-@verbatim
- int
- main (int argc, char *argv[])
- {
- NodeContainer nodes;
- nodes.Create (2);
-
- PointToPointHelper pointToPoint;
- pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
- pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
-
- NetDeviceContainer devices;
- devices = pointToPoint.Install (nodes);
-@end verbatim
-
-This creates two nodes with a point-to-point channel between them, just as
-shown in the illustration at the start of the file.
-
-The next few lines of code show something new. If we trace a connection that
-behaves perfectly, we will end up with a monotonically increasing congestion
-window. To see any interesting behavior, we really want to introduce link
-errors which will drop packets, cause duplicate ACKs and trigger the more
-interesting behaviors of the congestion window.
-
-@command{ns-3} provides @code{ErrorModel} objects which can be attached to
-@code{Channels}. We are using the @code{RateErrorModel} which allows us
-to introduce errors into a @code{Channel} at a given @emph{rate}.
-
-@verbatim
- Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> (
- "RanVar", RandomVariableValue (UniformVariable (0., 1.)),
- "ErrorRate", DoubleValue (0.00001));
- devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
-@end verbatim
-
-The above code instantiates a @code{RateErrorModel} Object. Rather than
-using the two-step process of instantiating it and then setting Attributes,
-we use the convenience function @code{CreateObjectWithAttributes} which
-allows us to do both at the same time. We set the ``RanVar''
-@code{Attribute} to a random variable that generates a uniform distribution
-from 0 to 1. We also set the ``ErrorRate'' @code{Attribute}.
-We then set the resulting instantiated @code{RateErrorModel} as the error
-model used by the point-to-point @code{NetDevice}. This will give us some
-retransmissions and make our plot a little more interesting.
-
-@verbatim
- InternetStackHelper stack;
- stack.Install (nodes);
-
- Ipv4AddressHelper address;
- address.SetBase (``10.1.1.0'', ``255.255.255.252'');
- Ipv4InterfaceContainer interfaces = address.Assign (devices);
-@end verbatim
-
-The above code should be familiar. It installs internet stacks on our two
-nodes and creates interfaces and assigns IP addresses for the point-to-point
-devices.
-
-Since we are using TCP, we need something on the destination node to receive
-TCP connections and data. The @code{PacketSink} @code{Application} is commonly
-used in @command{ns-3} for that purpose.
-
-@verbatim
- uint16_t sinkPort = 8080;
- Address sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
- PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
- InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
- ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
- sinkApps.Start (Seconds (0.));
- sinkApps.Stop (Seconds (20.));
-@end verbatim
-
-This should all be familiar, with the exception of,
-
-@verbatim
- PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
- InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
-@end verbatim
-
-This code instantiates a @code{PacketSinkHelper} and tells it to create sockets
-using the class @code{ns3::TcpSocketFactory}. This class implements a design
-pattern called ``object factory'' which is a commonly used mechanism for
-specifying a class used to create objects in an abstract way. Here, instead of
-having to create the objects themselves, you provide the @code{ PacketSinkHelper}
-a string that specifies a @code{TypeId} string used to create an object which
-can then be used, in turn, to create instances of the Objects created by the
-factory.
-
-The remaining parameter tells the @code{Application} which address and port it
-should @code{Bind} to.
-
-The next two lines of code will create the socket and connect the trace source.
-
-@verbatim
- Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
- TcpSocketFactory::GetTypeId ());
- ns3TcpSocket->TraceConnectWithoutContext (``CongestionWindow'',
- MakeCallback (&CwndChange));
-@end verbatim
-
-The first statement calls the static member function @code{Socket::CreateSocket}
-and provides a @code{Node} and an explicit @code{TypeId} for the object factory
-used to create the socket. This is a slightly lower level call than the
-@code{PacketSinkHelper} call above, and uses an explicit C++ type instead of
-one referred to by a string. Otherwise, it is conceptually the same thing.
-
-Once the @code{TcpSocket} is created and attached to the @code{Node}, we can
-use @code{TraceConnectWithoutContext} to connect the CongestionWindow trace
-source to our trace sink.
-
-Recall that we coded an @code{Application} so we could take that @code{Socket}
-we just made (during configuration time) and use it in simulation time. We now
-have to instantiate that @code{Application}. We didn't go to any trouble to
-create a helper to manage the @code{Application} so we are going to have to
-create and install it ``manually''. This is actually quite easy:
-
-@verbatim
- Ptr<MyApp> app = CreateObject<MyApp> ();
- app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
- nodes.Get (0)->AddApplication (app);
- app->Start (Seconds (1.));
- app->Stop (Seconds (20.));
-@end verbatim
-
-The first line creates an @code{Object} of type @code{MyApp} -- our
-@code{Application}. The second line tells the @code{Application} what
-@code{Socket} to use, what address to connect to, how much data to send
-at each send event, how many send events to generate and the rate at which
-to produce data from those events.
-
-Next, we manually add the @code{MyApp Application} to the source node
-and explicitly call the @code{Start} and @code{Stop} methods on the
-@code{Application} to tell it when to start and stop doing its thing.
-
-We need to actually do the connect from the receiver point-to-point @code{NetDevice}
-to our callback now.
-
-@verbatim
- devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
-@end verbatim
-
-It should now be obvious that we are getting a reference to the receiving
-@code{Node NetDevice} from its container and connecting the trace source defined
-by the attribute ``PhyRxDrop'' on that device to the trace sink @code{RxDrop}.
-
-Finally, we tell the simulator to override any @code{Applications} and just
-stop processing events at 20 seconds into the simulation.
-
-@verbatim
- Simulator::Stop (Seconds(20));
- Simulator::Run ();
- Simulator::Destroy ();
-
- return 0;
- }
-@end verbatim
-
-Recall that as soon as @code{Simulator::Run} is called, configuration time
-ends, and simulation time begins. All of the work we orchestrated by
-creating the @code{Application} and teaching it how to connect and send
-data actually happens during this function call.
-
-As soon as @code{Simulator::Run} returns, the simulation is complete and
-we enter the teardown phase. In this case, @code{Simulator::Destroy} takes
-care of the gory details and we just return a success code after it completes.
-
-@subsection Running fifth.cc
-
-Since we have provided the file @code{fifth.cc} for you, if you have built
-your distribution (in debug mode since it uses NS_LOG -- recall that optimized
-builds optimize out NS_LOGs) it will be waiting for you to run.
-
-@verbatim
- ./waf --run fifth
- Waf: Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build
- Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
- 'build' finished successfully (0.684s)
- 1.20919 1072
- 1.21511 1608
- 1.22103 2144
- ...
- 1.2471 8040
- 1.24895 8576
- 1.2508 9112
- RxDrop at 1.25151
- ...
-@end verbatim
-
-You can probably see immediately a downside of using prints of any kind in your
-traces. We get those extraneous waf messages printed all over our interesting
-information along with those RxDrop messages. We will remedy that soon, but I'm
-sure you can't wait to see the results of all of this work. Let's redirect that
-output to a file called @code{cwnd.dat}:
-
-@verbatim
- ./waf --run fifth > cwnd.dat 2>&1
-@end verbatim
-
-Now edit up ``cwnd.dat'' in your favorite editor and remove the waf build status
-and drop lines, leaving only the traced data (you could also comment out the
-@code{TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));} in the
-script to get rid of the drop prints just as easily.
-
-You can now run gnuplot (if you have it installed) and tell it to generate some
-pretty pictures:
-
-@verbatim
- gnuplot> set terminal png size 640,480
- gnuplot> set output "cwnd.png"
- gnuplot> plot "cwnd.dat" using 1:2 title 'Congestion Window' with linespoints
- gnuplot> exit
-@end verbatim
-
-You should now have a graph of the congestion window versus time sitting in the
-file ``cwnd.png'' in all of its glory, that looks like:
-
-@sp 1
-@center @image{figures/cwnd,,,,png}
-
-@subsection Using Mid-Level Helpers
-
-In the previous section, we showed how to hook a trace source and get hopefully
-interesting information out of a simulation. Perhaps you will recall that we
-called logging to the standard output using @code{std::cout} a ``Blunt Instrument''
-much earlier in this chapter. We also wrote about how it was a problem having
-to parse the log output in order to isolate interesting information. It may
-have occurred to you that we just spent a lot of time implementing an example
-that exhibits all of the problems we purport to fix with the @code{ns-3} tracing
-system! You would be correct. But, bear with us. We're not done yet.
-
-One of the most important things we want to do is to is to have the ability to
-easily control the amount of output coming out of the simulation; and we also
-want to save those data to a file so we can refer back to it later. We can use
-the mid-level trace helpers provided in @code{ns-3} to do just that and complete
-the picture.
-
-We provide a script that writes the cwnd change and drop events developed in
-the example @code{fifth.cc } to disk in separate files. The cwnd changes are
-stored as a tab-separated ASCII file and the drop events are stored in a pcap
-file. The changes to make this happen are quite small.
-
-@subsubsection A sixth.cc Walkthrough
-
-Let's take a look at the changes required to go from @code{fifth.cc} to
-@code{sixth.cc}. Open @code{examples/tutorial/fifth.cc} in your favorite
-editor. You can see the first change by searching for CwndChange. You will
-find that we have changed the signatures for the trace sinks and have added
-a single line to each sink that writes the traced information to a stream
-representing a file.
-
-@verbatim
- static void
- CwndChange (Ptr<OutputStreamWrapper> stream, uint32_t oldCwnd, uint32_t newCwnd)
- {
- NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
- *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
- }
-
- static void
- RxDrop (Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
- {
- NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
- file->Write(Simulator::Now(), p);
- }
-@end verbatim
-
-We have added a ``stream'' parameter to the @code{CwndChange} trace sink.
-This is an object that holds (keeps safely alive) a C++ output stream. It
-turns out that this is a very simple object, but one that manages lifetime
-issues for the stream and solves a problem that even experienced C++ users
-run into. It turns out that the copy constructor for ostream is marked
-private. This means that ostreams do not obey value semantics and cannot
-be used in any mechanism that requires the stream to be copied. This includes
-the @command{ns-3} callback system, which as you may recall, requires objects
-that obey value semantics. Further notice that we have added the following
-line in the @code{CwndChange} trace sink implementation:
-
-@verbatim
- *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
-@end verbatim
-
-This would be very familiar code if you replaced @code{*stream->GetStream ()}
-with @code{std::cout}, as in:
-
-@verbatim
- std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
-@end verbatim
-
-This illustrates that the @code{Ptr<OutputStreamWrapper>} is really just
-carrying around a @code{std::ofstream} for you, and you can use it here like
-any other output stream.
-
-A similar situation happens in @code{RxDrop} except that the object being
-passed around (a @code{Ptr<PcapFileWrapper>}) represents a pcap file. There
-is a one-liner in the trace sink to write a timestamp and the contents of the
-packet being dropped to the pcap file:
-
-@verbatim
- file->Write(Simulator::Now(), p);
-@end verbatim
-
-Of course, if we have objects representing the two files, we need to create
-them somewhere and also cause them to be passed to the trace sinks. If you
-look in the @code{main} function, you will find new code to do just that:
-
-@verbatim
- AsciiTraceHelper asciiTraceHelper;
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
- ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
-
- ...
-
- PcapHelper pcapHelper;
- Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", std::ios::out, PcapHelper::DLT_PPP);
- devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
-@end verbatim
-
-In the first section of the code snippet above, we are creating the ASCII
-trace file, creating an object responsible for managing it and using a
-variant of the callback creation function to arrange for the object to be
-passed to the sink. Our ASCII trace helpers provide a rich set of
-functions to make using text (ASCII) files easy. We are just going to
-illustrate the use of the file stream creation function here.
-
-The @code{CreateFileStream{}} function is basically going to instantiate
-a std::ofstream object and create a new file (or truncate an existing file).
-This ofstream is packaged up in an @code{ns-3} object for lifetime management
-and copy constructor issue resolution.
-
-We then take this @code{ns-3} object representing the file and pass it to
-@code{MakeBoundCallback()}. This function creates a callback just like
-@code{MakeCallback()}, but it ``binds'' a new value to the callback. This
-value is added to the callback before it is called.
-
-Essentially, @code{MakeBoundCallback(&CwndChange, stream)} causes the trace
-source to add the additional ``stream'' parameter to the front of the formal
-parameter list before invoking the callback. This changes the required
-signature of the @code{CwndChange} sink to match the one shown above, which
-includes the ``extra'' parameter @code{Ptr<OutputStreamWrapper> stream}.
-
-In the second section of code in the snippet above, we instantiate a
-@code{PcapHelper} to do the same thing for our pcap trace file that we did
-with the @code{AsciiTraceHelper}. The line of code,
-
-@verbatim
- Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP);
-@end verbatim
-
-creates a pcap file named ``sixth.pcap'' with file mode ``w''. This means that
-the new file is to truncated if an existing file with that name is found. The
-final parameter is the ``data link type'' of the new pcap file. These are
-the same as the pcap library data link types defined in @code{bpf.h} if you are
-familar with pcap. In this case, @code{DLT_PPP} indicates that the pcap file
-is going to contain packets prefixed with point to point headers. This is true
-since the packets are coming from our point-to-point device driver. Other
-common data link types are DLT_EN10MB (10 MB Ethernet) appropriate for csma
-devices and DLT_IEEE802_11 (IEEE 802.11) appropriate for wifi devices. These
-are defined in @code{src/helper/trace-helper.h"} if you are interested in seeing
-the list. The entries in the list match those in @code{bpf.h} but we duplicate
-them to avoid a pcap source dependence.
-
-A @code{ns-3} object representing the pcap file is returned from @code{CreateFile}
-and used in a bound callback exactly as it was in the ascii case.
-
-An important detour: It is important to notice that even though both of these
-objects are declared in very similar ways,
-
-@verbatim
- Ptr<PcapFileWrapper> file ...
- Ptr<OutputStreamWrapper> stream ...
-@end verbatim
-
-The underlying objects are entirely different. For example, the
-Ptr<PcapFileWrapper> is a smart pointer to an @command{ns-3} Object that is a
-fairly heaviweight thing that supports @code{Attributes} and is integrated into
-the config system. The Ptr<OutputStreamWrapper>, on the other hand, is a smart
-pointer to a reference counted object that is a very lightweight thing.
-Remember to always look at the object you are referencing before making any
-assumptions about the ``powers'' that object may have.
-
-For example, take a look at @code{src/common/pcap-file-object.h} in the
-distribution and notice,
-
-@verbatim
- class PcapFileWrapper : public Object
-@end verbatim
-
-that class @code{PcapFileWrapper} is an @command{ns-3} Object by virtue of
-its inheritance. Then look at @code{src/common/output-stream-wrapper.h} and
-notice,
-
-@verbatim
- class OutputStreamWrapper : public SimpleRefCount<OutputStreamWrapper>
-@end verbatim
-
-that this object is not an @command{ns-3} Object at all, it is ``merely'' a
-C++ object that happens to support intrusive reference counting.
-
-The point here is that just because you read Ptr<something> it does not necessarily
-mean that ``something'' is an @command{ns-3} Object on which you can hang @command{ns-3}
-@code{Attributes}, for example.
-
-Now, back to the example. If you now build and run this example,
-
-@verbatim
- ./waf --run sixth
-@end verbatim
-
-you will see the same messages appear as when you ran ``fifth'', but two new
-files will appear in the top-level directory of your @code{ns-3} distribution.
-
-@verbatim
- sixth.cwnd sixth.pcap
-@end verbatim
-
-Since ``sixth.cwnd'' is an ASCII text file, you can view it with @code{cat}
-or your favorite file viewer.
-
-@verbatim
- 1.20919 536 1072
- 1.21511 1072 1608
- ...
- 9.30922 8893 8925
- 9.31754 8925 8957
-@end verbatim
-
-You have a tab separated file with a timestamp, an old congestion window and a
-new congestion window suitable for directly importing into your plot program.
-There are no extraneous prints in the file, no parsing or editing is required.
-
-Since ``sixth.pcap'' is a pcap file, you can fiew it with @code{tcpdump}.
-
-@verbatim
- reading from file ../../sixth.pcap, link-type PPP (PPP)
- 1.251507 IP 10.1.1.1.49153 > 10.1.1.2.8080: . 17689:18225(536) ack 1 win 65535
- 1.411478 IP 10.1.1.1.49153 > 10.1.1.2.8080: . 33808:34312(504) ack 1 win 65535
- ...
- 7.393557 IP 10.1.1.1.49153 > 10.1.1.2.8080: . 781568:782072(504) ack 1 win 65535
- 8.141483 IP 10.1.1.1.49153 > 10.1.1.2.8080: . 874632:875168(536) ack 1 win 65535
-@end verbatim
-
-You have a pcap file with the packets that were dropped in the simulation. There
-are no other packets present in the file and there is nothing else present to
-make life difficult.
-
-It's been a long journey, but we are now at a point where we can appreciate the
-@code{ns-3} tracing system. We have pulled important events out of the middle
-of a TCP implementation and a device driver. We stored those events directly in
-files usable with commonly known tools. We did this without modifying any of the
-core code involved, and we did this in only 18 lines of code:
-
-@verbatim
- static void
- CwndChange (Ptr<OutputStreamWrapper> stream, uint32_t oldCwnd, uint32_t newCwnd)
- {
- NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
- *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
- }
-
- ...
-
- AsciiTraceHelper asciiTraceHelper;
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
- ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
-
- ...
-
- static void
- RxDrop (Ptr<PcapFileWrapper> file, Ptr<const Packet> p)
- {
- NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
- file->Write(Simulator::Now(), p);
- }
-
- ...
-
- PcapHelper pcapHelper;
- Ptr<PcapFileWrapper> file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP);
- devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));
-@end verbatim
-
-@c ============================================================================
-@c Using Trace Helpers
-@c ============================================================================
-@node Using Trace Helpers
-@section Using Trace Helpers
-
-The @code{ns-3} trace helpers provide a rich environment for configuring and
-selecting different trace events and writing them to files. In previous
-sections, primarily ``Building Topologies,'' we have seen several varieties
-of the trace helper methods designed for use inside other (device) helpers.
-
-Perhaps you will recall seeing some of these variations:
-
-@verbatim
- pointToPoint.EnablePcapAll ("second");
- pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
- csma.EnablePcap ("third", csmaDevices.Get (0), true);
- pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
-@end verbatim
-
-What may not be obvious, though, is that there is a consistent model for all of
-the trace-related methods found in the system. We will now take a little time
-and take a look at the ``big picture''.
-
-There are currently two primary use cases of the tracing helpers in @code{ns-3}:
-Device helpers and protocol helpers. Device helpers look at the problem
-of specifying which traces should be enabled through a node, device pair. For
-example, you may want to specify that pcap tracing should be enabled on a
-particular device on a specific node. This follows from the @code{ns-3} device
-conceptual model, and also the conceptual models of the various device helpers.
-Following naturally from this, the files created follow a
-<prefix>-<node>-<device> naming convention.
-
-Protocol helpers look at the problem of specifying which traces should be
-enabled through a protocol and interface pair. This follows from the @code{ns-3}
-protocol stack conceptual model, and also the conceptual models of internet
-stack helpers. Naturally, the trace files should follow a
-<prefix>-<protocol>-<interface> naming convention.
-
-The trace helpers therefore fall naturally into a two-dimensional taxonomy.
-There are subtleties that prevent all four classes from behaving identically,
-but we do strive to make them all work as similarly as possible; and whenever
-possible there are analogs for all methods in all classes.
-
-@verbatim
- | pcap | ascii |
- -----------------+------+-------|
- Device Helper | | |
- -----------------+------+-------|
- Protocol Helper | | |
- -----------------+------+-------|
-@end verbatim
-
-We use an approach called a @code{mixin} to add tracing functionality to our
-helper classes. A @code{mixin} is a class that provides functionality to that
-is inherited by a subclass. Inheriting from a mixin is not considered a form
-of specialization but is really a way to collect functionality.
-
-Let's take a quick look at all four of these cases and their respective
-@code{mixins}.
-
-@subsection Pcap Tracing Device Helpers
-
-The goal of these helpers is to make it easy to add a consistent pcap trace
-facility to an @code{ns-3} device. We want all of the various flavors of
-pcap tracing to work the same across all devices, so the methods of these
-helpers are inherited by device helpers. Take a look at
-@code{src/helper/trace-helper.h} if you want to follow the discussion while
-looking at real code.
-
-The class @code{PcapHelperForDevice} is a @code{mixin} provides the high level
-functionality for using pcap tracing in an @code{ns-3} device. Every device
-must implement a single virtual method inherited from this class.
-
-@verbatim
- virtual void EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename) = 0;
-@end verbatim
-
-The signature of this method reflects the device-centric view of the situation
-at this level. All of the public methods inherited from class
-2@code{PcapUserHelperForDevice} reduce to calling this single device-dependent
-implementation method. For example, the lowest level pcap method,
-
-@verbatim
- void EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
-@end verbatim
-
-will call the device implementation of @code{EnablePcapInternal} directly. All
-other public pcap tracing methods build on this implementation to provide
-additional user-level functionality. What this means to the user is that all
-device helpers in the system will have all of the pcap trace methods available;
-and these methods will all work in the same way across devices if the device
-implements @code{EnablePcapInternal} correctly.
-
-@subsubsection Pcap Tracing Device Helper Methods
-
-@verbatim
- void EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
- void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
- void EnablePcap (std::string prefix, NetDeviceContainer d, bool promiscuous = false);
- void EnablePcap (std::string prefix, NodeContainer n, bool promiscuous = false);
- void EnablePcap (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
- void EnablePcapAll (std::string prefix, bool promiscuous = false);
-@end verbatim
-
-In each of the methods shown above, there is a default parameter called
-@code{promiscuous} that defaults to false. This parameter indicates that the
-trace should not be gathered in promiscuous mode. If you do want your traces
-to include all traffic seen by the device (and if the device supports a
-promiscuous mode) simply add a true parameter to any of the calls above. For example,
-
-@verbatim
- Ptr<NetDevice> nd;
- ...
- helper.EnablePcap ("prefix", nd, true);
-@end verbatim
-
-will enable promiscuous mode captures on the @code{NetDevice} specified by @code{nd}.
-
-The first two methods also include a default parameter called @code{explicitFilename}
-that will be discussed below.
-
-You are encouraged to peruse the Doxygen for class @code{PcapHelperForDevice}
-to find the details of these methods; but to summarize ...
-
-You can enable pcap tracing on a particular node/net-device pair by providing a
-@code{Ptr<NetDevice>} to an @code{EnablePcap} method. The @code{Ptr<Node>} is
-implicit since the net device must belong to exactly one @code{Node}.
-For example,
-
-@verbatim
- Ptr<NetDevice> nd;
- ...
- helper.EnablePcap ("prefix", nd);
-@end verbatim
-
-You can enable pcap tracing on a particular node/net-device pair by providing a
-@code{std::string} representing an object name service string to an
-@code{EnablePcap} method. The @code{Ptr<NetDevice>} is looked up from the name
-string. Again, the @code<Node> is implicit since the named net device must
-belong to exactly one @code{Node}. For example,
-
-@verbatim
- Names::Add ("server" ...);
- Names::Add ("server/eth0" ...);
- ...
- helper.EnablePcap ("prefix", "server/ath0");
-@end verbatim
-
-You can enable pcap tracing on a collection of node/net-device pairs by
-providing a @code{NetDeviceContainer}. For each @code{NetDevice} in the container
-the type is checked. For each device of the proper type (the same type as is
-managed by the device helper), tracing is enabled. Again, the @code<Node> is
-implicit since the found net device must belong to exactly one @code{Node}.
-For example,
-
-@verbatim
- NetDeviceContainer d = ...;
- ...
- helper.EnablePcap ("prefix", d);
-@end verbatim
-
-You can enable pcap tracing on a collection of node/net-device pairs by
-providing a @code{NodeContainer}. For each @code{Node} in the @code{NodeContainer}
-its attached @code{NetDevices} are iterated. For each @code{NetDevice} attached
-to each node in the container, the type of that device is checked. For each
-device of the proper type (the same type as is managed by the device helper),
-tracing is enabled.
-
-@verbatim
- NodeContainer n;
- ...
- helper.EnablePcap ("prefix", n);
-@end verbatim
-
-You can enable pcap tracing on the basis of node ID and device ID as well as
-with explicit @code{Ptr}. Each @code{Node} in the system has an integer node ID
-and each device connected to a node has an integer device ID.
-
-@verbatim
- helper.EnablePcap ("prefix", 21, 1);
-@end verbatim
-
-Finally, you can enable pcap tracing for all devices in the system, with the
-same type as that managed by the device helper.
-
-@verbatim
- helper.EnablePcapAll ("prefix");
-@end verbatim
-
-@subsubsection Pcap Tracing Device Helper Filename Selection
-
-Implicit in the method descriptions above is the construction of a complete
-filename by the implementation method. By convention, pcap traces in the
-@code{ns-3} system are of the form ``<prefix>-<node id>-<device id>.pcap''
-
-As previously mentioned, every node in the system will have a system-assigned
-node id; and every device will have an interface index (also called a device id)
-relative to its node. By default, then, a pcap trace file created as a result
-of enabling tracing on the first device of node 21 using the prefix ``prefix''
-would be ``prefix-21-1.pcap''.
-
-You can always use the @code{ns-3} object name service to make this more clear.
-For example, if you use the object name service to assign the name ``server''
-to node 21, the resulting pcap trace file name will automatically become,
-``prefix-server-1.pcap'' and if you also assign the name ``eth0'' to the
-device, your pcap file name will automatically pick this up and be called
-``prefix-server-eth0.pcap''.
-
-Finally, two of the methods shown above,
-
-@verbatim
- void EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
- void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
-@end verbatim
-
-have a default parameter called @code{explicitFilename}. When set to true,
-this parameter disables the automatic filename completion mechanism and allows
-you to create an explicit filename. This option is only available in the
-methods which enable pcap tracing on a single device.
-
-For example, in order to arrange for a device helper to create a single
-promiscuous pcap capture file of a specific name (``my-pcap-file.pcap'') on a
-given device, one could:
-
-@verbatim
- Ptr<NetDevice> nd;
- ...
- helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);
-@end verbatim
-
-The first @code{true} parameter enables promiscuous mode traces and the second
-tells the helper to interpret the @code{prefix} parameter as a complete filename.
-
-@subsection Ascii Tracing Device Helpers
-
-The behavior of the ascii trace helper @code{mixin} is substantially similar to
-the pcap version. Take a look at @code{src/helper/trace-helper.h} if you want to
-follow the discussion while looking at real code.
-
-The class @code{AsciiTraceHelperForDevice} adds the high level functionality for
-using ascii tracing to a device helper class. As in the pcap case, every device
-must implement a single virtual method inherited from the ascii trace @code{mixin}.
-
-@verbatim
- virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
- std::string prefix,
- Ptr<NetDevice> nd,
- bool explicitFilename) = 0;
-
-@end verbatim
-
-The signature of this method reflects the device-centric view of the situation
-at this level; and also the fact that the helper may be writing to a shared
-output stream. All of the public ascii-trace-related methods inherited from
-class @code{AsciiTraceHelperForDevice} reduce to calling this single device-
-dependent implementation method. For example, the lowest level ascii trace
-methods,
-
-@verbatim
- void EnableAscii (std::string prefix, Ptr<NetDevice> nd, bool explicitFilename = false);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
-@verbatim
-
-will call the device implementation of @code{EnableAsciiInternal} directly,
-providing either a valid prefix or stream. All other public ascii tracing
-methods will build on these low-level functions to provide additional user-level
-functionality. What this means to the user is that all device helpers in the
-system will have all of the ascii trace methods available; and these methods
-will all work in the same way across devices if the devices implement
-@code{EnablAsciiInternal} correctly.
-
-@subsubsection Ascii Tracing Device Helper Methods
-
-@verbatim
- void EnableAscii (std::string prefix, Ptr<NetDevice> nd, bool explicitFilename = false);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
-
- void EnableAscii (std::string prefix, std::string ndName, bool explicitFilename = false);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, std::string ndName);
-
- void EnableAscii (std::string prefix, NetDeviceContainer d);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, NetDeviceContainer d);
-
- void EnableAscii (std::string prefix, NodeContainer n);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, NodeContainer n);
-
- void EnableAsciiAll (std::string prefix);
- void EnableAsciiAll (Ptr<OutputStreamWrapper> stream);
-
- void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
- void EnableAscii (Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t deviceid);
-@end verbatim
-
-You are encouraged to peruse the Doxygen for class @code{TraceHelperForDevice}
-to find the details of these methods; but to summarize ...
-
-There are twice as many methods available for ascii tracing as there were for
-pcap tracing. This is because, in addition to the pcap-style model where traces
-from each unique node/device pair are written to a unique file, we support a model
-in which trace information for many node/device pairs is written to a common file.
-This means that the <prefix>-<node>-<device> file name generation mechanism is
-replaced by a mechanism to refer to a common file; and the number of API methods
-is doubled to allow all combinations.
-
-Just as in pcap tracing, you can enable ascii tracing on a particular
-node/net-device pair by providing a @code{Ptr<NetDevice>} to an @code{EnableAscii}
-method. The @code{Ptr<Node>} is implicit since the net device must belong to
-exactly one @code{Node}. For example,
-
-@verbatim
- Ptr<NetDevice> nd;
- ...
- helper.EnableAscii ("prefix", nd);
-@end verbatim
-
-The first four methods also include a default parameter called @code{explicitFilename}
-that operate similar to equivalent parameters in the pcap case.
-
-In this case, no trace contexts are written to the ascii trace file since they
-would be redundant. The system will pick the file name to be created using
-the same rules as described in the pcap section, except that the file will
-have the suffix ``.tr'' instead of ``.pcap''.
-
-If you want to enable ascii tracing on more than one net device and have all
-traces sent to a single file, you can do that as well by using an object to
-refer to a single file. We have already seen this in the ``cwnd'' example
-above:
-
-@verbatim
- Ptr<NetDevice> nd1;
- Ptr<NetDevice> nd2;
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAscii (stream, nd1);
- helper.EnableAscii (stream, nd2);
-@verbatim
-
-In this case, trace contexts are written to the ascii trace file since they
-are required to disambiguate traces from the two devices. Note that since the
-user is completely specifying the file name, the string should include the ``,tr''
-for consistency.
-
-You can enable ascii tracing on a particular node/net-device pair by providing a
-@code{std::string} representing an object name service string to an
-@code{EnablePcap} method. The @code{Ptr<NetDevice>} is looked up from the name
-string. Again, the @code<Node> is implicit since the named net device must
-belong to exactly one @code{Node}. For example,
-
-@verbatim
- Names::Add ("client" ...);
- Names::Add ("client/eth0" ...);
- Names::Add ("server" ...);
- Names::Add ("server/eth0" ...);
- ...
- helper.EnableAscii ("prefix", "client/eth0");
- helper.EnableAscii ("prefix", "server/eth0");
-@end verbatim
-
-This would result in two files named ``prefix-client-eth0.tr'' and
-``prefix-server-eth0.tr'' with traces for each device in the respective trace
-file. Since all of the EnableAscii functions are overloaded to take a stream wrapper,
-you can use that form as well:
-
-@verbatim
- Names::Add ("client" ...);
- Names::Add ("client/eth0" ...);
- Names::Add ("server" ...);
- Names::Add ("server/eth0" ...);
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAscii (stream, "client/eth0");
- helper.EnableAscii (stream, "server/eth0");
-@end verbatim
-
-This would result in a single trace file called ``trace-file-name.tr'' that
-contains all of the trace events for both devices. The events would be
-disambiguated by trace context strings.
-
-You can enable ascii tracing on a collection of node/net-device pairs by
-providing a @code{NetDeviceContainer}. For each @code{NetDevice} in the container
-the type is checked. For each device of the proper type (the same type as is
-managed by the device helper), tracing is enabled. Again, the @code<Node> is
-implicit since the found net device must belong to exactly one @code{Node}.
-For example,
-
-@verbatim
- NetDeviceContainer d = ...;
- ...
- helper.EnableAscii ("prefix", d);
-@end verbatim
-
-This would result in a number of ascii trace files being created, each of which
-follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
-traces into a single file is accomplished similarly to the examples above:
-
-@verbatim
- NetDeviceContainer d = ...;
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAscii (stream, d);
-@end verbatim
-
-You can enable ascii tracing on a collection of node/net-device pairs by
-providing a @code{NodeContainer}. For each @code{Node} in the @code{NodeContainer}
-its attached @code{NetDevices} are iterated. For each @code{NetDevice} attached
-to each node in the container, the type of that device is checked. For each
-device of the proper type (the same type as is managed by the device helper),
-tracing is enabled.
-
-@verbatim
- NodeContainer n;
- ...
- helper.EnableAscii ("prefix", n);
-@end verbatim
-
-This would result in a number of ascii trace files being created, each of which
-follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
-traces into a single file is accomplished similarly to the examples above:
-
-You can enable pcap tracing on the basis of node ID and device ID as well as
-with explicit @code{Ptr}. Each @code{Node} in the system has an integer node ID
-and each device connected to a node has an integer device ID.
-
-@verbatim
- helper.EnableAscii ("prefix", 21, 1);
-@end verbatim
-
-Of course, the traces can be combined into a single file as shown above.
-
-Finally, you can enable pcap tracing for all devices in the system, with the
-same type as that managed by the device helper.
-
-@verbatim
- helper.EnableAsciiAll ("prefix");
-@end verbatim
-
-This would result in a number of ascii trace files being created, one for
-every device in the system of the type managed by the helper. All of these
-files will follow the <prefix>-<node id>-<device id>.tr convention. Combining
-all of the traces into a single file is accomplished similarly to the examples
-above.
-
-@subsubsection Ascii Tracing Device Helper Filename Selection
-
-Implicit in the prefix-style method descriptions above is the construction of the
-complete filenames by the implementation method. By convention, ascii traces
-in the @code{ns-3} system are of the form ``<prefix>-<node id>-<device id>.tr''
-
-As previously mentioned, every node in the system will have a system-assigned
-node id; and every device will have an interface index (also called a device id)
-relative to its node. By default, then, an ascii trace file created as a result
-of enabling tracing on the first device of node 21, using the prefix ``prefix'',
-would be ``prefix-21-1.tr''.
-
-You can always use the @code{ns-3} object name service to make this more clear.
-For example, if you use the object name service to assign the name ``server''
-to node 21, the resulting ascii trace file name will automatically become,
-``prefix-server-1.tr'' and if you also assign the name ``eth0'' to the
-device, your ascii trace file name will automatically pick this up and be called
-``prefix-server-eth0.tr''.
-
-Several of the methods have a default parameter called @code{explicitFilename}.
-When set to true, this parameter disables the automatic filename completion
-mechanism and allows you to create an explicit filename. This option is only
-available in the methods which take a prefix and enable tracing on a single device.
-
-@subsection Pcap Tracing Protocol Helpers
-
-The goal of these @code{mixins} is to make it easy to add a consistent pcap trace
-facility to protocols. We want all of the various flavors of pcap tracing to
-work the same across all protocols, so the methods of these helpers are
-inherited by stack helpers. Take a look at @code{src/helper/trace-helper.h}
-if you want to follow the discussion while looking at real code.
-
-In this section we will be illustrating the methods as applied to the protocol
-@code{Ipv4}. To specify traces in similar protocols, just substitute the
-appropriate type. For example, use a @code{Ptr<Ipv6>} instead of a
-@code{Ptr<Ipv4>} and call @code{EnablePcapIpv6} instead of @code{EnablePcapIpv4}.
-
-The class @code{PcapHelperForIpv4} provides the high level functionality for
-using pcap tracing in the @code{Ipv4} protocol. Each protocol helper enabling these
-methods must implement a single virtual method inherited from this class. There
-will be a separate implementation for @code{Ipv6}, for example, but the only
-difference will be in the method names and signatures. Different method names
-are required to disambiguate class @code{Ipv4} from @code{Ipv6} which are both
-derived from class @code{Object}, and methods that share the same signature.
-
-@verbatim
- virtual void EnablePcapIpv4Internal (std::string prefix,
- Ptr<Ipv4> ipv4,
- uint32_t interface,
- bool explicitFilename) = 0;
-@end verbatim
-
-The signature of this method reflects the protocol and interface-centric view
-of the situation at this level. All of the public methods inherited from class
-@code{PcapHelperForIpv4} reduce to calling this single device-dependent
-implementation method. For example, the lowest level pcap method,
-
-@verbatim
- void EnablePcapIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename = false);
-@verbatim
-
-will call the device implementation of @code{EnablePcapIpv4Internal} directly.
-All other public pcap tracing methods build on this implementation to provide
-additional user-level functionality. What this means to the user is that all
-protocol helpers in the system will have all of the pcap trace methods
-available; and these methods will all work in the same way across
-protocols if the helper implements @code{EnablePcapIpv4Internal} correctly.
-
-@subsubsection Pcap Tracing Protocol Helper Methods
-
-These methods are designed to be in one-to-one correspondence with the @code{Node}-
-and @code{NetDevice}- centric versions of the device versions. Instead of
-@code{Node} and @code{NetDevice} pair constraints, we use protocol and interface
-constraints.
-
-Note that just like in the device version, there are six methods:
-
-@verbatim
- void EnablePcapIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename = false);
- void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explicitFilename = false);
- void EnablePcapIpv4 (std::string prefix, Ipv4InterfaceContainer c);
- void EnablePcapIpv4 (std::string prefix, NodeContainer n);
- void EnablePcapIpv4 (std::string prefix, uint32_t nodeid, uint32_t interface, bool explicitFilename);
- void EnablePcapIpv4All (std::string prefix);
-@end verbatim
-
-You are encouraged to peruse the Doxygen for class @code{PcapHelperForIpv4}
-to find the details of these methods; but to summarize ...
-
-You can enable pcap tracing on a particular protocol/interface pair by providing a
-@code{Ptr<Ipv4>} and @code{interface} to an @code{EnablePcap} method. For example,
-
-@verbatim
- Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
- ...
- helper.EnablePcapIpv4 ("prefix", ipv4, 0);
-@end verbatim
-
-You can enable pcap tracing on a particular node/net-device pair by providing a
-@code{std::string} representing an object name service string to an
-@code{EnablePcap} method. The @code{Ptr<Ipv4>} is looked up from the name
-string. For example,
-
-@verbatim
- Names::Add ("serverIPv4" ...);
- ...
- helper.EnablePcapIpv4 ("prefix", "serverIpv4", 1);
-@end verbatim
-
-You can enable pcap tracing on a collection of protocol/interface pairs by
-providing an @code{Ipv4InterfaceContainer}. For each @code{Ipv4} / interface
-pair in the container the protocol type is checked. For each protocol of the
-proper type (the same type as is managed by the device helper), tracing is
-enabled for the corresponding interface. For example,
-
-@verbatim
- NodeContainer nodes;
- ...
- NetDeviceContainer devices = deviceHelper.Install (nodes);
- ...
- Ipv4AddressHelper ipv4;
- ipv4.SetBase ("10.1.1.0", "255.255.255.0");
- Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
- ...
- helper.EnablePcapIpv4 ("prefix", interfaces);
-@end verbatim
-
-You can enable pcap tracing on a collection of protocol/interface pairs by
-providing a @code{NodeContainer}. For each @code{Node} in the @code{NodeContainer}
-the appropriate protocol is found. For each protocol, its interfaces are
-enumerated and tracing is enabled on the resulting pairs. For example,
-
-@verbatim
- NodeContainer n;
- ...
- helper.EnablePcapIpv4 ("prefix", n);
-@end verbatim
-
-You can enable pcap tracing on the basis of node ID and interface as well. In
-this case, the node-id is translated to a @code{Ptr<Node>} and the appropriate
-protocol is looked up in the node. The resulting protocol and interface are
-used to specify the resulting trace source.
-
-@verbatim
- helper.EnablePcapIpv4 ("prefix", 21, 1);
-@end verbatim
-
-Finally, you can enable pcap tracing for all interfaces in the system, with
-associated protocol being the same type as that managed by the device helper.
-
-@verbatim
- helper.EnablePcapIpv4All ("prefix");
-@end verbatim
-
-@subsubsection Pcap Tracing Protocol Helper Filename Selection
-
-Implicit in all of the method descriptions above is the construction of the
-complete filenames by the implementation method. By convention, pcap traces
-taken for devices in the @code{ns-3} system are of the form
-``<prefix>-<node id>-<device id>.pcap''. In the case of protocol traces,
-there is a one-to-one correspondence between protocols and @code{Nodes}.
-This is because protocol @code{Objects} are aggregated to @code{Node Objects}.
-Since there is no global protocol id in the system, we use the corresponding
-node id in file naming. Therefore there is a possibility for file name
-collisions in automatically chosen trace file names. For this reason, the
-file name convention is changed for protocol traces.
-
-As previously mentioned, every node in the system will have a system-assigned
-node id. Since there is a one-to-one correspondence between protocol instances
-and node instances we use the node id. Each interface has an interface id
-relative to its protocol. We use the convention
-"<prefix>-n<node id>-i<interface id>.pcap" for trace file naming in protocol
-helpers.
-
-Therefore, by default, a pcap trace file created as a result of enabling tracing
-on interface 1 of the Ipv4 protocol of node 21 using the prefix ``prefix''
-would be ``prefix-n21-i1.pcap''.
-
-You can always use the @code{ns-3} object name service to make this more clear.
-For example, if you use the object name service to assign the name ``serverIpv4''
-to the Ptr<Ipv4> on node 21, the resulting pcap trace file name will
-automatically become, ``prefix-nserverIpv4-i1.pcap''.
-
-Several of the methods have a default parameter called @code{explicitFilename}.
-When set to true, this parameter disables the automatic filename completion
-mechanism and allows you to create an explicit filename. This option is only
-available in the methods which take a prefix and enable tracing on a single device.
-
-@subsection Ascii Tracing Protocol Helpers
-
-The behavior of the ascii trace helpers is substantially similar to the pcap
-case. Take a look at @code{src/helper/trace-helper.h} if you want to
-follow the discussion while looking at real code.
-
-In this section we will be illustrating the methods as applied to the protocol
-@code{Ipv4}. To specify traces in similar protocols, just substitute the
-appropriate type. For example, use a @code{Ptr<Ipv6>} instead of a
-@code{Ptr<Ipv4>} and call @code{EnableAsciiIpv6} instead of @code{EnableAsciiIpv4}.
-
-The class @code{AsciiTraceHelperForIpv4} adds the high level functionality
-for using ascii tracing to a protocol helper. Each protocol that enables these
-methods must implement a single virtual method inherited from this class.
-
-@verbatim
- virtual void EnableAsciiIpv4Internal (Ptr<OutputStreamWrapper> stream,
- std::string prefix,
- Ptr<Ipv4> ipv4,
- uint32_t interface,
- bool explicitFilename) = 0;
-@end verbatim
-
-The signature of this method reflects the protocol- and interface-centric view
-of the situation at this level; and also the fact that the helper may be writing
-to a shared output stream. All of the public methods inherited from class
-@code{PcapAndAsciiTraceHelperForIpv4} reduce to calling this single device-
-dependent implementation method. For example, the lowest level ascii trace
-methods,
-
-@verbatim
- void EnableAsciiIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename = false);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
-@verbatim
-
-will call the device implementation of @code{EnableAsciiIpv4Internal} directly,
-providing either the prefix or the stream. All other public ascii tracing
-methods will build on these low-level functions to provide additional user-level
-functionality. What this means to the user is that all device helpers in the
-system will have all of the ascii trace methods available; and these methods
-will all work in the same way across protocols if the protocols implement
-@code{EnablAsciiIpv4Internal} correctly.
-
-@subsubsection Ascii Tracing Protocol Helper Methods
-
-@verbatim
- void EnableAsciiIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface, bool explicitFilename = false);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
-
- void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explicitFilename = false);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, std::string ipv4Name, uint32_t interface);
-
- void EnableAsciiIpv4 (std::string prefix, Ipv4InterfaceContainer c);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ipv4InterfaceContainer c);
-
- void EnableAsciiIpv4 (std::string prefix, NodeContainer n);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, NodeContainer n);
-
- void EnableAsciiIpv4All (std::string prefix);
- void EnableAsciiIpv4All (Ptr<OutputStreamWrapper> stream);
-
- void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
- void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t interface);
-@end verbatim
-
-You are encouraged to peruse the Doxygen for class @code{PcapAndAsciiHelperForIpv4}
-to find the details of these methods; but to summarize ...
-
-There are twice as many methods available for ascii tracing as there were for
-pcap tracing. This is because, in addition to the pcap-style model where traces
-from each unique protocol/interface pair are written to a unique file, we
-support a model in which trace information for many protocol/interface pairs is
-written to a common file. This means that the <prefix>-n<node id>-<interface>
-file name generation mechanism is replaced by a mechanism to refer to a common
-file; and the number of API methods is doubled to allow all combinations.
-
-Just as in pcap tracing, you can enable ascii tracing on a particular
-protocol/interface pair by providing a @code{Ptr<Ipv4>} and an @code{interface}
-to an @code{EnableAscii} method.
-For example,
-
-@verbatim
- Ptr<Ipv4> ipv4;
- ...
- helper.EnableAsciiIpv4 ("prefix", ipv4, 1);
-@end verbatim
-
-In this case, no trace contexts are written to the ascii trace file since they
-would be redundant. The system will pick the file name to be created using
-the same rules as described in the pcap section, except that the file will
-have the suffix ``.tr'' instead of ``.pcap''.
-
-If you want to enable ascii tracing on more than one interface and have all
-traces sent to a single file, you can do that as well by using an object to
-refer to a single file. We have already something similar to this in the
-``cwnd'' example above:
-
-@verbatim
- Ptr<Ipv4> protocol1 = node1->GetObject<Ipv4> ();
- Ptr<Ipv4> protocol2 = node2->GetObject<Ipv4> ();
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAsciiIpv4 (stream, protocol1, 1);
- helper.EnableAsciiIpv4 (stream, protocol2, 1);
-@verbatim
-
-In this case, trace contexts are written to the ascii trace file since they
-are required to disambiguate traces from the two interfaces. Note that since
-the user is completely specifying the file name, the string should include the
-``,tr'' for consistency.
-
-You can enable ascii tracing on a particular protocol by providing a
-@code{std::string} representing an object name service string to an
-@code{EnablePcap} method. The @code{Ptr<Ipv4>} is looked up from the name
-string. The @code<Node> in the resulting filenames is implicit since there
-is a one-to-one correspondence between protocol instances and nodes,
-For example,
-
-@verbatim
- Names::Add ("node1Ipv4" ...);
- Names::Add ("node2Ipv4" ...);
- ...
- helper.EnableAsciiIpv4 ("prefix", "node1Ipv4", 1);
- helper.EnableAsciiIpv4 ("prefix", "node2Ipv4", 1);
-@end verbatim
-
-This would result in two files named ``prefix-nnode1Ipv4-i1.tr'' and
-``prefix-nnode2Ipv4-i1.tr'' with traces for each interface in the respective
-trace file. Since all of the EnableAscii functions are overloaded to take a
-stream wrapper, you can use that form as well:
-
-@verbatim
- Names::Add ("node1Ipv4" ...);
- Names::Add ("node2Ipv4" ...);
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAsciiIpv4 (stream, "node1Ipv4", 1);
- helper.EnableAsciiIpv4 (stream, "node2Ipv4", 1);
-@end verbatim
-
-This would result in a single trace file called ``trace-file-name.tr'' that
-contains all of the trace events for both interfaces. The events would be
-disambiguated by trace context strings.
-
-You can enable ascii tracing on a collection of protocol/interface pairs by
-providing an @code{Ipv4InterfaceContainer}. For each protocol of the proper
-type (the same type as is managed by the device helper), tracing is enabled
-for the corresponding interface. Again, the @code<Node> is implicit since
-there is a one-to-one correspondence between each protocol and its node.
-For example,
-
-@verbatim
- NodeContainer nodes;
- ...
- NetDeviceContainer devices = deviceHelper.Install (nodes);
- ...
- Ipv4AddressHelper ipv4;
- ipv4.SetBase ("10.1.1.0", "255.255.255.0");
- Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
- ...
- ...
- helper.EnableAsciiIpv4 ("prefix", interfaces);
-@end verbatim
-
-This would result in a number of ascii trace files being created, each of which
-follows the <prefix>-n<node id>-i<interface>.tr convention. Combining all of the
-traces into a single file is accomplished similarly to the examples above:
-
-@verbatim
- NodeContainer nodes;
- ...
- NetDeviceContainer devices = deviceHelper.Install (nodes);
- ...
- Ipv4AddressHelper ipv4;
- ipv4.SetBase ("10.1.1.0", "255.255.255.0");
- Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
- ...
- Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
- ...
- helper.EnableAsciiIpv4 (stream, interfaces);
-@end verbatim
-
-You can enable ascii tracing on a collection of protocol/interface pairs by
-providing a @code{NodeContainer}. For each @code{Node} in the @code{NodeContainer}
-the appropriate protocol is found. For each protocol, its interfaces are
-enumerated and tracing is enabled on the resulting pairs. For example,
-
-@verbatim
- NodeContainer n;
- ...
- helper.EnableAsciiIpv4 ("prefix", n);
-@end verbatim
-
-This would result in a number of ascii trace files being created, each of which
-follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
-traces into a single file is accomplished similarly to the examples above:
-
-You can enable pcap tracing on the basis of node ID and device ID as well. In
-this case, the node-id is translated to a @code{Ptr<Node>} and the appropriate
-protocol is looked up in the node. The resulting protocol and interface are
-used to specify the resulting trace source.
-
-@verbatim
- helper.EnableAsciiIpv4 ("prefix", 21, 1);
-@end verbatim
-
-Of course, the traces can be combined into a single file as shown above.
-
-Finally, you can enable ascii tracing for all interfaces in the system, with
-associated protocol being the same type as that managed by the device helper.
-
-@verbatim
- helper.EnableAsciiIpv4All ("prefix");
-@end verbatim
-
-This would result in a number of ascii trace files being created, one for
-every interface in the system related to a protocol of the type managed by the
-helper. All of these files will follow the <prefix>-n<node id>-i<interface.tr
-convention. Combining all of the traces into a single file is accomplished
-similarly to the examples above.
-
-@subsubsection Ascii Tracing Protocol Helper Filename Selection
-
-Implicit in the prefix-style method descriptions above is the construction of the
-complete filenames by the implementation method. By convention, ascii traces
-in the @code{ns-3} system are of the form ``<prefix>-<node id>-<device id>.tr''
-
-As previously mentioned, every node in the system will have a system-assigned
-node id. Since there is a one-to-one correspondence between protocols and nodes
-we use to node-id to identify the protocol identity. Every interface on a
-given protocol will have an interface index (also called simply an interface)
-relative to its protocol. By default, then, an ascii trace file created as a result
-of enabling tracing on the first device of node 21, using the prefix ``prefix'',
-would be ``prefix-n21-i1.tr''. Use the prefix to disambiguate multiple protocols
-per node.
-
-You can always use the @code{ns-3} object name service to make this more clear.
-For example, if you use the object name service to assign the name ``serverIpv4''
-to the protocol on node 21, and also specify interface one, the resulting ascii
-trace file name will automatically become, ``prefix-nserverIpv4-1.tr''.
-
-Several of the methods have a default parameter called @code{explicitFilename}.
-When set to true, this parameter disables the automatic filename completion
-mechanism and allows you to create an explicit filename. This option is only
-available in the methods which take a prefix and enable tracing on a single device.
-
-@c ============================================================================
-@c Summary
-@c ============================================================================
-@node Summary
-@section Summary
-
-@code{ns-3} includes an extremely rich environment allowing users at several
-levels to customize the kinds of information that can be extracted from
-simulations.
-
-There are high-level helper functions that allow users to simply control the
-collection of pre-defined outputs to a fine granularity. There are mid-level
-helper functions to allow more sophisticated users to customize how information
-is extracted and saved; and there are low-level core functions to allow expert
-users to alter the system to present new and previously unexported information
-in a way that will be immediately accessible to users at higher levels.
-
-This is a very comprehensive system, and we realize that it is a lot to
-digest, especially for new users or those not intimately familiar with C++
-and its idioms. We do consider the tracing system a very important part of
-@code{ns-3} and so recommend becoming as familiar as possible with it. It is
-probably the case that understanding the rest of the @code{ns-3} system will
-be quite simple once you have mastered the tracing system